using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using FriendPatches.Callbacks;
using FriendPatches.Core;
using FriendPatches.Patches;
using FriendPatches.Tools;
using GameNetcodeStuff;
using HarmonyLib;
using Steamworks;
using TMPro;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("FriendPatches")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("FriendPatches")]
[assembly: AssemblyCopyright("Copyright © 2024")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("955504ed-4fb7-496c-856e-f65e5b63ca4b")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace FriendPatches.Tools
{
public static class PatchHelper
{
public static HarmonyMethod Method(Expression<Action> action, bool debug = false)
{
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_0020: Expected O, but got Unknown
return new HarmonyMethod(SymbolExtensions.GetMethodInfo(action), -1, (string[])null, (string[])null, (bool?)debug)
{
priority = 10000
};
}
public static HarmonyMethod Method<A>(Expression<Action<A>> action, bool debug = false)
{
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_0020: Expected O, but got Unknown
return new HarmonyMethod(SymbolExtensions.GetMethodInfo<A>(action), -1, (string[])null, (string[])null, (bool?)debug)
{
priority = 10000
};
}
public static HarmonyMethod Method<A, B>(Expression<Action<A, B>> action, bool debug = false)
{
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_0020: Expected O, but got Unknown
return new HarmonyMethod(SymbolExtensions.GetMethodInfo((LambdaExpression)action), -1, (string[])null, (string[])null, (bool?)debug)
{
priority = 10000
};
}
}
public static class Reflection
{
public static Type Type(string type)
{
return AccessTools.TypeByName(type);
}
public static List<ConstructorInfo> Constructors(string type)
{
return AccessTools.GetDeclaredConstructors(Type(type), (bool?)null);
}
public static List<ConstructorInfo> Constructors(Type type)
{
return AccessTools.GetDeclaredConstructors(type, (bool?)null);
}
public static MethodBase Method(string type, string method, Type[] args = null, bool declared = true)
{
if (declared)
{
return AccessTools.DeclaredMethod(Type(type), method, args, (Type[])null);
}
return AccessTools.Method(Type(type), method, args, (Type[])null);
}
public static MethodBase Method(Type type, string method, Type[] args = null, bool declared = true)
{
if (declared)
{
return AccessTools.DeclaredMethod(type, method, args, (Type[])null);
}
return AccessTools.Method(type, method, args, (Type[])null);
}
public static FieldInfo Field(string type, string field, bool declared = true)
{
if (declared)
{
return AccessTools.DeclaredField(Type(type), field);
}
return AccessTools.Field(Type(type), field);
}
public static FieldInfo Field(Type type, string field, bool declared = true)
{
if (declared)
{
return AccessTools.DeclaredField(type, field);
}
return AccessTools.Field(type, field);
}
public static PropertyInfo Property(string type, string property, bool declared = true)
{
if (declared)
{
return AccessTools.DeclaredProperty(Type(type), property);
}
return AccessTools.Property(Type(type), property);
}
public static PropertyInfo Property(Type type, string property, bool declared = true)
{
if (declared)
{
return AccessTools.DeclaredProperty(type, property);
}
return AccessTools.Property(type, property);
}
}
}
namespace FriendPatches.Patches
{
public static class GameNetworkManager_Patches
{
public static void Apply(Harmony harmony)
{
if (FriendPatchesSettings.SetPlayedWithOnSteam)
{
harmony.Patch(Reflection.Method(typeof(GameNetworkManager), "SteamMatchmaking_OnLobbyMemberJoined"), (HarmonyMethod)null, (HarmonyMethod)null, PatchHelper.Method(() => PlayerJoined(null, null)), (HarmonyMethod)null, (HarmonyMethod)null);
}
}
public static void HandleFriendJoin(List<SteamId> steamIdsInLobby, SteamId id)
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: Unknown result type (might be due to invalid IL or missing references)
//IL_0066: Unknown result type (might be due to invalid IL or missing references)
//IL_006b: Unknown result type (might be due to invalid IL or missing references)
//IL_0071: Unknown result type (might be due to invalid IL or missing references)
//IL_007c: Unknown result type (might be due to invalid IL or missing references)
if (steamIdsInLobby == null || steamIdsInLobby.Contains(id))
{
return;
}
steamIdsInLobby.Add(id);
if ((Object)(object)StartOfRound.Instance != (Object)null && StartOfRound.Instance.localPlayerController.playerSteamId == SteamId.op_Implicit(id))
{
foreach (SteamId otherId in steamIdsInLobby)
{
if (SteamId.op_Implicit(otherId) != SteamId.op_Implicit(id))
{
Task.Run(delegate
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
SteamFriends.SetPlayedWith(otherId);
});
}
}
}
Task.Run(delegate
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
SteamFriends.SetPlayedWith(id);
});
}
private static IEnumerable<CodeInstruction> PlayerJoined(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Expected O, but got Unknown
//IL_0032: Unknown result type (might be due to invalid IL or missing references)
//IL_0038: Expected O, but got Unknown
//IL_0046: Unknown result type (might be due to invalid IL or missing references)
//IL_004c: Expected O, but got Unknown
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
//IL_0060: Expected O, but got Unknown
//IL_006e: Unknown result type (might be due to invalid IL or missing references)
//IL_0074: Expected O, but got Unknown
//IL_0096: Unknown result type (might be due to invalid IL or missing references)
//IL_009c: Expected O, but got Unknown
//IL_00be: Unknown result type (might be due to invalid IL or missing references)
//IL_00c4: Expected O, but got Unknown
//IL_0103: Unknown result type (might be due to invalid IL or missing references)
//IL_010d: Expected O, but got Unknown
CodeMatcher val = new CodeMatcher(instructions, generator);
val.MatchForward(true, (CodeMatch[])(object)new CodeMatch[6]
{
new CodeMatch((Func<CodeInstruction, bool>)((CodeInstruction i) => i.opcode == OpCodes.Ldfld && ((FieldInfo)i.operand).Name == "steamIdsInLobby"), (string)null),
new CodeMatch((OpCode?)OpCodes.Ldloc_1, (object)null, (string)null),
new CodeMatch((OpCode?)OpCodes.Ldloc_3, (object)null, (string)null),
new CodeMatch((OpCode?)OpCodes.Ldelema, (object)null, (string)null),
new CodeMatch((Func<CodeInstruction, bool>)((CodeInstruction i) => i.opcode == OpCodes.Ldfld && ((FieldInfo)i.operand).Name == "Id" && ((FieldInfo)i.operand).DeclaringType == typeof(Friend)), (string)null),
new CodeMatch((Func<CodeInstruction, bool>)((CodeInstruction i) => i.opcode == OpCodes.Callvirt && ((MethodInfo)i.operand).Name == "Add" && ((MethodInfo)i.operand).DeclaringType.Name.StartsWith("List")), (string)null)
});
if (!val.ReportFailure(MethodBase.GetCurrentMethod(), (Action<string>)FriendPatchesPlugin.Log.LogFatal))
{
val.SetInstruction(new CodeInstruction(OpCodes.Call, (object)Reflection.Method(typeof(GameNetworkManager_Patches), "HandleFriendJoin")));
}
return val.InstructionEnumeration();
}
}
}
namespace FriendPatches.Core
{
public static class FriendPatchesInfo
{
public const string GUID = "lauriichan.friendpatches";
public const string PrintName = "FriendPatches";
public const string Version = "1.0.4";
}
public static class FriendPatchesSettings
{
public static bool SetPlayedWithOnSteam { get; private set; }
public static bool UsernameFix { get; private set; }
internal static void SetupConfig(ConfigFile cfg)
{
UsernameFix = cfg.Bind<bool>("General", "Enable the username fix patches", true, "Enables patches that listen to Steam callbacks for username changes and updates the player names accordingly.").Value;
SetPlayedWithOnSteam = cfg.Bind<bool>("Steam", "Enable PlayedWith patches", true, "Enables patches that add players that joined your lobby to the 'Played With' list on Steam.").Value;
}
}
[BepInPlugin("lauriichan.friendpatches", "FriendPatches", "1.0.4")]
internal class FriendPatchesPlugin : BaseUnityPlugin
{
private Harmony harmony;
public static ManualLogSource Log { get; private set; }
public void Awake()
{
Log = ((BaseUnityPlugin)this).Logger;
FriendPatchesSettings.SetupConfig(((BaseUnityPlugin)this).Config);
SetupCallbacks();
SetupPatches();
}
private void SetupPatches()
{
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
//IL_0019: Expected O, but got Unknown
if (harmony == null)
{
harmony = new Harmony("lauriichan.friendpatches");
GameNetworkManager_Patches.Apply(harmony);
}
}
private void SetupCallbacks()
{
SteamFriendsCallback.Apply();
}
public void OnDestroy()
{
if (harmony != null)
{
harmony.UnpatchSelf();
harmony = null;
}
ShutdownCallbacks();
}
private void ShutdownCallbacks()
{
SteamFriendsCallback.Unapply();
}
}
}
namespace FriendPatches.Callbacks
{
public static class SteamFriendsCallback
{
private static bool applied;
public static void Apply()
{
if (FriendPatchesSettings.UsernameFix)
{
applied = true;
SteamFriends.OnPersonaStateChange += PersonaChanged;
}
}
public static void Unapply()
{
if (applied)
{
applied = false;
SteamFriends.OnPersonaStateChange -= PersonaChanged;
}
}
private static void PersonaChanged(Friend friend)
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_0036: Unknown result type (might be due to invalid IL or missing references)
//IL_003b: Unknown result type (might be due to invalid IL or missing references)
//IL_004b: Unknown result type (might be due to invalid IL or missing references)
if (!GameNetworkManager.Instance.currentLobby.HasValue || (Object)(object)StartOfRound.Instance == (Object)null)
{
return;
}
SteamId friendId = friend.Id;
if (GameNetworkManager.Instance.steamIdsInLobby.Contains(friendId))
{
Task.Run(delegate
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
DoNameUpdate(friendId, ((Friend)(ref friend)).Name, ((Friend)(ref friend)).IsMe);
});
}
}
private static void DoNameUpdate(SteamId friendId, string friendName, bool isMe)
{
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
StartOfRound instance = StartOfRound.Instance;
FriendPatchesPlugin.Log.LogInfo((object)$"Updating friend ({friendId}): {friendName}");
PlayerControllerB val = instance.allPlayerScripts[instance.thisClientPlayerId];
ulong num = SteamId.op_Implicit(friendId);
for (int i = 0; i < instance.allPlayerScripts.Length; i++)
{
PlayerControllerB val2 = instance.allPlayerScripts[i];
if ((Object)(object)val2 == (Object)null || !val2.isPlayerControlled || val2.playerSteamId != num)
{
continue;
}
val2.playerUsername = friendName;
if ((Object)(object)val2.usernameBillboardText != (Object)null)
{
((TMP_Text)val2.usernameBillboardText).text = friendName;
}
string name = friendName;
int numberOfDuplicateNamesInLobby = instance.GetNumberOfDuplicateNamesInLobby(val);
if (numberOfDuplicateNamesInLobby > 0)
{
name = $"{friendName}{numberOfDuplicateNamesInLobby}";
}
if ((Object)(object)val.quickMenuManager != (Object)null)
{
PlayerListSlot val3 = val.quickMenuManager.playerListSlots[i];
if (val3 != null)
{
val3.playerSteamId = SteamId.op_Implicit(friendId);
((TMP_Text)val3.usernameHeader).text = friendName;
if ((Object)(object)GameNetworkManager.Instance.localPlayerController != (Object)null)
{
val3.volumeSliderContainer.SetActive(!isMe);
}
}
}
if ((Object)(object)instance.mapScreen == (Object)null)
{
TransformAndName val4 = instance.mapScreen.radarTargets[i];
if (val4 != null)
{
val4.name = name;
}
}
break;
}
}
private static int GetNumberOfDuplicateNamesInLobby(this StartOfRound round, PlayerControllerB self)
{
int num = 0;
for (int i = 0; i < round.allPlayerScripts.Length; i++)
{
PlayerControllerB val = round.allPlayerScripts[i];
if ((Object)(object)val != (Object)null && (val.isPlayerControlled || val.isPlayerDead) && !((Object)(object)val == (Object)(object)self) && val.playerUsername == self.playerUsername)
{
num++;
}
}
for (int j = 0; j < round.allPlayerScripts.Length; j++)
{
PlayerControllerB val = round.allPlayerScripts[j];
if ((Object)(object)val != (Object)null && (val.isPlayerControlled || val.isPlayerDead) && !((Object)(object)val == (Object)(object)self) && val.playerUsername == $"{val.playerUsername}{num}")
{
num++;
}
}
return num;
}
}
}