using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using ChainedPuzzles;
using GameData;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem.Collections.Generic;
using Microsoft.CodeAnalysis;
using Player;
using SNetwork;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("GTFOshouleimod")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("GTFOshouleimod")]
[assembly: AssemblyTitle("GTFOshouleimod")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace GTFOshouleimod
{
[BepInPlugin("com.gtfo.glowsticktogrenade", "GlowStick To Grenade", "6.2.2")]
public class Plugin : BasePlugin
{
internal static ManualLogSource Log;
private const uint GreenGlowStickItemId = 114u;
private const uint RedGlowStickItemId = 130u;
private const uint OrangeGlowStickItemId = 167u;
private const uint YellowGlowStickItemId = 174u;
private const uint GrenadeItemId = 136u;
private const string CheckpointWarningMessageChinese = "[警告] 重生点扫描期间请勿投掷手雷,否则读取存档可能无限循环!";
private const string CheckpointWarningMessageEnglish1 = "[WARNING] Don't throw grenades during the scan!";
private const string CheckpointWarningMessageEnglish2 = "[WARNING] It may cause an infinite reload loop!";
private static bool _checkpointCaptureOpen;
private static bool _checkpointScanActive;
private static bool _throwBlockLogged;
private static float _throwUnlockAt;
private static int _checkpointRecallDepth;
public override void Load()
{
//IL_007c: Unknown result type (might be due to invalid IL or missing references)
//IL_0082: Expected O, but got Unknown
//IL_0095: Unknown result type (might be due to invalid IL or missing references)
//IL_00a2: Expected O, but got Unknown
//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
//IL_0104: Unknown result type (might be due to invalid IL or missing references)
//IL_0111: Expected O, but got Unknown
//IL_0111: Expected O, but got Unknown
//IL_0244: Unknown result type (might be due to invalid IL or missing references)
//IL_0252: Expected O, but got Unknown
//IL_0267: Unknown result type (might be due to invalid IL or missing references)
//IL_0274: Expected O, but got Unknown
//IL_0289: Unknown result type (might be due to invalid IL or missing references)
//IL_0296: Expected O, but got Unknown
//IL_02aa: Unknown result type (might be due to invalid IL or missing references)
//IL_02b8: Expected O, but got Unknown
//IL_02cd: Unknown result type (might be due to invalid IL or missing references)
//IL_02da: Expected O, but got Unknown
//IL_02ef: Unknown result type (might be due to invalid IL or missing references)
//IL_02fc: Expected O, but got Unknown
Log = ((BasePlugin)this).Log;
Log.LogInfo((object)"======================================");
Log.LogInfo((object)" GlowStick To Grenade");
Log.LogInfo((object)"======================================");
try
{
MethodInfo methodInfo = AccessTools.Method(typeof(ConsumableDistributionDataBlock), "Setup", (Type[])null, (Type[])null);
if (methodInfo == null)
{
Log.LogError((object)"找不到 ConsumableDistributionDataBlock.Setup!");
return;
}
Harmony val = new Harmony("com.gtfo.glowsticktogrenade");
val.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(Plugin), "ConsumableDistributionSetupPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
MethodInfo methodInfo2 = AccessTools.Method(typeof(ReplicatedItemWrapper), "TryCollectCaptureData", (Type[])null, (Type[])null);
if (methodInfo2 == null)
{
Log.LogError((object)"找不到 ReplicatedItemWrapper.TryCollectCaptureData!");
return;
}
val.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(Plugin), "TryCollectCaptureDataPrefix", (Type[])null), new HarmonyMethod(typeof(Plugin), "TryCollectCaptureDataPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
MethodInfo methodInfo3 = AccessTools.Method(typeof(SNet_Capture), "OpenBuffer", new Type[2]
{
typeof(eBufferType),
typeof(ushort)
}, (Type[])null);
MethodInfo methodInfo4 = AccessTools.Method(typeof(SNet_Capture), "CloseBuffer", new Type[1] { typeof(eBufferType) }, (Type[])null);
MethodInfo methodInfo5 = AccessTools.Method(typeof(SNet_Capture), "OnResetSession", (Type[])null, (Type[])null);
MethodInfo methodInfo6 = AccessTools.Method(typeof(ThrowingWeapon), "Update", Type.EmptyTypes, (Type[])null);
MethodInfo methodInfo7 = AccessTools.Method(typeof(CP_Bioscan_Core), "OnSyncStateChange", (Type[])null, (Type[])null);
MethodInfo methodInfo8 = AccessTools.Method(typeof(CP_Bioscan_Core), "OnDestroy", Type.EmptyTypes, (Type[])null);
if (methodInfo3 == null || methodInfo4 == null || methodInfo5 == null || methodInfo6 == null || methodInfo7 == null || methodInfo8 == null)
{
Log.LogError((object)"找不到检查点缓冲区或投掷状态方法!");
return;
}
val.Patch((MethodBase)methodInfo3, new HarmonyMethod(typeof(Plugin), "OpenBufferPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
val.Patch((MethodBase)methodInfo4, (HarmonyMethod)null, new HarmonyMethod(typeof(Plugin), "CloseBufferPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
val.Patch((MethodBase)methodInfo5, (HarmonyMethod)null, new HarmonyMethod(typeof(Plugin), "ResetSessionPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
val.Patch((MethodBase)methodInfo6, new HarmonyMethod(typeof(Plugin), "ThrowingWeaponUpdatePrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
val.Patch((MethodBase)methodInfo7, (HarmonyMethod)null, new HarmonyMethod(typeof(Plugin), "BioscanStateChangePostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
val.Patch((MethodBase)methodInfo8, (HarmonyMethod)null, new HarmonyMethod(typeof(Plugin), "BioscanDestroyPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
Log.LogInfo((object)"成功 Hook 消耗品生成、检查点缓冲区和投掷状态");
Log.LogInfo((object)"关卡生成时将荧光棒分布项替换为手雷 ID 136");
Log.LogInfo((object)"检查点扫描 1%-100% 及最终保存期间禁止投掷 ID 136");
}
catch (Exception ex)
{
Log.LogError((object)"Hook 消耗品生成表失败:");
Log.LogError((object)ex);
}
}
private static void ConsumableDistributionSetupPostfix()
{
try
{
int num = 0;
Il2CppArrayBase<ConsumableDistributionDataBlock> allBlocks = GameDataBlockBase<ConsumableDistributionDataBlock>.GetAllBlocks();
foreach (ConsumableDistributionDataBlock item in allBlocks)
{
if (item == null || item.SpawnData == null)
{
continue;
}
Enumerator<ConsumableSpawnData> enumerator2 = item.SpawnData.GetEnumerator();
while (enumerator2.MoveNext())
{
ConsumableSpawnData current2 = enumerator2.Current;
if (current2 != null && IsGlowStick(current2.ItemID))
{
uint itemID = current2.ItemID;
current2.ItemID = 136u;
num++;
Log.LogInfo((object)("生成表 " + ((GameDataBlockBase<ConsumableDistributionDataBlock>)(object)item).persistentID + ": " + itemID + " -> " + 136u));
}
}
}
Log.LogInfo((object)("生成阶段替换完成,共修改 " + num + " 个荧光棒分布项;未修改 pItemData 或 prefab"));
}
catch (Exception ex)
{
Log.LogError((object)"修改消耗品生成表失败:");
Log.LogError((object)ex);
}
}
private static bool TryCollectCaptureDataPrefix(ReplicatedItemWrapper __instance, ref bool __result, ref eCapturePass captureType)
{
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
try
{
if ((Object)(object)__instance != (Object)null && !__instance.m_aboutToBeDestroyed && (Object)(object)__instance.Item != (Object)null)
{
uint itemID_gearCRC = __instance.Item.Get_pItemData().itemID_gearCRC;
if (itemID_gearCRC != 136)
{
return true;
}
}
captureType = (eCapturePass)0;
__result = false;
Log.LogDebug((object)"检查点捕获时跳过 ID 136 或无效的 ReplicatedItemWrapper");
return false;
}
catch (Exception ex)
{
captureType = (eCapturePass)0;
__result = false;
Log.LogError((object)"检查点物品保护执行失败,已安全跳过该物品:");
Log.LogError((object)ex);
return false;
}
}
private static void TryCollectCaptureDataPostfix(ref pItemSpawnData spawnData, ref bool __result, ref eCapturePass captureType)
{
if (!__result)
{
return;
}
try
{
uint itemID_gearCRC = spawnData.itemData.itemID_gearCRC;
if (itemID_gearCRC == 136)
{
captureType = (eCapturePass)0;
__result = false;
Log.LogInfo((object)"检查点捕获时从最终 pItemSpawnData 中过滤 ID 136");
}
}
catch (Exception ex)
{
captureType = (eCapturePass)0;
__result = false;
Log.LogError((object)"检查点最终捕获数据检查失败,已安全跳过该物品:");
Log.LogError((object)ex);
}
}
private unsafe static bool ItemSpawnPacketCapturePrefix(pItemSpawnData data, eCapturePass captureDataType)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0003: Unknown result type (might be due to invalid IL or missing references)
try
{
uint itemID_gearCRC = data.itemData.itemID_gearCRC;
if (itemID_gearCRC != 136)
{
return true;
}
Log.LogInfo((object)("检查点保存期间过滤 ID 136 实时物品生成包,捕获阶段: " + ((object)(*(eCapturePass*)(&captureDataType))/*cast due to .constrained prefix*/).ToString()));
return false;
}
catch (Exception ex)
{
Log.LogError((object)"检查实时物品生成包失败,已保留原始捕获行为:");
Log.LogError((object)ex);
return true;
}
}
private static bool ItemRecallSpawnPrefix(SNet_ReplicationManager<pItemSpawnData, ItemReplicator> __instance, pItemSpawnData spawnData)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
if (spawnData.replicationData.isRecall == 0)
{
return true;
}
try
{
uint itemID_gearCRC = spawnData.itemData.itemID_gearCRC;
ushort prefabID = spawnData.replicationData.PrefabID;
bool flag = __instance == null || __instance.m_prefabs == null || prefabID >= __instance.m_prefabs.Count || (Object)(object)__instance.m_prefabs[(int)prefabID] == (Object)null;
if (itemID_gearCRC != 136 && !flag)
{
return true;
}
Log.LogWarning((object)("检查点读取时跳过不安全的物品记录:ItemID=" + itemID_gearCRC + ", PrefabID=" + prefabID + ", InvalidPrefab=" + flag));
return false;
}
catch (Exception ex)
{
Log.LogError((object)"验证检查点物品回放记录失败,已跳过该记录:");
Log.LogError((object)ex);
return false;
}
}
private static bool GetItemReplicatorPrefix(SNet_ReplicationManager_Item __instance, ref pItemSpawnData spawnData, ref GameObject go, ref ItemReplicator __result)
{
if (_checkpointRecallDepth <= 0 && spawnData.replicationData.isRecall == 0)
{
return true;
}
try
{
ushort prefabID = spawnData.replicationData.PrefabID;
uint itemID_gearCRC = spawnData.itemData.itemID_gearCRC;
bool flag = __instance == null || ((SNet_ReplicationManager<pItemSpawnData, ItemReplicator>)(object)__instance).m_prefabs == null || prefabID >= ((SNet_ReplicationManager<pItemSpawnData, ItemReplicator>)(object)__instance).m_prefabs.Count || (Object)(object)((SNet_ReplicationManager<pItemSpawnData, ItemReplicator>)(object)__instance).m_prefabs[(int)prefabID] == (Object)null;
bool flag2 = itemID_gearCRC == 136;
if (!flag && !flag2)
{
return true;
}
if (TryFindRegisteredItemPrefab(__instance, 136u, out var prefabId, out var actualItemId, out var prefabName) || TryFindRegisteredItemPrefab(__instance, 114u, out prefabId, out actualItemId, out prefabName) || TryFindRegisteredItemPrefab(__instance, 174u, out prefabId, out actualItemId, out prefabName) || TryFindSafeFallbackPrefab(__instance, out prefabId, out actualItemId, out prefabName))
{
ushort num = prefabID;
uint num2 = itemID_gearCRC;
spawnData.replicationData.PrefabID = prefabId;
spawnData.itemData.itemID_gearCRC = actualItemId;
Log.LogWarning((object)("已修正不安全的检查点物品记录:ItemID=" + num2 + " -> " + actualItemId + ", PrefabID=" + num + " -> " + prefabId + ", ReplacementPrefab=" + prefabName + ", RecallDepth=" + _checkpointRecallDepth));
return true;
}
go = null;
__result = null;
Log.LogError((object)("找不到可用于修正检查点的已注册物品 prefab:ItemID=" + itemID_gearCRC + ", PrefabID=" + prefabID + ", PacketIsRecall=" + spawnData.replicationData.isRecall + ", RecallDepth=" + _checkpointRecallDepth + ", InvalidPrefab=" + flag));
return false;
}
catch (Exception ex)
{
go = null;
__result = null;
Log.LogError((object)"验证物品复制器数据失败,已阻止本次不安全创建:");
Log.LogError((object)ex);
return false;
}
}
private static bool TryFindRegisteredItemPrefab(SNet_ReplicationManager_Item manager, uint wantedItemId, out ushort prefabId, out uint actualItemId, out string prefabName)
{
//IL_0079: Unknown result type (might be due to invalid IL or missing references)
prefabId = 0;
actualItemId = 0u;
prefabName = string.Empty;
if (manager == null || ((SNet_ReplicationManager<pItemSpawnData, ItemReplicator>)(object)manager).m_prefabs == null)
{
return false;
}
int count = ((SNet_ReplicationManager<pItemSpawnData, ItemReplicator>)(object)manager).m_prefabs.Count;
for (int i = 0; i < count && i <= 65535; i++)
{
GameObject val = ((SNet_ReplicationManager<pItemSpawnData, ItemReplicator>)(object)manager).m_prefabs[i];
if ((Object)(object)val == (Object)null)
{
continue;
}
try
{
Item componentInChildren = val.GetComponentInChildren<Item>(true);
if (!((Object)(object)componentInChildren == (Object)null))
{
uint itemID_gearCRC = componentInChildren.Get_pItemData().itemID_gearCRC;
if (itemID_gearCRC == wantedItemId)
{
prefabId = (ushort)i;
actualItemId = itemID_gearCRC;
prefabName = ((Object)val).name;
return true;
}
}
}
catch
{
}
}
return false;
}
private static bool TryFindSafeFallbackPrefab(SNet_ReplicationManager_Item manager, out ushort prefabId, out uint actualItemId, out string prefabName)
{
prefabId = 0;
actualItemId = 114u;
prefabName = string.Empty;
if (manager == null || ((SNet_ReplicationManager<pItemSpawnData, ItemReplicator>)(object)manager).m_prefabs == null)
{
return false;
}
int num = -1;
string text = string.Empty;
int count = ((SNet_ReplicationManager<pItemSpawnData, ItemReplicator>)(object)manager).m_prefabs.Count;
for (int i = 0; i < count && i <= 65535; i++)
{
GameObject val = ((SNet_ReplicationManager<pItemSpawnData, ItemReplicator>)(object)manager).m_prefabs[i];
if (!((Object)(object)val == (Object)null))
{
string text2 = ((Object)val).name ?? string.Empty;
if (num < 0)
{
num = i;
text = text2;
}
if (text2.IndexOf("glow", StringComparison.OrdinalIgnoreCase) >= 0 || text2.IndexOf("stick", StringComparison.OrdinalIgnoreCase) >= 0)
{
prefabId = (ushort)i;
prefabName = text2;
return true;
}
}
}
if (num < 0)
{
return false;
}
prefabId = (ushort)num;
prefabName = text;
return true;
}
private static void OpenBufferPrefix(eBufferType type)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0003: Invalid comparison between Unknown and I4
if ((int)type == 3)
{
_checkpointCaptureOpen = true;
_checkpointScanActive = false;
_throwBlockLogged = false;
_throwUnlockAt = Time.unscaledTime + 1.5f;
Log.LogInfo((object)"检查点保存开始:暂时禁止投掷 ID 136");
}
}
private static void CloseBufferPostfix(eBufferType type)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0003: Invalid comparison between Unknown and I4
if ((int)type == 3)
{
_checkpointCaptureOpen = false;
_checkpointScanActive = false;
_throwBlockLogged = false;
_throwUnlockAt = 0f;
Log.LogInfo((object)"检查点保存完成:恢复投掷 ID 136");
}
}
private static void ResetSessionPostfix()
{
_checkpointCaptureOpen = false;
_checkpointScanActive = false;
_throwBlockLogged = false;
_throwUnlockAt = 0f;
}
private static void BioscanStateChangePostfix(CP_Bioscan_Core __instance, eBioscanStatus status, float progress)
{
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: Invalid comparison between Unknown and I4
//IL_006d: Unknown result type (might be due to invalid IL or missing references)
//IL_006f: Invalid comparison between Unknown and I4
try
{
if ((Object)(object)__instance == (Object)null || __instance.Owner == null || !__instance.Owner.IsCheckpointScanner)
{
return;
}
if ((int)status == 3)
{
if (!_checkpointScanActive)
{
Log.LogInfo((object)"检查点扫描开始:暂时禁止投掷 ID 136");
BroadcastCheckpointWarning();
}
_checkpointScanActive = true;
_throwUnlockAt = 0f;
}
else if ((int)status == 4)
{
_checkpointScanActive = true;
_throwUnlockAt = Time.unscaledTime + 5f;
Log.LogInfo((object)"检查点扫描完成:保持投掷锁直到保存结束");
}
else if (!_checkpointCaptureOpen)
{
_checkpointScanActive = false;
_throwBlockLogged = false;
_throwUnlockAt = 0f;
}
}
catch (Exception ex)
{
Log.LogError((object)"更新检查点扫描状态失败:");
Log.LogError((object)ex);
}
}
private static void BroadcastCheckpointWarning()
{
try
{
if (SNet.IsMaster && PlayerManager.HasLocalPlayerAgent())
{
PlayerAgent localPlayerAgent = PlayerManager.GetLocalPlayerAgent();
if (!((Object)(object)localPlayerAgent == (Object)null))
{
PlayerChatManager.WantToSentTextMessage(localPlayerAgent, "[警告] 重生点扫描期间请勿投掷手雷,否则读取存档可能无限循环!", (PlayerAgent)null);
PlayerChatManager.WantToSentTextMessage(localPlayerAgent, "[WARNING] Don't throw grenades during the scan!", (PlayerAgent)null);
PlayerChatManager.WantToSentTextMessage(localPlayerAgent, "[WARNING] It may cause an infinite reload loop!", (PlayerAgent)null);
Log.LogInfo((object)"已向全队广播一轮中英文检查点投掷警告(共三条)");
}
}
}
catch (Exception ex)
{
Log.LogError((object)"广播检查点投掷警告失败:");
Log.LogError((object)ex);
}
}
private static void BioscanDestroyPostfix(CP_Bioscan_Core __instance)
{
try
{
if ((Object)(object)__instance != (Object)null && __instance.Owner != null && __instance.Owner.IsCheckpointScanner)
{
_checkpointScanActive = false;
_checkpointCaptureOpen = false;
_throwBlockLogged = false;
_throwUnlockAt = 0f;
}
}
catch
{
}
}
private static bool ThrowingWeaponUpdatePrefix(ThrowingWeapon __instance)
{
//IL_0075: Unknown result type (might be due to invalid IL or missing references)
if (_throwUnlockAt > 0f && Time.unscaledTime >= _throwUnlockAt)
{
_checkpointCaptureOpen = false;
_checkpointScanActive = false;
_throwBlockLogged = false;
_throwUnlockAt = 0f;
Log.LogInfo((object)"检查点保存保护超时释放:恢复投掷 ID 136");
}
if ((!_checkpointCaptureOpen && !_checkpointScanActive) || (Object)(object)__instance == (Object)null)
{
return true;
}
try
{
if (((Item)__instance).pItemData.itemID_gearCRC != 136)
{
return true;
}
if (!_throwBlockLogged)
{
_throwBlockLogged = true;
Log.LogWarning((object)"检查点正在保存,已暂时阻止投掷 ID 136");
}
return false;
}
catch (Exception ex)
{
Log.LogError((object)"检查投掷状态失败,已保留游戏原始行为:");
Log.LogError((object)ex);
return true;
}
}
private static void RecallBufferPrefix()
{
_checkpointRecallDepth++;
}
private static Exception RecallBufferFinalizer(Exception __exception)
{
if (_checkpointRecallDepth > 0)
{
_checkpointRecallDepth--;
}
return __exception;
}
private static bool IsGlowStick(uint itemId)
{
return itemId == 114 || itemId == 130 || itemId == 167 || itemId == 174;
}
}
}