mirror of
https://github.com/misternebula/quantum-space-buddies.git
synced 2025-01-26 09:35:26 +00:00
Merge branch 'dev' into picture-frame-doors
This commit is contained in:
commit
c8ce4bdfb4
@ -1,5 +1,4 @@
|
||||
using Mirror;
|
||||
using QSB.ItemSync.WorldObjects.Items;
|
||||
using QSB.ItemSync.WorldObjects.Items;
|
||||
using QSB.Messaging;
|
||||
using QSB.Player;
|
||||
using QSB.SectorSync.WorldObjects;
|
||||
@ -8,39 +7,21 @@ using UnityEngine;
|
||||
|
||||
namespace QSB.ItemSync.Messages;
|
||||
|
||||
internal class DropItemMessage : QSBWorldObjectMessage<IQSBItem>
|
||||
internal class DropItemMessage : QSBWorldObjectMessage<IQSBItem,
|
||||
(Vector3 LocalPos, Vector3 LocalNorm, int SectorId)>
|
||||
{
|
||||
private Vector3 Position;
|
||||
private Vector3 Normal;
|
||||
private int SectorId;
|
||||
|
||||
public DropItemMessage(Vector3 position, Vector3 normal, Sector sector)
|
||||
{
|
||||
Position = position;
|
||||
Normal = normal;
|
||||
SectorId = sector.GetWorldObject<QSBSector>().ObjectId;
|
||||
}
|
||||
|
||||
public override void Serialize(NetworkWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
writer.Write(Position);
|
||||
writer.Write(Normal);
|
||||
writer.Write(SectorId);
|
||||
}
|
||||
|
||||
public override void Deserialize(NetworkReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
Position = reader.ReadVector3();
|
||||
Normal = reader.ReadVector3();
|
||||
SectorId = reader.Read<int>();
|
||||
}
|
||||
public DropItemMessage(Vector3 position, Vector3 normal, Sector sector) : base((
|
||||
sector.transform.InverseTransformPoint(position),
|
||||
sector.transform.InverseTransformDirection(normal),
|
||||
sector.GetWorldObject<QSBSector>().ObjectId
|
||||
)) { }
|
||||
|
||||
public override void OnReceiveRemote()
|
||||
{
|
||||
var sector = SectorId.GetWorldObject<QSBSector>().AttachedObject;
|
||||
WorldObject.DropItem(sector.transform.TransformPoint(Position), Normal, sector);
|
||||
var sector = Data.SectorId.GetWorldObject<QSBSector>().AttachedObject;
|
||||
var position = sector.transform.TransformPoint(Data.LocalPos);
|
||||
var normal = sector.transform.TransformDirection(Data.LocalNorm);
|
||||
WorldObject.DropItem(position, normal, sector);
|
||||
|
||||
var player = QSBPlayerManager.GetPlayer(From);
|
||||
player.HeldItem = WorldObject;
|
||||
|
@ -90,7 +90,7 @@ internal class ItemPatches : QSBPatch
|
||||
var parent = (customDropTarget == null)
|
||||
? targetRigidbody.transform
|
||||
: customDropTarget.GetItemDropTargetTransform(hit.collider.gameObject);
|
||||
var IQSBItem = __instance._heldItem.GetWorldObject<IQSBItem>();
|
||||
var qsbItem = __instance._heldItem.GetWorldObject<IQSBItem>();
|
||||
__instance._heldItem.DropItem(hit.point, hit.normal, parent, sector, customDropTarget);
|
||||
__instance._heldItem = null;
|
||||
QSBPlayerManager.LocalPlayer.HeldItem = null;
|
||||
@ -98,12 +98,13 @@ internal class ItemPatches : QSBPatch
|
||||
var parentSector = parent.GetComponentInChildren<Sector>();
|
||||
if (parentSector != null)
|
||||
{
|
||||
var localPos = parentSector.transform.InverseTransformPoint(hit.point);
|
||||
IQSBItem.SendMessage(new DropItemMessage(localPos, hit.normal, parentSector));
|
||||
return false;
|
||||
qsbItem.SendMessage(new DropItemMessage(hit.point, hit.normal, parentSector));
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugLog.ToConsole($"Error - No sector found for rigidbody {targetRigidbody.name}!.", MessageType.Error);
|
||||
}
|
||||
|
||||
DebugLog.ToConsole($"Error - No sector found for rigidbody {targetRigidbody.name}!.", MessageType.Error);
|
||||
return false;
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
using QSB.Messaging;
|
||||
using QSB.MeteorSync.WorldObjects;
|
||||
|
||||
namespace QSB.MeteorSync.Messages;
|
||||
|
||||
public class FragmentDamageMessage : QSBWorldObjectMessage<QSBFragment, float>
|
||||
{
|
||||
public FragmentDamageMessage(float damage) : base(damage) { }
|
||||
|
||||
public override void OnReceiveRemote() => WorldObject.AddDamage(Data);
|
||||
}
|
@ -1,147 +1,27 @@
|
||||
using Mirror;
|
||||
using OWML.Common;
|
||||
using OWML.Common;
|
||||
using QSB.Messaging;
|
||||
using QSB.MeteorSync.WorldObjects;
|
||||
using QSB.Utility;
|
||||
using UnityEngine;
|
||||
|
||||
namespace QSB.MeteorSync.Messages;
|
||||
|
||||
/// called when we request a resync on client join
|
||||
/// pain
|
||||
public class FragmentInitialStateMessage : QSBWorldObjectMessage<QSBFragment>
|
||||
/// <summary>
|
||||
/// original integrity, leash length
|
||||
/// </summary>
|
||||
public class FragmentInitialStateMessage : QSBWorldObjectMessage<QSBFragment, (float OrigIntegrity, float LeashLength)>
|
||||
{
|
||||
private float Integrity;
|
||||
private float OrigIntegrity;
|
||||
private float LeashLength;
|
||||
private bool IsDetached;
|
||||
|
||||
private bool IsThruWhiteHole;
|
||||
private Vector3 RelPos;
|
||||
private Quaternion RelRot;
|
||||
private Vector3 RelVel;
|
||||
private Vector3 RelAngVel;
|
||||
|
||||
public FragmentInitialStateMessage(QSBFragment qsbFragment)
|
||||
{
|
||||
Integrity = qsbFragment.AttachedObject._integrity;
|
||||
OrigIntegrity = qsbFragment.AttachedObject._origIntegrity;
|
||||
LeashLength = qsbFragment.LeashLength;
|
||||
IsDetached = qsbFragment.IsDetached;
|
||||
|
||||
if (IsDetached)
|
||||
{
|
||||
IsThruWhiteHole = qsbFragment.IsThruWhiteHole;
|
||||
|
||||
var body = qsbFragment.Body;
|
||||
var refBody = qsbFragment.RefBody;
|
||||
var pos = body.GetPosition();
|
||||
RelPos = refBody.transform.ToRelPos(pos);
|
||||
RelRot = refBody.transform.ToRelRot(body.GetRotation());
|
||||
RelVel = refBody.ToRelVel(body.GetVelocity(), pos);
|
||||
RelAngVel = refBody.ToRelAngVel(body.GetAngularVelocity());
|
||||
}
|
||||
}
|
||||
|
||||
public override void Serialize(NetworkWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
writer.Write(Integrity);
|
||||
writer.Write(OrigIntegrity);
|
||||
writer.Write(LeashLength);
|
||||
writer.Write(IsDetached);
|
||||
if (IsDetached)
|
||||
{
|
||||
writer.Write(IsThruWhiteHole);
|
||||
writer.Write(RelPos);
|
||||
writer.Write(RelRot);
|
||||
writer.Write(RelVel);
|
||||
writer.Write(RelAngVel);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Deserialize(NetworkReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
Integrity = reader.Read<float>();
|
||||
OrigIntegrity = reader.Read<float>();
|
||||
LeashLength = reader.Read<float>();
|
||||
IsDetached = reader.Read<bool>();
|
||||
if (IsDetached)
|
||||
{
|
||||
IsThruWhiteHole = reader.Read<bool>();
|
||||
RelPos = reader.ReadVector3();
|
||||
RelRot = reader.ReadQuaternion();
|
||||
RelVel = reader.ReadVector3();
|
||||
RelAngVel = reader.ReadVector3();
|
||||
}
|
||||
}
|
||||
public FragmentInitialStateMessage(float origIntegrity, float leashLength) : base((origIntegrity, leashLength)) { }
|
||||
|
||||
public override void OnReceiveRemote()
|
||||
{
|
||||
WorldObject.AttachedObject._origIntegrity = OrigIntegrity;
|
||||
WorldObject.LeashLength = LeashLength;
|
||||
if (!OWMath.ApproxEquals(WorldObject.AttachedObject._integrity, Integrity))
|
||||
WorldObject.AttachedObject._origIntegrity = Data.OrigIntegrity;
|
||||
if (WorldObject.LeashLength == null)
|
||||
{
|
||||
WorldObject.AttachedObject._integrity = Integrity;
|
||||
WorldObject.AttachedObject.CallOnTakeDamage();
|
||||
WorldObject.LeashLength = Data.LeashLength;
|
||||
}
|
||||
|
||||
if (IsDetached && !WorldObject.IsDetached)
|
||||
else
|
||||
{
|
||||
// the detach is delayed, so wait until that happens
|
||||
Delay.RunWhen(() => WorldObject.IsDetached, () =>
|
||||
{
|
||||
var body = WorldObject.Body;
|
||||
|
||||
if (IsThruWhiteHole && !WorldObject.IsThruWhiteHole)
|
||||
{
|
||||
var whiteHoleVolume = MeteorManager.WhiteHoleVolume;
|
||||
var attachedFluidDetector = body.GetAttachedFluidDetector();
|
||||
var attachedForceDetector = body.GetAttachedForceDetector();
|
||||
if (attachedFluidDetector is ConstantFluidDetector constantFluidDetector)
|
||||
{
|
||||
constantFluidDetector.SetDetectableFluid(whiteHoleVolume._fluidVolume);
|
||||
}
|
||||
|
||||
if (attachedForceDetector is ConstantForceDetector constantForceDetector)
|
||||
{
|
||||
constantForceDetector.ClearAllFields();
|
||||
}
|
||||
|
||||
WorldObject.DetachableFragment.ChangeFragmentSector(whiteHoleVolume._whiteHoleSector,
|
||||
whiteHoleVolume._whiteHoleProxyShadowSuperGroup);
|
||||
|
||||
WorldObject.DetachableFragment.EndWarpScaling();
|
||||
body.gameObject.AddComponent<DebrisLeash>().Init(whiteHoleVolume._whiteHoleBody, WorldObject.LeashLength);
|
||||
whiteHoleVolume._ejectedBodyList.Add(body);
|
||||
}
|
||||
else if (!IsThruWhiteHole && WorldObject.IsThruWhiteHole)
|
||||
{
|
||||
// should only happen if client is way too far ahead and they try to connect. we fail here.
|
||||
DebugLog.ToConsole($"{WorldObject} is thru white hole, but msg is not. fuck", MessageType.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (WorldObject.IsThruWhiteHole)
|
||||
{
|
||||
var debrisLeash = body.GetComponent<DebrisLeash>();
|
||||
debrisLeash._deccelerating = false;
|
||||
debrisLeash.enabled = true;
|
||||
}
|
||||
|
||||
var refBody = WorldObject.RefBody;
|
||||
var pos = refBody.transform.FromRelPos(RelPos);
|
||||
body.SetPosition(pos);
|
||||
body.SetRotation(refBody.transform.FromRelRot(RelRot));
|
||||
body.SetVelocity(refBody.FromRelVel(RelVel, pos));
|
||||
body.SetAngularVelocity(refBody.FromRelAngVel(RelAngVel));
|
||||
});
|
||||
}
|
||||
else if (!IsDetached && WorldObject.IsDetached)
|
||||
{
|
||||
// should only happen if client is way too far ahead and they try to connect. we fail here.
|
||||
DebugLog.ToConsole($"{WorldObject} is detached, but msg is not. fuck", MessageType.Error);
|
||||
DebugLog.ToConsole($"leash length for {WorldObject} already set", MessageType.Warning);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
10
QSB/MeteorSync/Messages/FragmentIntegrityMessage.cs
Normal file
10
QSB/MeteorSync/Messages/FragmentIntegrityMessage.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using QSB.Messaging;
|
||||
using QSB.MeteorSync.WorldObjects;
|
||||
|
||||
namespace QSB.MeteorSync.Messages;
|
||||
|
||||
public class FragmentIntegrityMessage : QSBWorldObjectMessage<QSBFragment, float>
|
||||
{
|
||||
public FragmentIntegrityMessage(float integrity) : base(integrity) { }
|
||||
public override void OnReceiveRemote() => WorldObject.SetIntegrity(Data);
|
||||
}
|
@ -1,33 +1,18 @@
|
||||
using Mirror;
|
||||
using QSB.Messaging;
|
||||
using QSB.Messaging;
|
||||
using QSB.MeteorSync.WorldObjects;
|
||||
using QSB.WorldSync;
|
||||
|
||||
namespace QSB.MeteorSync.Messages;
|
||||
|
||||
public class MeteorLaunchMessage : QSBWorldObjectMessage<QSBMeteorLauncher>
|
||||
public class MeteorLaunchMessage : QSBWorldObjectMessage<QSBMeteorLauncher, (int MeteorId, float LaunchSpeed)>
|
||||
{
|
||||
private int MeteorId;
|
||||
private float LaunchSpeed;
|
||||
public MeteorLaunchMessage(MeteorController meteor, float launchSpeed) : base((
|
||||
meteor.GetWorldObject<QSBMeteor>().ObjectId,
|
||||
launchSpeed
|
||||
)) { }
|
||||
|
||||
public MeteorLaunchMessage(QSBMeteorLauncher qsbMeteorLauncher)
|
||||
{
|
||||
MeteorId = qsbMeteorLauncher.MeteorId;
|
||||
LaunchSpeed = qsbMeteorLauncher.LaunchSpeed;
|
||||
}
|
||||
|
||||
public override void Serialize(NetworkWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
writer.Write(MeteorId);
|
||||
writer.Write(LaunchSpeed);
|
||||
}
|
||||
|
||||
public override void Deserialize(NetworkReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
MeteorId = reader.Read<int>();
|
||||
LaunchSpeed = reader.Read<float>();
|
||||
}
|
||||
|
||||
public override void OnReceiveRemote() => WorldObject.LaunchMeteor(MeteorId, LaunchSpeed);
|
||||
}
|
||||
public override void OnReceiveRemote() => WorldObject.LaunchMeteor(
|
||||
Data.MeteorId.GetWorldObject<QSBMeteor>().AttachedObject,
|
||||
Data.LaunchSpeed
|
||||
);
|
||||
}
|
||||
|
@ -3,6 +3,9 @@ using QSB.MeteorSync.WorldObjects;
|
||||
|
||||
namespace QSB.MeteorSync.Messages;
|
||||
|
||||
/// <summary>
|
||||
/// for syncing impact with a remote player/probe
|
||||
/// </summary>
|
||||
public class MeteorSpecialImpactMessage : QSBWorldObjectMessage<QSBMeteor>
|
||||
{
|
||||
public override void OnReceiveRemote() => WorldObject.SpecialImpact();
|
||||
|
@ -1,5 +1,6 @@
|
||||
using Cysharp.Threading.Tasks;
|
||||
using QSB.MeteorSync.WorldObjects;
|
||||
using QSB.Utility;
|
||||
using QSB.WorldSync;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
@ -18,8 +19,14 @@ public class MeteorManager : WorldObjectManager
|
||||
await UniTask.WaitUntil(() => LateInitializerManager.isDoneInitializing, cancellationToken: ct);
|
||||
|
||||
WhiteHoleVolume = QSBWorldSync.GetUnityObjects<WhiteHoleVolume>().First();
|
||||
QSBWorldSync.Init<QSBMeteorLauncher, MeteorLauncher>();
|
||||
QSBWorldSync.Init<QSBMeteor, MeteorController>();
|
||||
QSBWorldSync.Init<QSBFragment, FragmentIntegrity>();
|
||||
|
||||
var meteorLaunchers = QSBWorldSync.GetUnityObjects<MeteorLauncher>().SortDeterministic().ToList();
|
||||
QSBWorldSync.Init<QSBMeteorLauncher, MeteorLauncher>(meteorLaunchers);
|
||||
|
||||
// order by pool instead of using SortDeterministic
|
||||
var meteors = meteorLaunchers.SelectMany(x =>
|
||||
x._meteorPool.EmptyIfNull().Concat(x._dynamicMeteorPool.EmptyIfNull()));
|
||||
QSBWorldSync.Init<QSBMeteor, MeteorController>(meteors);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,13 +19,8 @@ public class MeteorServerPatches : QSBPatch
|
||||
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(typeof(MeteorLauncher), nameof(MeteorLauncher.FixedUpdate))]
|
||||
public static bool FixedUpdate(MeteorLauncher __instance)
|
||||
public static bool MeteorLauncher_FixedUpdate(MeteorLauncher __instance)
|
||||
{
|
||||
if (!QSBWorldSync.AllObjectsReady)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (__instance._launchedMeteors != null)
|
||||
{
|
||||
for (var i = __instance._launchedMeteors.Count - 1; i >= 0; i--)
|
||||
@ -63,13 +58,13 @@ public class MeteorServerPatches : QSBPatch
|
||||
if (!__instance._areParticlesPlaying)
|
||||
{
|
||||
__instance._areParticlesPlaying = true;
|
||||
foreach (var particleSystem in __instance._launchParticles)
|
||||
foreach (var launchParticle in __instance._launchParticles)
|
||||
{
|
||||
particleSystem.Play();
|
||||
launchParticle.Play();
|
||||
}
|
||||
|
||||
var qsbMeteorLauncher = __instance.GetWorldObject<QSBMeteorLauncher>();
|
||||
qsbMeteorLauncher.SendMessage(new MeteorPreLaunchMessage());
|
||||
__instance.GetWorldObject<QSBMeteorLauncher>()
|
||||
.SendMessage(new MeteorPreLaunchMessage());
|
||||
}
|
||||
|
||||
if (Time.time > __instance._lastLaunchTime + __instance._launchDelay + 2.3f)
|
||||
@ -78,9 +73,9 @@ public class MeteorServerPatches : QSBPatch
|
||||
__instance._lastLaunchTime = Time.time;
|
||||
__instance._launchDelay = Random.Range(__instance._minInterval, __instance._maxInterval);
|
||||
__instance._areParticlesPlaying = false;
|
||||
foreach (var particleSystem in __instance._launchParticles)
|
||||
foreach (var launchParticle in __instance._launchParticles)
|
||||
{
|
||||
particleSystem.Stop();
|
||||
launchParticle.Stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -90,7 +85,7 @@ public class MeteorServerPatches : QSBPatch
|
||||
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(typeof(MeteorLauncher), nameof(MeteorLauncher.LaunchMeteor))]
|
||||
public static bool LaunchMeteor(MeteorLauncher __instance)
|
||||
public static bool MeteorLauncher_LaunchMeteor(MeteorLauncher __instance)
|
||||
{
|
||||
var flag = __instance._dynamicMeteorPool != null && (__instance._meteorPool == null || Random.value < __instance._dynamicProbability);
|
||||
MeteorController meteorController = null;
|
||||
@ -125,13 +120,9 @@ public class MeteorServerPatches : QSBPatch
|
||||
|
||||
if (meteorController != null)
|
||||
{
|
||||
var qsbMeteorLauncher = __instance.GetWorldObject<QSBMeteorLauncher>();
|
||||
var qsbMeteor = meteorController.GetWorldObject<QSBMeteor>();
|
||||
var launchSpeed = Random.Range(__instance._minLaunchSpeed, __instance._maxLaunchSpeed);
|
||||
|
||||
qsbMeteorLauncher.MeteorId = qsbMeteor.ObjectId;
|
||||
qsbMeteorLauncher.LaunchSpeed = Random.Range(__instance._minLaunchSpeed, __instance._maxLaunchSpeed);
|
||||
|
||||
var linearVelocity = __instance._parentBody.GetPointVelocity(__instance.transform.position) + (__instance.transform.TransformDirection(__instance._launchDirection) * qsbMeteorLauncher.LaunchSpeed);
|
||||
var linearVelocity = __instance._parentBody.GetPointVelocity(__instance.transform.position) + __instance.transform.TransformDirection(__instance._launchDirection) * launchSpeed;
|
||||
var angularVelocity = __instance.transform.forward * 2f;
|
||||
meteorController.Launch(null, __instance.transform.position, __instance.transform.rotation, linearVelocity, angularVelocity);
|
||||
if (__instance._audioSector.ContainsOccupant(DynamicOccupant.Player))
|
||||
@ -140,32 +131,18 @@ public class MeteorServerPatches : QSBPatch
|
||||
__instance._launchSource.PlayOneShot(AudioType.BH_MeteorLaunch);
|
||||
}
|
||||
|
||||
qsbMeteorLauncher.SendMessage(new MeteorLaunchMessage(qsbMeteorLauncher));
|
||||
__instance.GetWorldObject<QSBMeteorLauncher>()
|
||||
.SendMessage(new MeteorLaunchMessage(meteorController, launchSpeed));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(MeteorController), nameof(MeteorController.Impact))]
|
||||
public static void Impact(MeteorController __instance,
|
||||
GameObject hitObject, Vector3 impactPoint, Vector3 impactVel)
|
||||
{
|
||||
var qsbMeteor = __instance.GetWorldObject<QSBMeteor>();
|
||||
if (QSBMeteor.IsSpecialImpact(hitObject))
|
||||
{
|
||||
qsbMeteor.SendMessage(new MeteorSpecialImpactMessage());
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(FragmentIntegrity), nameof(FragmentIntegrity.AddDamage))]
|
||||
public static void AddDamage(FragmentIntegrity __instance,
|
||||
float damage)
|
||||
{
|
||||
var qsbFragment = __instance.GetWorldObject<QSBFragment>();
|
||||
qsbFragment.SendMessage(new FragmentDamageMessage(damage));
|
||||
}
|
||||
public static void FragmentIntegrity_AddDamage(FragmentIntegrity __instance) =>
|
||||
__instance.GetWorldObject<QSBFragment>()
|
||||
.SendMessage(new FragmentIntegrityMessage(__instance._integrity));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -177,97 +154,13 @@ public class MeteorClientPatches : QSBPatch
|
||||
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(typeof(MeteorLauncher), nameof(MeteorLauncher.FixedUpdate))]
|
||||
public static bool FixedUpdate(MeteorLauncher __instance)
|
||||
public static bool MeteorLauncher_FixedUpdate()
|
||||
=> false;
|
||||
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(typeof(MeteorLauncher), nameof(MeteorLauncher.LaunchMeteor))]
|
||||
public static bool LaunchMeteor(MeteorLauncher __instance)
|
||||
{
|
||||
var qsbMeteorLauncher = __instance.GetWorldObject<QSBMeteorLauncher>();
|
||||
|
||||
MeteorController meteorController = null;
|
||||
QSBMeteor qsbMeteor;
|
||||
|
||||
bool MeteorMatches(MeteorController x)
|
||||
{
|
||||
qsbMeteor = x.GetWorldObject<QSBMeteor>();
|
||||
return qsbMeteor.ObjectId == qsbMeteorLauncher.MeteorId;
|
||||
}
|
||||
|
||||
if (__instance._meteorPool != null)
|
||||
{
|
||||
meteorController = __instance._meteorPool.Find(MeteorMatches);
|
||||
if (meteorController != null)
|
||||
{
|
||||
meteorController.Initialize(__instance.transform, __instance._detectableField, __instance._detectableFluid);
|
||||
}
|
||||
}
|
||||
else if (__instance._dynamicMeteorPool != null)
|
||||
{
|
||||
meteorController = __instance._dynamicMeteorPool.Find(MeteorMatches);
|
||||
if (meteorController != null)
|
||||
{
|
||||
meteorController.Initialize(__instance.transform, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
if (meteorController != null)
|
||||
{
|
||||
var linearVelocity = __instance._parentBody.GetPointVelocity(__instance.transform.position) + (__instance.transform.TransformDirection(__instance._launchDirection) * qsbMeteorLauncher.LaunchSpeed);
|
||||
var angularVelocity = __instance.transform.forward * 2f;
|
||||
meteorController.Launch(null, __instance.transform.position, __instance.transform.rotation, linearVelocity, angularVelocity);
|
||||
if (__instance._audioSector.ContainsOccupant(DynamicOccupant.Player))
|
||||
{
|
||||
__instance._launchSource.pitch = Random.Range(0.4f, 0.6f);
|
||||
__instance._launchSource.PlayOneShot(AudioType.BH_MeteorLaunch);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugLog.ToConsole($"{qsbMeteorLauncher} - could not find meteor {qsbMeteorLauncher.MeteorId} in pool", MessageType.Warning);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(typeof(MeteorController), nameof(MeteorController.Impact))]
|
||||
public static bool Impact(MeteorController __instance,
|
||||
GameObject hitObject, Vector3 impactPoint, Vector3 impactVel)
|
||||
{
|
||||
__instance._intactRenderer.enabled = false;
|
||||
__instance._impactLight.enabled = true;
|
||||
__instance._impactLight.intensity = __instance._impactLightCurve.Evaluate(0f);
|
||||
var rotation = Quaternion.LookRotation(impactVel);
|
||||
foreach (var particleSystem in __instance._impactParticles)
|
||||
{
|
||||
particleSystem.transform.rotation = rotation;
|
||||
particleSystem.Play();
|
||||
}
|
||||
|
||||
__instance._impactSource.PlayOneShot(AudioType.BH_MeteorImpact);
|
||||
foreach (var owCollider in __instance._owColliders)
|
||||
{
|
||||
owCollider.SetActivation(false);
|
||||
}
|
||||
|
||||
__instance._owRigidbody.MakeKinematic();
|
||||
__instance.transform.SetParent(hitObject.GetAttachedOWRigidbody().transform);
|
||||
FragmentSurfaceProxy.UntrackMeteor(__instance);
|
||||
FragmentCollisionProxy.UntrackMeteor(__instance);
|
||||
__instance._ignoringCollisions = false;
|
||||
__instance._hasImpacted = true;
|
||||
__instance._impactTime = Time.time;
|
||||
|
||||
var qsbMeteor = __instance.GetWorldObject<QSBMeteor>();
|
||||
if (QSBMeteor.IsSpecialImpact(hitObject))
|
||||
{
|
||||
qsbMeteor.SendMessage(new MeteorSpecialImpactMessage());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
[HarmonyPatch(typeof(FragmentIntegrity), nameof(FragmentIntegrity.AddDamage))]
|
||||
public static bool FragmentIntegrity_AddDamage()
|
||||
=> false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -277,86 +170,46 @@ public class MeteorPatches : QSBPatch
|
||||
{
|
||||
public override QSBPatchTypes Type => QSBPatchTypes.OnClientConnect;
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(MeteorController), nameof(MeteorController.Impact))]
|
||||
public static void MeteorController_Impact(MeteorController __instance,
|
||||
GameObject hitObject, Vector3 impactPoint, Vector3 impactVel)
|
||||
{
|
||||
if (QSBMeteor.IsSpecialImpact(hitObject))
|
||||
{
|
||||
__instance.GetWorldObject<QSBMeteor>()
|
||||
.SendMessage(new MeteorSpecialImpactMessage());
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(typeof(DetachableFragment), nameof(DetachableFragment.Detach))]
|
||||
public static void Detach_Prefix(DetachableFragment __instance, out FragmentIntegrity __state) =>
|
||||
public static void DetachableFragment_Detach_Prefix(DetachableFragment __instance, out FragmentIntegrity __state) =>
|
||||
// this gets set to null in Detach, so store it here and and then restore it in postfix
|
||||
__state = __instance._fragmentIntegrity;
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(DetachableFragment), nameof(DetachableFragment.Detach))]
|
||||
public static void Detach_Postfix(DetachableFragment __instance, FragmentIntegrity __state) =>
|
||||
public static void DetachableFragment_Detach_Postfix(DetachableFragment __instance, FragmentIntegrity __state) =>
|
||||
__instance._fragmentIntegrity = __state;
|
||||
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(typeof(DebrisLeash), nameof(DebrisLeash.MoveByDistance))]
|
||||
public static bool MoveByDistance(DebrisLeash __instance,
|
||||
float distance)
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(DebrisLeash), nameof(DebrisLeash.Init))]
|
||||
public static void DebrisLeash_Init(DebrisLeash __instance)
|
||||
{
|
||||
if (__instance._detachableFragment == null || __instance._detachableFragment._fragmentIntegrity == null)
|
||||
{
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
|
||||
var qsbFragment = __instance._detachableFragment._fragmentIntegrity.GetWorldObject<QSBFragment>();
|
||||
|
||||
if (__instance.enabled)
|
||||
if (qsbFragment.LeashLength != null)
|
||||
{
|
||||
var vector = __instance._attachedBody.GetPosition() - __instance._anchorBody.GetPosition();
|
||||
var d = Mathf.Min(distance, qsbFragment.LeashLength - vector.magnitude);
|
||||
__instance._attachedBody.SetPosition(__instance._anchorBody.GetPosition() + (vector.normalized * d));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(typeof(DebrisLeash), nameof(DebrisLeash.FixedUpdate))]
|
||||
public static bool FixedUpdate(DebrisLeash __instance)
|
||||
{
|
||||
if (__instance._detachableFragment == null || __instance._detachableFragment._fragmentIntegrity == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!QSBWorldSync.AllObjectsReady)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var qsbFragment = __instance._detachableFragment._fragmentIntegrity.GetWorldObject<QSBFragment>();
|
||||
|
||||
if (!__instance._deccelerating)
|
||||
{
|
||||
var num = Vector3.Distance(__instance._attachedBody.GetPosition(), __instance._anchorBody.GetPosition());
|
||||
var num2 = Mathf.Pow(__instance._attachedBody.GetVelocity().magnitude, 2f) / (2f * __instance._deccel);
|
||||
var vector = __instance._attachedBody.GetVelocity() - __instance._anchorBody.GetVelocity();
|
||||
if (num >= qsbFragment.LeashLength - num2 && vector.magnitude > 0.1f)
|
||||
{
|
||||
__instance._deccelerating = true;
|
||||
return false;
|
||||
}
|
||||
__instance._leashLength = (float)qsbFragment.LeashLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
var vector2 = __instance._attachedBody.GetVelocity() - __instance._anchorBody.GetVelocity();
|
||||
var velocityChange = -vector2.normalized * Mathf.Min(__instance._deccel * Time.deltaTime, vector2.magnitude);
|
||||
if (velocityChange.magnitude < 0.01f)
|
||||
{
|
||||
__instance._attachedBody.SetVelocity(__instance._anchorBody.GetVelocity());
|
||||
__instance._deccelerating = false;
|
||||
if (__instance._detachableFragment != null)
|
||||
{
|
||||
__instance._detachableFragment.ComeToRest(__instance._anchorBody);
|
||||
}
|
||||
|
||||
__instance.enabled = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
__instance._attachedBody.AddVelocityChange(velocityChange);
|
||||
DebugLog.ToConsole($"DebrisLeash.Init called for {qsbFragment} before LeashLength was set", MessageType.Warning);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,27 +11,34 @@ public class QSBFragment : WorldObject<FragmentIntegrity>
|
||||
{
|
||||
public override async UniTask Init(CancellationToken ct)
|
||||
{
|
||||
DetachableFragment = AttachedObject.GetComponent<DetachableFragment>();
|
||||
|
||||
if (QSBCore.IsHost)
|
||||
{
|
||||
LeashLength = Random.Range(MeteorManager.WhiteHoleVolume._debrisDistMin, MeteorManager.WhiteHoleVolume._debrisDistMax);
|
||||
// SetIntegrity(0);
|
||||
}
|
||||
}
|
||||
|
||||
public override void SendInitialState(uint to) =>
|
||||
this.SendMessage(new FragmentInitialStateMessage(this) { To = to });
|
||||
public override void SendInitialState(uint to)
|
||||
{
|
||||
this.SendMessage(new FragmentInitialStateMessage(AttachedObject._origIntegrity, (float)LeashLength) { To = to });
|
||||
this.SendMessage(new FragmentIntegrityMessage(AttachedObject._integrity));
|
||||
}
|
||||
|
||||
public DetachableFragment DetachableFragment;
|
||||
public bool IsDetached => DetachableFragment != null && DetachableFragment._isDetached;
|
||||
public bool IsThruWhiteHole => IsDetached && DetachableFragment._sector != null &&
|
||||
DetachableFragment._sector._parentSector == MeteorManager.WhiteHoleVolume._whiteHoleSector;
|
||||
public OWRigidbody RefBody => IsThruWhiteHole ? MeteorManager.WhiteHoleVolume._whiteHoleBody : Locator._brittleHollow._owRigidbody;
|
||||
public OWRigidbody Body => IsDetached ? AttachedObject.transform.parent.parent.GetAttachedOWRigidbody() : null;
|
||||
public void SetIntegrity(float integrity)
|
||||
{
|
||||
if (OWMath.ApproxEquals(AttachedObject._integrity, integrity))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/// what the leash length will be when we eventually detach and fall thru white hole
|
||||
public float LeashLength;
|
||||
AttachedObject._integrity = integrity;
|
||||
AttachedObject.CallOnTakeDamage();
|
||||
}
|
||||
|
||||
public void AddDamage(float damage)
|
||||
=> AttachedObject.AddDamage(damage);
|
||||
}
|
||||
/// <summary>
|
||||
/// what the leash length will be when we eventually detach and fall thru white hole.
|
||||
/// <para/>
|
||||
/// generated by the server and sent to clients in the initial state message.
|
||||
/// </summary>
|
||||
public float? LeashLength;
|
||||
}
|
||||
|
@ -1,26 +1,38 @@
|
||||
using QSB.WorldSync;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using QSB.WorldSync;
|
||||
using System.Threading;
|
||||
using UnityEngine;
|
||||
|
||||
namespace QSB.MeteorSync.WorldObjects;
|
||||
|
||||
public class QSBMeteor : WorldObject<MeteorController>
|
||||
{
|
||||
private QSBMeteorLauncher _qsbMeteorLauncher;
|
||||
|
||||
public override async UniTask Init(CancellationToken ct)
|
||||
{
|
||||
var meteorLauncher = AttachedObject._suspendRoot.GetComponent<MeteorLauncher>();
|
||||
await UniTask.WaitUntil(() => QSBWorldSync.AllObjectsAdded, cancellationToken: ct);
|
||||
_qsbMeteorLauncher = meteorLauncher.GetWorldObject<QSBMeteorLauncher>();
|
||||
}
|
||||
|
||||
public override void SendInitialState(uint to)
|
||||
{
|
||||
// todo SendInitialState
|
||||
}
|
||||
|
||||
public static bool IsSpecialImpact(GameObject go) =>
|
||||
go == Locator.GetPlayerCollider().gameObject || (Locator.GetProbe() != null && go == Locator.GetProbe()._anchor._collider.gameObject);
|
||||
go == Locator.GetPlayerCollider().gameObject ||
|
||||
Locator.GetProbe() != null && go == Locator.GetProbe()._anchor._collider.gameObject;
|
||||
|
||||
public void SpecialImpact()
|
||||
{
|
||||
AttachedObject._intactRenderer.enabled = false;
|
||||
AttachedObject._impactLight.enabled = true;
|
||||
AttachedObject._impactLight.intensity = AttachedObject._impactLightCurve.Evaluate(0f);
|
||||
foreach (var particleSystem in AttachedObject._impactParticles)
|
||||
foreach (var impactParticle in AttachedObject._impactParticles)
|
||||
{
|
||||
particleSystem.Play();
|
||||
impactParticle.Play();
|
||||
}
|
||||
|
||||
AttachedObject._impactSource.PlayOneShot(AudioType.BH_MeteorImpact);
|
||||
@ -36,4 +48,4 @@ public class QSBMeteor : WorldObject<MeteorController>
|
||||
AttachedObject._hasImpacted = true;
|
||||
AttachedObject._impactTime = Time.time;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,34 +1,52 @@
|
||||
using QSB.WorldSync;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using QSB.Utility;
|
||||
using QSB.WorldSync;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using UnityEngine;
|
||||
|
||||
namespace QSB.MeteorSync.WorldObjects;
|
||||
|
||||
public class QSBMeteorLauncher : WorldObject<MeteorLauncher>
|
||||
{
|
||||
private QSBMeteor[] _qsbMeteors;
|
||||
|
||||
public override async UniTask Init(CancellationToken ct)
|
||||
{
|
||||
var meteors = AttachedObject._meteorPool.EmptyIfNull().Concat(AttachedObject._dynamicMeteorPool.EmptyIfNull());
|
||||
await UniTask.WaitUntil(() => QSBWorldSync.AllObjectsAdded, cancellationToken: ct);
|
||||
_qsbMeteors = meteors.Select(x => x.GetWorldObject<QSBMeteor>()).ToArray();
|
||||
}
|
||||
|
||||
public override void SendInitialState(uint to)
|
||||
{
|
||||
// todo SendInitialState
|
||||
}
|
||||
|
||||
public int MeteorId;
|
||||
public float LaunchSpeed;
|
||||
|
||||
public void PreLaunchMeteor()
|
||||
{
|
||||
foreach (var particleSystem in AttachedObject._launchParticles)
|
||||
foreach (var launchParticle in AttachedObject._launchParticles)
|
||||
{
|
||||
particleSystem.Play();
|
||||
launchParticle.Play();
|
||||
}
|
||||
}
|
||||
|
||||
public void LaunchMeteor(int meteorId, float launchSpeed)
|
||||
public void LaunchMeteor(MeteorController meteor, float launchSpeed)
|
||||
{
|
||||
MeteorId = meteorId;
|
||||
LaunchSpeed = launchSpeed;
|
||||
meteor.Initialize(AttachedObject.transform, AttachedObject._detectableField, AttachedObject._detectableFluid);
|
||||
|
||||
AttachedObject.LaunchMeteor();
|
||||
foreach (var particleSystem in AttachedObject._launchParticles)
|
||||
var linearVelocity = AttachedObject._parentBody.GetPointVelocity(AttachedObject.transform.position) + AttachedObject.transform.TransformDirection(AttachedObject._launchDirection) * launchSpeed;
|
||||
var angularVelocity = AttachedObject.transform.forward * 2f;
|
||||
meteor.Launch(null, AttachedObject.transform.position, AttachedObject.transform.rotation, linearVelocity, angularVelocity);
|
||||
if (AttachedObject._audioSector.ContainsOccupant(DynamicOccupant.Player))
|
||||
{
|
||||
particleSystem.Stop();
|
||||
AttachedObject._launchSource.pitch = Random.Range(0.4f, 0.6f);
|
||||
AttachedObject._launchSource.PlayOneShot(AudioType.BH_MeteorLaunch);
|
||||
}
|
||||
|
||||
foreach (var launchParticle in AttachedObject._launchParticles)
|
||||
{
|
||||
launchParticle.Stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,8 +5,10 @@ using QSB.OrbSync.Messages;
|
||||
using QSB.OrbSync.TransformSync;
|
||||
using QSB.Utility;
|
||||
using QSB.WorldSync;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace QSB.OrbSync.WorldObjects;
|
||||
|
||||
@ -37,7 +39,7 @@ public class QSBOrb : WorldObject<NomaiInterfaceOrb>
|
||||
public override void SendInitialState(uint to)
|
||||
{
|
||||
this.SendMessage(new OrbDragMessage(AttachedObject._isBeingDragged) { To = to });
|
||||
var slotIndex = AttachedObject._slots.IndexOf(AttachedObject._occupiedSlot);
|
||||
var slotIndex = Array.IndexOf(AttachedObject._slots, AttachedObject._occupiedSlot);
|
||||
this.SendMessage(new OrbSlotMessage(slotIndex, false) { To = to });
|
||||
}
|
||||
|
||||
|
@ -74,7 +74,7 @@ public class PlayerJoinMessage : QSBMessage
|
||||
|
||||
var player = QSBPlayerManager.GetPlayer(From);
|
||||
player.Name = PlayerName;
|
||||
DebugLog.ToAll($"{player} joined!", MessageType.Info);
|
||||
DebugLog.ToAll($"{player.Name} joined!", MessageType.Info);
|
||||
DebugLog.DebugWrite($"{player} joined. qsbVersion:{QSBVersion}, gameVersion:{GameVersion}, dlcInstalled:{DlcInstalled}", MessageType.Info);
|
||||
}
|
||||
|
||||
|
@ -156,7 +156,7 @@ public static class Extensions
|
||||
return y;
|
||||
}
|
||||
|
||||
public static int IndexOf<T>(this T[] array, T value) => Array.IndexOf(array, value);
|
||||
public static IEnumerable<T> EmptyIfNull<T>(this IEnumerable<T> source) => source ?? Enumerable.Empty<T>();
|
||||
|
||||
public static bool IsInRange<T>(this IList<T> list, int index) => index >= 0 && index < list.Count;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user