using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text.Json;
using BoneLib;
using BonelabGunGame;
using HarmonyLib;
using Il2CppSLZ.Marrow;
using Il2CppSLZ.Marrow.Combat;
using Il2CppSLZ.Marrow.Data;
using Il2CppSLZ.Marrow.Warehouse;
using LabFusion.Entities;
using LabFusion.Extensions;
using LabFusion.Network;
using LabFusion.Network.Serialization;
using LabFusion.Player;
using LabFusion.RPC;
using LabFusion.SDK.Gamemodes;
using LabFusion.SDK.Modules;
using MelonLoader;
using Microsoft.CodeAnalysis;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: MelonInfo(typeof(FusionGunGameMod), "Fusion Gun Game", "1.0.8", "Local Mod", null)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("FusionGunGame")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("FusionGunGame")]
[assembly: AssemblyTitle("FusionGunGame")]
[assembly: AssemblyVersion("1.0.0.0")]
[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 BonelabGunGame
{
public sealed class FusionGunGameMod : MelonMod
{
private Harmony _harmony;
public override void OnInitializeMelon()
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0010: Expected O, but got Unknown
_harmony = new Harmony("local.bonelab.fusiongungame");
_harmony.PatchAll(Assembly.GetExecutingAssembly());
if (MelonBase.FindMelon("LabFusion", "Lakatrazz") == null)
{
((MelonBase)this).LoggerInstance.Warning("Fusion was not found; Gun Game will stay inactive.");
return;
}
ModuleManager.RegisterModule<GunGameModule>();
GamemodeRegistration.LoadGamemodes(Assembly.GetExecutingAssembly());
((MelonBase)this).LoggerInstance.Msg("Fusion Gun Game loaded. Select it from Fusion's gamemode list.");
}
public override void OnDeinitializeMelon()
{
Harmony harmony = _harmony;
if (harmony != null)
{
harmony.UnpatchSelf();
}
}
}
public sealed class GunGameModule : Module
{
public override string Name => "Fusion Gun Game";
public override string Author => "Local Mod";
public override Version Version => new Version(1, 0, 8);
public override ConsoleColor Color => ConsoleColor.Cyan;
protected override void OnModuleRegistered()
{
ModuleMessageManager.RegisterHandler<KillReportMessage>();
ModuleMessageManager.RegisterHandler<TierUpdateMessage>();
}
}
public sealed class FusionGunGameMode : Gamemode
{
private static readonly string[] FallbackBarcodes = new string[10] { "c1534c5a-fcfc-4f43-8fb0-d29531393131", "c1534c5a-bcb7-4f02-a4f5-da9550333530", "c1534c5a-2a4f-481f-8542-cc9545646572", "c1534c5a-d00c-4aa8-adfd-3495534d474d", "c1534c5a-8d03-42de-93c7-f595534d4755", "c1534c5a-4c47-428d-b5a5-b05747756e56", "c1534c5a-40e5-40e0-8139-194347756e55", "c1534c5a-a6b5-4177-beb8-04d947756e41", "c1534c5a-9112-49e5-b022-9c955269666c", "c1534c5a-c061-4c5c-a5e2-3d955269666c" };
private const int MatchTiers = 10;
private static readonly Random Random = new Random();
private static FusionGunGameMode _instance;
private readonly GunGameProgression _progression = new GunGameProgression(10);
private byte? _lastAttacker;
private float _lastAttackTime;
private ushort? _currentNetworkWeaponId;
private string _currentBarcode;
private readonly Dictionary<byte, (int tier, string barcode)> _lastAppliedUpdate = new Dictionary<byte, (int, string)>();
private readonly Dictionary<byte, float> _recentVictimDeaths = new Dictionary<byte, float>();
private int _respawnGeneration;
internal static float LocalInvulnerabilityUntil = float.NegativeInfinity;
public override string Title => "Gun Game";
public override string Author => "Local Mod";
public override string Description => "Get a player kill to advance to the next weapon. First to finish the weapon ladder wins.";
public override void OnGamemodeRegistered()
{
_instance = this;
((Gamemode)this).OnGamemodeRegistered();
}
public override void OnGamemodeUnregistered()
{
if (_instance == this)
{
_instance = null;
}
((Gamemode)this).OnGamemodeUnregistered();
}
public override void OnGamemodeStarted()
{
SdkGunCatalog.Load();
_progression.ResetMatch();
_lastAppliedUpdate.Clear();
_recentVictimDeaths.Clear();
_lastAttacker = null;
LocalHealth.OnAttackedByPlayer += OnAttackedByPlayer;
LocalHealth.OnRespawn += OnLocalRespawn;
SpawnLocalTier(0, PickGun());
((Gamemode)this).OnGamemodeStarted();
}
public override void OnGamemodeStopped()
{
LocalHealth.OnAttackedByPlayer -= OnAttackedByPlayer;
LocalHealth.OnRespawn -= OnLocalRespawn;
LocalInvulnerabilityUntil = float.NegativeInfinity;
_lastAttacker = null;
_respawnGeneration++;
DespawnCurrentWeapon();
_progression.ResetMatch();
_lastAppliedUpdate.Clear();
_recentVictimDeaths.Clear();
((Gamemode)this).OnGamemodeStopped();
}
protected override void OnPlayerLeft(PlayerID player)
{
_progression.ResetPlayer(player.SmallID);
((Gamemode)this).OnPlayerLeft(player);
}
private void OnAttackedByPlayer(Attack attack, BodyPart bodyPart, PlayerID attacker)
{
if (attacker != null && attacker.IsValid)
{
_lastAttacker = attacker.SmallID;
_lastAttackTime = Time.time;
}
}
private void OnLocalRespawn()
{
_lastAttacker = null;
LocalInvulnerabilityUntil = Time.time + 3f;
MelonLogger.Msg("Gun Game: 3-second respawn immunity started.");
MelonCoroutines.Start(RespawnRoutine(++_respawnGeneration));
}
private IEnumerator RespawnRoutine(int generation)
{
yield return (object)new WaitForSeconds(0.8f);
if (generation == _respawnGeneration && ((Gamemode)this).IsStarted && PlayerIDManager.LocalID != null)
{
MoveToRandomSpawn();
SpawnLocalTier(_progression.GetTier(PlayerIDManager.LocalID.SmallID), _currentBarcode ?? PickGun());
}
}
internal static void OnLocalPlayerDeath(Player_Health health)
{
//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
FusionGunGameMode instance = _instance;
if (instance == null || !((Gamemode)instance).IsStarted || (Object)(object)health == (Object)null)
{
return;
}
RigManager rigManager = Player.RigManager;
if ((Object)(object)rigManager == (Object)null || (Object)(object)((Component)health).transform == (Object)null || (Object)(object)((Component)health).transform.root != (Object)(object)((Component)rigManager).transform.root)
{
return;
}
if (!instance._lastAttacker.HasValue || Time.time - instance._lastAttackTime > 10f)
{
instance._lastAttacker = null;
return;
}
PlayerID localID = PlayerIDManager.LocalID;
byte value = instance._lastAttacker.Value;
instance._lastAttacker = null;
if (localID != null && value != localID.SmallID)
{
KillReportData killReportData = new KillReportData
{
KillerId = value,
VictimId = localID.SmallID
};
if (NetworkInfo.IsHost)
{
ProcessKillReport(killReportData);
}
else
{
MessageRelay.RelayModule<KillReportMessage, KillReportData>(killReportData, new MessageRoute((RelayType)1, (NetworkChannel)0));
}
MelonLogger.Msg($"Gun Game: reported player kill {value} -> {localID.SmallID}.");
}
}
internal static void HandleKillReport(KillReportData data, ReceivedMessage received)
{
FusionGunGameMode instance = _instance;
if (instance != null && ((Gamemode)instance).IsStarted && NetworkInfo.IsHost && (!((ReceivedMessage)(ref received)).Sender.HasValue || ((ReceivedMessage)(ref received)).Sender.Value == data.VictimId))
{
ProcessKillReport(data);
}
}
private static void ProcessKillReport(KillReportData data)
{
//IL_0138: Unknown result type (might be due to invalid IL or missing references)
FusionGunGameMode instance = _instance;
if (instance == null || !((Gamemode)instance).IsStarted || !NetworkInfo.IsHost || data.KillerId == data.VictimId)
{
return;
}
float time = Time.time;
if (!instance._recentVictimDeaths.TryGetValue(data.VictimId, out var value) || !(time - value < 3f))
{
instance._recentVictimDeaths[data.VictimId] = time;
if (instance._progression.RecordKill(data.KillerId, data.VictimId, out var newTier))
{
bool isWinner = instance._progression.HasWon(data.KillerId);
MelonLogger.Msg($"Gun Game: player {data.KillerId} advanced to weapon tier {newTier + 1}.");
string barcode = instance.PickGun();
TierUpdateData tierUpdateData = new TierUpdateData
{
PlayerId = data.KillerId,
Tier = newTier,
IsWinner = isWinner,
Barcode = barcode
};
instance.ApplyTier(tierUpdateData.PlayerId, tierUpdateData.Tier, tierUpdateData.IsWinner, tierUpdateData.Barcode);
MessageRelay.RelayModule<TierUpdateMessage, TierUpdateData>(tierUpdateData, new MessageRoute((RelayType)2, (NetworkChannel)0));
}
}
}
internal static void HandleTierUpdate(TierUpdateData data)
{
_instance?.ApplyTier(data.PlayerId, data.Tier, data.IsWinner, data.Barcode);
}
private void ApplyTier(byte playerId, int tier, bool winner, string barcode)
{
if (_lastAppliedUpdate.TryGetValue(playerId, out (int, string) value) && value.Item1 == tier && string.Equals(value.Item2, barcode, StringComparison.Ordinal))
{
return;
}
_lastAppliedUpdate[playerId] = (tier, barcode);
_progression.ApplyAuthoritativeTier(playerId, tier);
if (playerId == PlayerIDManager.LocalID.SmallID)
{
if (winner)
{
MelonLogger.Msg("Gun Game: you won the match!");
}
else
{
SpawnLocalTier(tier, barcode);
}
}
if (winner)
{
MelonLogger.Msg($"Gun Game: player {playerId} won the match.");
if (NetworkInfo.IsHost)
{
GamemodeManager.StopGamemode();
}
}
}
private string PickGun()
{
IReadOnlyList<string> barcodes = SdkGunCatalog.Barcodes;
if (barcodes.Count <= 0)
{
return FallbackBarcodes[Random.Next(FallbackBarcodes.Length)];
}
return barcodes[Random.Next(barcodes.Count)];
}
private void SpawnLocalTier(int tier, string barcode)
{
//IL_007a: Unknown result type (might be due to invalid IL or missing references)
//IL_0080: Unknown result type (might be due to invalid IL or missing references)
//IL_008a: Unknown result type (might be due to invalid IL or missing references)
//IL_008f: Unknown result type (might be due to invalid IL or missing references)
//IL_0094: Unknown result type (might be due to invalid IL or missing references)
//IL_0159: Unknown result type (might be due to invalid IL or missing references)
//IL_015b: Unknown result type (might be due to invalid IL or missing references)
//IL_0160: Unknown result type (might be due to invalid IL or missing references)
//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
//IL_00c7: Expected O, but got Unknown
//IL_00c9: Expected O, but got Unknown
//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
//IL_0112: Unknown result type (might be due to invalid IL or missing references)
if (tier < 0 || tier >= _progression.TierCount)
{
return;
}
try
{
DespawnCurrentWeapon();
RigManager rigManager = Player.RigManager;
if ((Object)(object)rigManager == (Object)null || (Object)(object)rigManager.physicsRig == (Object)null || (Object)(object)((Rig)rigManager.physicsRig).m_head == (Object)null)
{
return;
}
Transform head = ((Rig)rigManager.physicsRig).m_head;
Vector3 val = head.position + head.forward * 0.8f;
if (string.IsNullOrWhiteSpace(barcode))
{
barcode = PickGun();
}
_currentBarcode = barcode;
if (NetworkInfo.HasServer)
{
Spawnable spawnable = new Spawnable
{
crateRef = new SpawnableCrateReference(barcode)
};
NetworkAssetSpawner.Spawn(new SpawnRequestInfo
{
Spawnable = spawnable,
Position = val,
Rotation = head.rotation,
SpawnEffect = false,
SpawnSource = (EntitySource)0,
SpawnCallback = delegate(SpawnCallbackInfo info)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
if (info.Entity != null)
{
_currentNetworkWeaponId = info.Entity.ID;
MelonLogger.Msg($"Gun Game: spawned synchronized weapon tier {tier + 1} (entity {info.Entity.ID}).");
}
else
{
MelonLogger.Warning("Gun Game: Fusion returned a weapon spawn without a network entity.");
}
}
});
MelonLogger.Msg($"Gun Game: requesting synchronized weapon tier {tier + 1}.");
}
else
{
HelperMethods.SpawnCrate(barcode, val, head.rotation, Vector3.one, false, (Action<GameObject>)null, (Action<GameObject>)null);
}
}
catch (Exception value)
{
MelonLogger.Error($"Gun Game could not spawn tier {tier + 1}: {value}");
}
}
private void MoveToRandomSpawn()
{
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
//IL_006d: Unknown result type (might be due to invalid IL or missing references)
//IL_0082: Unknown result type (might be due to invalid IL or missing references)
//IL_0090: Unknown result type (might be due to invalid IL or missing references)
//IL_0095: Unknown result type (might be due to invalid IL or missing references)
//IL_0135: Unknown result type (might be due to invalid IL or missing references)
//IL_013a: Unknown result type (might be due to invalid IL or missing references)
//IL_013c: Unknown result type (might be due to invalid IL or missing references)
//IL_015b: Unknown result type (might be due to invalid IL or missing references)
//IL_016f: Unknown result type (might be due to invalid IL or missing references)
//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
//IL_00db: Unknown result type (might be due to invalid IL or missing references)
//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
try
{
RigManager rigManager = Player.RigManager;
if ((Object)(object)rigManager == (Object)null)
{
return;
}
Vector3 position = ((Component)rigManager).transform.position;
List<Vector3> list = new List<Vector3>();
RaycastHit val = default(RaycastHit);
for (int i = 0; i < 40; i++)
{
float num = (float)Random.NextDouble() * ((float)Math.PI * 2f);
float num2 = 12f + (float)Random.NextDouble() * 33f;
float num3 = position.x + Mathf.Cos(num) * num2;
float num4 = position.z + Mathf.Sin(num) * num2;
if (Physics.Raycast(new Vector3(num3, position.y + 100f, num4), Vector3.down, ref val, 250f) && !((Object)(object)((RaycastHit)(ref val)).collider == (Object)null) && !(((RaycastHit)(ref val)).normal.y < 0.65f))
{
Vector3 val2 = ((RaycastHit)(ref val)).point + Vector3.up * 0.2f;
if (Vector3.Distance(val2, position) >= 10f)
{
list.Add(val2);
}
}
}
if (list.Count == 0)
{
MelonLogger.Warning("Gun Game: no walkable ground found near the map's respawn point; keeping the normal location.");
return;
}
Vector3 val3 = list[Random.Next(list.Count)];
RigManagerExtensions.TeleportToPosition(rigManager, val3, true);
MelonLogger.Msg($"Gun Game: teleported from respawn point {position} to random point {val3}.");
}
catch (Exception ex)
{
MelonLogger.Warning("Gun Game: random respawn failed; using normal respawn location. " + ex.Message);
}
}
private void DespawnCurrentWeapon()
{
//IL_0025: Unknown result type (might be due to invalid IL or missing references)
//IL_0041: Unknown result type (might be due to invalid IL or missing references)
ushort? currentNetworkWeaponId = _currentNetworkWeaponId;
_currentNetworkWeaponId = null;
try
{
if (NetworkInfo.HasServer && currentNetworkWeaponId.HasValue)
{
NetworkAssetSpawner.Despawn(new DespawnRequestInfo
{
EntityID = currentNetworkWeaponId.Value,
DespawnEffect = false
});
}
}
catch (Exception ex)
{
MelonLogger.Warning("Gun Game could not remove the previous weapon: " + ex.Message);
}
}
}
public sealed class KillReportData : INetSerializable
{
public byte KillerId;
public byte VictimId;
public int? GetSize()
{
return 2;
}
public void Serialize(INetSerializer serializer)
{
serializer.SerializeValue(ref KillerId);
serializer.SerializeValue(ref VictimId);
}
}
public sealed class KillReportMessage : ModuleMessageHandler
{
protected override void OnHandleMessage(ReceivedMessage received)
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
FusionGunGameMode.HandleKillReport(((ReceivedMessage)(ref received)).ReadData<KillReportData>(), received);
}
}
internal static class SdkGunCatalog
{
private static readonly List<string> _barcodes = new List<string>();
public static IReadOnlyList<string> Barcodes => _barcodes;
public static void Load()
{
if (_barcodes.Count > 0)
{
return;
}
string text = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "AppData", "LocalLow", "Stress Level Zero", "BONELAB", "Mods");
if (!Directory.Exists(text))
{
MelonLogger.Warning("Gun Game: SDK mods folder was not found at " + text + "; using fallback firearms.");
return;
}
HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
int num = 0;
int num2 = 0;
foreach (string item in Directory.EnumerateFiles(text, "*.pallet.json", SearchOption.AllDirectories))
{
try
{
using JsonDocument jsonDocument = JsonDocument.Parse(File.ReadAllText(item));
if (!jsonDocument.RootElement.TryGetProperty("objects", out var value) || value.ValueKind != JsonValueKind.Object)
{
continue;
}
if (IsExcludedPallet(item, value))
{
num++;
continue;
}
foreach (JsonProperty item2 in value.EnumerateObject())
{
JsonElement value2 = item2.Value;
if (!value2.TryGetProperty("isa", out var value3) || !value3.TryGetProperty("type", out var value4) || !(value4.GetString() ?? string.Empty).StartsWith("crate-spawnable", StringComparison.OrdinalIgnoreCase) || !value2.TryGetProperty("tags", out var value5) || value5.ValueKind != JsonValueKind.Array || !value5.EnumerateArray().Any((JsonElement tag) => string.Equals(tag.GetString(), "Gun", StringComparison.OrdinalIgnoreCase)))
{
continue;
}
JsonElement value6;
if (HasExcludedGunName(value2))
{
num2++;
}
else if (value2.TryGetProperty("barcode", out value6) && value6.ValueKind == JsonValueKind.String)
{
string text2 = value6.GetString();
if (!string.IsNullOrWhiteSpace(text2))
{
hashSet.Add(text2);
}
}
}
}
catch (Exception ex)
{
MelonLogger.Warning("Gun Game: couldn't read SDK pallet " + Path.GetFileName(item) + ": " + ex.Message);
}
}
_barcodes.AddRange(hashSet);
MelonLogger.Msg($"Gun Game: loaded {_barcodes.Count} SDK guns; skipped {num} excluded pallets and {num2} excluded guns.");
if (_barcodes.Count == 0)
{
MelonLogger.Warning("Gun Game: no Gun-tagged SDK crates found; using fallback firearms.");
}
}
private static bool IsExcludedPallet(string file, JsonElement objects)
{
if (ContainsExcludedPack(file.Replace('\\', '/')))
{
return true;
}
foreach (JsonProperty item in objects.EnumerateObject())
{
JsonElement value = item.Value;
if (value.TryGetProperty("isa", out var value2) && value2.TryGetProperty("type", out var value3) && (value3.GetString() ?? string.Empty).StartsWith("pallet", StringComparison.OrdinalIgnoreCase))
{
return ContainsExcludedPack(GetString(value, "title")) || ContainsExcludedPack(GetString(value, "barcode"));
}
}
return false;
}
private static bool HasExcludedGunName(JsonElement crate)
{
string value = GetString(crate, "title");
string text = GetString(crate, "barcode");
if (!ContainsTranqName(value) && !ContainsTranqName(text))
{
return text.StartsWith("CyberBlue.LowPolyWeaponPack.", StringComparison.OrdinalIgnoreCase);
}
return true;
}
private static bool ContainsExcludedPack(string value)
{
if (!value.Contains("deadpool", StringComparison.OrdinalIgnoreCase) && !value.Contains("lowpoly", StringComparison.OrdinalIgnoreCase))
{
return value.Contains("low poly", StringComparison.OrdinalIgnoreCase);
}
return true;
}
private static bool ContainsTranqName(string value)
{
if (!value.Contains("tranq", StringComparison.OrdinalIgnoreCase))
{
return value.Contains("tranquil", StringComparison.OrdinalIgnoreCase);
}
return true;
}
private static string GetString(JsonElement element, string property)
{
if (!element.TryGetProperty(property, out var value) || value.ValueKind != JsonValueKind.String)
{
return string.Empty;
}
return value.GetString() ?? string.Empty;
}
}
public sealed class TierUpdateData : INetSerializable
{
public byte PlayerId;
public int Tier;
public bool IsWinner;
public string Barcode;
public int? GetSize()
{
return null;
}
public void Serialize(INetSerializer serializer)
{
serializer.SerializeValue(ref PlayerId);
serializer.SerializeValue(ref Tier);
serializer.SerializeValue(ref IsWinner);
serializer.SerializeValue(ref Barcode);
}
}
public sealed class TierUpdateMessage : ModuleMessageHandler
{
protected override void OnHandleMessage(ReceivedMessage received)
{
FusionGunGameMode.HandleTierUpdate(((ReceivedMessage)(ref received)).ReadData<TierUpdateData>());
}
}
[HarmonyPatch(typeof(Player_Health), "Death")]
internal static class PlayerDeathPatch
{
[HarmonyPostfix]
private static void Postfix(Player_Health __instance)
{
FusionGunGameMode.OnLocalPlayerDeath(__instance);
}
}
[HarmonyPatch(typeof(Player_Health), "TAKEDAMAGE")]
internal static class RespawnImmunityPatch
{
[HarmonyPrefix]
private static bool Prefix(Player_Health __instance)
{
if (Time.time >= FusionGunGameMode.LocalInvulnerabilityUntil || (Object)(object)__instance == (Object)null || (Object)(object)((Component)__instance).transform == (Object)null)
{
return true;
}
RigManager rigManager = Player.RigManager;
if ((Object)(object)rigManager == (Object)null || (Object)(object)((Component)__instance).transform.root != (Object)(object)((Component)rigManager).transform.root)
{
return true;
}
return false;
}
}
public sealed class GunGameProgression
{
private readonly Dictionary<int, int> _tiers = new Dictionary<int, int>();
private readonly int _tierCount;
public int TierCount => _tierCount;
public GunGameProgression(int tierCount)
{
if (tierCount <= 0)
{
throw new ArgumentOutOfRangeException("tierCount");
}
_tierCount = tierCount;
}
public int GetTier(int playerId)
{
if (!_tiers.TryGetValue(playerId, out var value))
{
return 0;
}
return value;
}
public bool RecordKill(int killerId, int victimId, out int newTier)
{
newTier = GetTier(killerId);
if (killerId == victimId || newTier >= _tierCount)
{
return false;
}
newTier++;
_tiers[killerId] = newTier;
return true;
}
public void ApplyAuthoritativeTier(int playerId, int tier)
{
if (tier < 0 || tier > _tierCount)
{
throw new ArgumentOutOfRangeException("tier");
}
if (tier == 0)
{
_tiers.Remove(playerId);
}
else
{
_tiers[playerId] = tier;
}
}
public bool HasWon(int playerId)
{
return GetTier(playerId) >= _tierCount;
}
public void ResetPlayer(int playerId)
{
_tiers.Remove(playerId);
}
public void ResetMatch()
{
_tiers.Clear();
}
}
}