Files
Nitrox/NitroxPatcher/Patches/Dynamic/Vehicle_TorpedoShot_Patch.cs
2025-07-06 00:23:46 +02:00

68 lines
3.5 KiB
C#

using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
using HarmonyLib;
using NitroxClient.Communication.Abstract;
using NitroxClient.MonoBehaviours;
using NitroxModel.DataStructures;
using NitroxModel.DataStructures.Unity;
using NitroxModel.Helper;
using NitroxModel.Packets;
using NitroxModel_Subnautica.DataStructures;
using UnityEngine;
namespace NitroxPatcher.Patches.Dynamic;
public sealed partial class Vehicle_TorpedoShot_Patch : NitroxPatch, IDynamicPatch
{
internal static readonly MethodInfo TARGET_METHOD = Reflect.Method(() => Vehicle.TorpedoShot(default, default, default));
/*
* Inserts a DUP instruction after the SeamothTorpedo object is pushed onto the stack so we can use it later on
* in the inserted callback.
* NB: Ldarg_0 refers to the 1st parameter (ItemsContainer) and Ldarg_1 refers to the 2nd parameter (TorpedoType) as this method is static
*
* MODIFICATION:
* component.Shoot(muzzle.position, aimingTransform.rotation, num, -1f);
* Vehicle_TorpedoShot_Patch.TorpedoShotCallback(dupped object, torpedoType); <--- INSERTED LINE
* return true;
*
* "dupped object" is the SeamothTorpedo object from the line:
* gameObject.GetComponent<SeamothTorpedo>();
*/
public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
// Always match for one more instruction after the searched one because the cursor will be moved right before it
return new CodeMatcher(instructions).MatchEndForward([
new CodeMatch(OpCodes.Pop),
new CodeMatch(OpCodes.Callvirt, Reflect.Method((GameObject t) => t.GetComponent<SeamothTorpedo>())),
new CodeMatch(OpCodes.Call),
])
.InsertAndAdvance([
new CodeInstruction(OpCodes.Dup),
])
.MatchEndForward([
new CodeMatch(OpCodes.Callvirt, Reflect.Method((Bullet t) => t.Shoot(default, default, default, default))),
new CodeMatch(OpCodes.Ldc_I4_1),
])
.InsertAndAdvance([
new CodeInstruction(OpCodes.Ldarg_1),
new CodeInstruction(OpCodes.Call, Reflect.Method(() => TorpedoShotCallback(default, default)))
])
.InstructionEnumeration();
}
public static void TorpedoShotCallback(SeamothTorpedo seamothTorpedo, TorpedoType torpedoType)
{
NitroxId bulletId = NitroxEntity.GenerateNewId(seamothTorpedo.gameObject);
NitroxVector3 position = seamothTorpedo.transform.position.ToDto();
NitroxQuaternion rotation = seamothTorpedo.transform.rotation.ToDto();
// In Bullet.Shoot, _consumption = f(lifeTime), lifeTime = g(_consumption), this is g:
float lifeTime = seamothTorpedo._consumption > 0 ? 1f / seamothTorpedo._consumption : 0f;
Resolve<IPacketSender>().Send(new TorpedoShot(bulletId, torpedoType.techType.ToDto(), position, rotation, seamothTorpedo.speed, lifeTime));
}
}