first commit
This commit is contained in:
92
NitroxPatcher/Patches/Dynamic/PDAScanner_Scan_Patch.cs
Normal file
92
NitroxPatcher/Patches/Dynamic/PDAScanner_Scan_Patch.cs
Normal file
@@ -0,0 +1,92 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
using HarmonyLib;
|
||||
using NitroxClient.Communication.Abstract;
|
||||
using NitroxModel.DataStructures;
|
||||
using NitroxModel.Helper;
|
||||
using NitroxModel.Packets;
|
||||
using NitroxModel_Subnautica.DataStructures;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxPatcher.Patches.Dynamic;
|
||||
|
||||
/// <summary>
|
||||
/// Broadcasts entry progress and entry unlockings when they happen.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is the only method that needs to be tracked to sync and persist PDAScanner's data, because the other methods
|
||||
/// are either unused (found out that they have no actual calls in SN's code, just as <see cref="PDAScanner.RemoveAllEntriesWhichUnlocks"/>)
|
||||
/// or simply called automatically by other events (just as <see cref="PDAScanner.CompleteAllEntriesWhichUnlocks"/>).
|
||||
/// </remarks>
|
||||
public sealed partial class PDAScanner_Scan_Patch : NitroxPatch, IDynamicPatch
|
||||
{
|
||||
internal static readonly MethodInfo TARGET_METHOD = Reflect.Method(() => PDAScanner.Scan());
|
||||
|
||||
internal static readonly OpCode INJECTION_OPCODE = OpCodes.Callvirt;
|
||||
internal static readonly object INJECTION_OPERAND = Reflect.Method((GameObject t) => t.SendMessage(default, default, default));
|
||||
|
||||
public static IEnumerable<CodeInstruction> Transpiler(MethodBase original, IEnumerable<CodeInstruction> instructions)
|
||||
{
|
||||
foreach (CodeInstruction instruction in instructions)
|
||||
{
|
||||
yield return instruction;
|
||||
|
||||
if (instruction.opcode.Equals(INJECTION_OPCODE) && instruction.operand.Equals(INJECTION_OPERAND))
|
||||
{
|
||||
yield return original.Ldloc<PDAScanner.Result>();
|
||||
yield return new(OpCodes.Ldloc_S, original.GetLocalVariableIndex<bool>(4));
|
||||
yield return new(OpCodes.Call, ((Action<PDAScanner.Result, bool>)Callback).Method);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// To determine which exact path the code took, we just need those two parameters
|
||||
public static void Callback(PDAScanner.Result result, bool alreadyComplete)
|
||||
{
|
||||
PDAScanner.ScanTarget scanTarget = PDAScanner.scanTarget;
|
||||
|
||||
TechType techType = scanTarget.techType;
|
||||
PDAScanner.EntryData entryData = PDAScanner.GetEntryData(techType);
|
||||
if (entryData == null || (result != PDAScanner.Result.Done && result != PDAScanner.Result.Researched))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// In the case the player has already fully researched the target
|
||||
if (alreadyComplete)
|
||||
{
|
||||
// In the case that the target is destroyable, the player is given 2 titanium and the object is destroyed
|
||||
// We want to broadcast the destruction event before the object is destroyed and corresponding scan data is invalidated.
|
||||
if (scanTarget.hasUID)
|
||||
{
|
||||
PDAScanFinished packet = new(new(scanTarget.uid), techType.ToDto(), entryData.totalFragments, true, true, true);
|
||||
Resolve<IPacketSender>().Send(packet);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
NitroxId targetId = scanTarget.hasUID ? new(scanTarget.uid) : null;
|
||||
|
||||
// Case in which the unlocked progress is incremented
|
||||
if (result == PDAScanner.Result.Done)
|
||||
{
|
||||
if (!PDAScanner.GetPartialEntryByKey(techType, out PDAScanner.Entry entry))
|
||||
{
|
||||
// Something wrong happened
|
||||
return;
|
||||
}
|
||||
PDAScanFinished packet = new(targetId, techType.ToDto(), entry.unlocked, false, entryData.destroyAfterScan);
|
||||
Resolve<IPacketSender>().Send(packet);
|
||||
}
|
||||
// Case in which the scanned entry is fully unlocked
|
||||
else if (result == PDAScanner.Result.Researched)
|
||||
{
|
||||
PDAScanFinished packet = new(targetId, techType.ToDto(), entryData.totalFragments, true, entryData.destroyAfterScan);
|
||||
Resolve<IPacketSender>().Send(packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user