Skip to content

Commit

Permalink
Spawning transpiler (#2241)
Browse files Browse the repository at this point in the history
  • Loading branch information
VALERA771 committed Nov 29, 2023
1 parent 96eb33b commit caaa732
Showing 1 changed file with 74 additions and 29 deletions.
103 changes: 74 additions & 29 deletions Exiled.Events/Patches/Events/Player/Spawning.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,19 @@

namespace Exiled.Events.Patches.Events.Player
{
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;

using API.Features;
using Exiled.API.Features.Pools;
using Exiled.Events.Attributes;
using Exiled.Events.EventArgs.Player;

using HarmonyLib;

using PlayerRoles;
using PlayerRoles.FirstPersonControl;
using PlayerRoles.FirstPersonControl.NetworkMessages;
using PlayerRoles.FirstPersonControl.Spawnpoints;

using UnityEngine;

using static HarmonyLib.AccessTools;

/// <summary>
Expand All @@ -37,38 +35,85 @@ private static MethodInfo TargetMethod()
return Method(TypeByName("PlayerRoles.FirstPersonControl.Spawnpoints.RoleSpawnpointManager").GetNestedTypes(all)[1], "<Init>b__2_0");
}

private static bool Prefix(ReferenceHub hub, PlayerRoleBase prevRole, PlayerRoleBase newRole)
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
if (newRole.ServerSpawnReason != RoleChangeReason.Destroyed && Player.TryGet(hub, out Player player))
{
Vector3 oldPosition = hub.transform.position;
float oldRotation = (prevRole as IFpcRole)?.FpcModule.MouseLook.CurrentVertical ?? 0;
List<CodeInstruction> newInstructions = ListPool<CodeInstruction>.Pool.Get(instructions);

Label skipLabel = generator.DefineLabel();

newInstructions[0].labels.Add(skipLabel);

if (newRole is IFpcRole fpcRole)
newInstructions.InsertRange(
0,
new CodeInstruction[]
{
if (newRole.ServerSpawnFlags.HasFlag(RoleSpawnFlags.UseSpawnpoint) && fpcRole.SpawnpointHandler != null && fpcRole.SpawnpointHandler.TryGetSpawnpoint(out Vector3 position, out float horizontalRot))
{
oldPosition = position;
oldRotation = horizontalRot;
}
// if (newRole is IFpcRole)
// goto skipLabel
new(OpCodes.Ldarg_3),
new(OpCodes.Isinst, typeof(IFpcRole)),
new(OpCodes.Brtrue_S, skipLabel),

// Player.Get(hub)
new(OpCodes.Ldarg_1),
new(OpCodes.Call, Method(typeof(Player), nameof(Player.Get), new[] { typeof(ReferenceHub) })),
new(OpCodes.Dup),

// Player::Position
new(OpCodes.Callvirt, PropertyGetter(typeof(Player), nameof(Player.Position))),

// 0f
new(OpCodes.Ldc_R4, 0f),

// oldRole
new(OpCodes.Ldarg_2),

// SpawningEventArgs(Player, Vector3, 0, PlayerRoleBase)
new(OpCodes.Newobj, GetDeclaredConstructors(typeof(SpawningEventArgs))[0]),

SpawningEventArgs ev = new(player, oldPosition, oldRotation, prevRole);
// Handlers.Player.OnSpawning(ev)
new(OpCodes.Call, Method(typeof(Handlers.Player), nameof(Handlers.Player.OnSpawning))),
});

Handlers.Player.OnSpawning(ev);
int index = newInstructions.FindLastIndex(x => x.opcode == OpCodes.Ldarg_1);

hub.transform.position = ev.Position;
fpcRole.FpcModule.MouseLook.CurrentHorizontal = ev.HorizontalRotation;
hub.connectionToClient.Send(new FpcOverrideMessage(ev.Position, ev.HorizontalRotation), 0);
}
else
IEnumerable<Label> labels = newInstructions[index].labels;

newInstructions.RemoveRange(index, 9);

newInstructions.InsertRange(
index,
new[]
{
Handlers.Player.OnSpawning(new(player, oldPosition, oldRotation, prevRole));
}
// Player.Get(hub)
new CodeInstruction(OpCodes.Ldarg_1).WithLabels(labels),
new(OpCodes.Call, Method(typeof(Player), nameof(Player.Get), new[] { typeof(ReferenceHub) })),

// position
new(OpCodes.Ldloc_1),

// rotation
new(OpCodes.Ldloc_2),

// oldRole
new(OpCodes.Ldarg_2),

return false;
}
// SpawningEventArgs(Player, Vector3, float, PlayerRoleBase)
new(OpCodes.Newobj, GetDeclaredConstructors(typeof(SpawningEventArgs))[0]),
new(OpCodes.Dup),

return true;
// Handlers.Player.OnSpawning(ev)
new(OpCodes.Call, Method(typeof(Handlers.Player), nameof(Handlers.Player.OnSpawning))),

// Set position and horizontal rotation
new(OpCodes.Call, Method(typeof(Spawning), nameof(Send))),
});

for (int z = 0; z < newInstructions.Count; z++)
yield return newInstructions[z];

ListPool<CodeInstruction>.Pool.Return(newInstructions);
}

private static void Send(SpawningEventArgs ev) => ev.Player.ReferenceHub.connectionToClient.Send(new FpcOverrideMessage(ev.Position, ev.HorizontalRotation));
}
}
}

0 comments on commit caaa732

Please sign in to comment.