using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
using HarmonyLib;
using NitroxClient.Communication.Abstract;
using NitroxClient.GameLogic;
using NitroxClient.GameLogic.PlayerLogic;
using NitroxModel.DataStructures;
using NitroxModel.Helper;
using NitroxModel.Packets;
using UnityEngine;
namespace NitroxPatcher.Patches.Dynamic;
///
/// Prevents non simulating players from running locally .
/// Broadcasts for the simulating player:
/// - attack on cyclops effects
/// - attack on local player effects
/// - attack on remote players effects
///
public sealed partial class SeaDragonMeleeAttack_OnTouchFront_Patch : NitroxPatch, IDynamicPatch
{
internal static readonly MethodInfo TARGET_METHOD = Reflect.Method((SeaDragonMeleeAttack t) => t.OnTouchFront(default));
public static bool Prefix(SeaDragonMeleeAttack __instance)
{
if (!__instance.TryGetNitroxId(out NitroxId creatureId) ||
Resolve().HasAnyLockType(creatureId))
{
return true;
}
return false;
}
/*
* 1st injection:
* base.gameObject.SendMessage("OnMeleeAttack", target, SendMessageOptions.DontRequireReceiver);
* this.timeLastBite = Time.time;
* BroadcastSeaDragonAttackTarget(this, target); <---- INSERTED LINE
*
* 2nd injection:
* global::Utils.PlayEnvSound(this.attackSound, collider.transform.position, 20f);
* }
* component3.gameObject.GetComponent().TakeDamage(this.biteDamage, default(Vector3), DamageType.Normal, base.gameObject);
* BroadcastSeaDragonAttackTarget(this, target); <---- INSERTED LINE
*
* 3rd injection:
* Exosuit component4 = target.GetComponent();
* BroadcastSeaDragonAttackRemotePlayer(this, target); <---- INSERTED LINE
* if (component4 != null)
* {
*/
public static IEnumerable Transpiler(IEnumerable instructions)
{
// 1st injection
return new CodeMatcher(instructions).MatchEndForward([
new CodeMatch(OpCodes.Ldarg_0),
new CodeMatch(OpCodes.Call, Reflect.Property(() => Time.time).GetGetMethod()),
new CodeMatch(OpCodes.Stfld, Reflect.Field((MeleeAttack t) => t.timeLastBite)),
new CodeMatch(OpCodes.Ret)
])
.InsertAndAdvance([
new CodeInstruction(OpCodes.Ldarg_0),
new CodeInstruction(OpCodes.Ldloc_0),
new CodeInstruction(OpCodes.Call, Reflect.Method(() => BroadcastSeaDragonAttackTarget(default, default))),
])
// 2nd injection
.MatchEndForward([
new CodeMatch(OpCodes.Call, Reflect.Property((Component t) => t.gameObject).GetGetMethod()),
new CodeMatch(OpCodes.Callvirt, Reflect.Method((LiveMixin t) => t.TakeDamage(default, default, default, default))),
new CodeMatch(OpCodes.Pop),
new CodeMatch(OpCodes.Br)
])
.InsertAndAdvance([
new CodeInstruction(OpCodes.Ldarg_0),
new CodeInstruction(OpCodes.Ldloc_0),
new CodeInstruction(OpCodes.Call, Reflect.Method(() => BroadcastSeaDragonAttackTarget(default, default))),
])
// 3rd injection
.MatchEndForward([
new CodeMatch(OpCodes.Ldloc_0),
new CodeMatch(OpCodes.Callvirt, Reflect.Method((GameObject t) => t.GetComponent())),
new CodeMatch(OpCodes.Stloc_S),
new CodeMatch(OpCodes.Ldloc_S),
])
.InsertAndAdvance([
new CodeInstruction(OpCodes.Ldarg_0),
new CodeInstruction(OpCodes.Ldloc_0),
new CodeInstruction(OpCodes.Call, Reflect.Method(() => BroadcastSeaDragonAttackRemotePlayer(default, default))),
])
.InstructionEnumeration();
}
public static void BroadcastSeaDragonAttackTarget(SeaDragonMeleeAttack seaDragonMeleeAttack, GameObject target)
{
if (seaDragonMeleeAttack.TryGetNitroxId(out NitroxId seaDragonId) &&
target.TryGetNitroxId(out NitroxId targetId))
{
Resolve().Send(new SeaDragonAttackTarget(seaDragonId, targetId, seaDragonMeleeAttack.seaDragon.Aggression.Value));
}
}
public static void BroadcastSeaDragonAttackRemotePlayer(SeaDragonMeleeAttack seaDragonMeleeAttack, GameObject target)
{
if (target.GetComponent())
{
return;
}
if (seaDragonMeleeAttack.TryGetNitroxId(out NitroxId seaDragonId) &&
target.TryGetComponent(out RemotePlayerIdentifier remotePlayerIdentifier))
{
Resolve().Send(new SeaDragonAttackTarget(seaDragonId, remotePlayerIdentifier.RemotePlayer.PlayerContext.PlayerNitroxId, seaDragonMeleeAttack.seaDragon.Aggression.Value));
}
}
}