Decompiled source of CookieProgression v0.1.2
CookieProgression.dll
Decompiled a month ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using CookieFx; using CookieFx.Client; using CookieFx.Network; using CookieFx.Network.Payloads; using CookieFx.Platform; using CookieFx.Players; using CookieFx.Server; using CookieFx.Skills; using CookieProgression; using CookieProgression.Experience; using CookieProgression.Patches; using CookieProgression.Payloads; using CookieProgression.Skills; using CookieProgression.UI; using GameNetcodeStuff; using HarmonyLib; using Microsoft.CodeAnalysis; using TMPro; using Unity.Netcode; using UnityEngine; using UnityEngine.Events; using UnityEngine.InputSystem; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: IgnoresAccessChecksTo("AmazingAssets.TerrainToMesh")] [assembly: IgnoresAccessChecksTo("Assembly-CSharp-firstpass")] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: IgnoresAccessChecksTo("ClientNetworkTransform")] [assembly: IgnoresAccessChecksTo("DissonanceVoip")] [assembly: IgnoresAccessChecksTo("Facepunch Transport for Netcode for GameObjects")] [assembly: IgnoresAccessChecksTo("Facepunch.Steamworks.Win64")] [assembly: IgnoresAccessChecksTo("Unity.AI.Navigation")] [assembly: IgnoresAccessChecksTo("Unity.Animation.Rigging")] [assembly: IgnoresAccessChecksTo("Unity.Animation.Rigging.DocCodeExamples")] [assembly: IgnoresAccessChecksTo("Unity.Burst")] [assembly: IgnoresAccessChecksTo("Unity.Burst.Unsafe")] [assembly: IgnoresAccessChecksTo("Unity.Collections")] [assembly: IgnoresAccessChecksTo("Unity.Collections.LowLevel.ILSupport")] [assembly: IgnoresAccessChecksTo("Unity.InputSystem")] [assembly: IgnoresAccessChecksTo("Unity.InputSystem.ForUI")] [assembly: IgnoresAccessChecksTo("Unity.Jobs")] [assembly: IgnoresAccessChecksTo("Unity.Mathematics")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.Common")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.MetricTypes")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStats")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Component")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Configuration")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Implementation")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsReporting")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetworkProfiler.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetworkSolutionInterface")] [assembly: IgnoresAccessChecksTo("Unity.Netcode.Components")] [assembly: IgnoresAccessChecksTo("Unity.Netcode.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.Networking.Transport")] [assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Csg")] [assembly: IgnoresAccessChecksTo("Unity.ProBuilder")] [assembly: IgnoresAccessChecksTo("Unity.ProBuilder.KdTree")] [assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Poly2Tri")] [assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Stl")] [assembly: IgnoresAccessChecksTo("Unity.Profiling.Core")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.ShaderLibrary")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.HighDefinition.Config.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.HighDefinition.Runtime")] [assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary")] [assembly: IgnoresAccessChecksTo("Unity.Services.Authentication")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Analytics")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Configuration")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Device")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Environments")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Environments.Internal")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Internal")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Networking")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Registration")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Scheduler")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Telemetry")] [assembly: IgnoresAccessChecksTo("Unity.Services.Core.Threading")] [assembly: IgnoresAccessChecksTo("Unity.Services.QoS")] [assembly: IgnoresAccessChecksTo("Unity.Services.Relay")] [assembly: IgnoresAccessChecksTo("Unity.TextMeshPro")] [assembly: IgnoresAccessChecksTo("Unity.Timeline")] [assembly: IgnoresAccessChecksTo("Unity.VisualEffectGraph.Runtime")] [assembly: IgnoresAccessChecksTo("UnityEngine.ARModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.NVIDIAModule")] [assembly: IgnoresAccessChecksTo("UnityEngine.UI")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("CookieSylvia")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("0.1.2.0")] [assembly: AssemblyInformationalVersion("0.1.2")] [assembly: AssemblyProduct("CookieProgression")] [assembly: AssemblyTitle("CookieProgression")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.1.2.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.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 CookieFx.Skills { public enum SkillFormat { Modifier, Mulitply, SubtractSeconds, Value } } namespace CookieFx.Patches { [HarmonyPatch] [HarmonyWrapSafe] internal static class DoorLockPatch { [HarmonyPatch(typeof(DoorLock), "Update")] [HarmonyTranspiler] private static IEnumerable<CodeInstruction> OnUpdate(IEnumerable<CodeInstruction> instructions) { FieldInfo lockPickTimeLeft = AccessTools.DeclaredField(typeof(DoorLock), "lockPickTimeLeft"); MethodInfo deltaTime = AccessTools.DeclaredPropertyGetter(typeof(Time), "deltaTime"); MethodInfo getMul = AccessUtils.MethodInfo((LambdaExpression)(Expression<Func<Func<SkillType, double>>>)(() => SkillManager.GetTeamMultiplier)); int step = 0; foreach (CodeInstruction instruction in instructions) { yield return instruction; if (CodeInstructionExtensions.IsLdarg(instruction, (int?)0)) { step = 1; continue; } if (step == 1 && CodeInstructionExtensions.LoadsField(instruction, lockPickTimeLeft, false)) { step = 2; continue; } if (step == 2 && CodeInstructionExtensions.Calls(instruction, deltaTime)) { yield return new CodeInstruction(OpCodes.Ldc_I4, (object)18); yield return new CodeInstruction(OpCodes.Call, (object)getMul); yield return new CodeInstruction(OpCodes.Conv_R4, (object)null); yield return new CodeInstruction(OpCodes.Ldc_R4, (object)1f); yield return new CodeInstruction(OpCodes.Add, (object)null); yield return new CodeInstruction(OpCodes.Mul, (object)null); } step = 0; } } } [HarmonyPatch] [HarmonyWrapSafe] internal static class ExpPatches { [HarmonyPatch(typeof(TimeOfDay), "SetNewProfitQuota")] [HarmonyTranspiler] private static IEnumerable<CodeInstruction> OnQuotaChange(IEnumerable<CodeInstruction> instructions) { MethodInfo original = AccessUtils.MethodInfo((LambdaExpression)(Expression<Func<Action<int, int, int>>>)(() => ((TimeOfDay)null).SyncNewProfitQuotaClientRpc)); MethodInfo target = AccessUtils.MethodInfo((LambdaExpression)(Expression<Func<Action<TimeOfDay, int, int, int>>>)(() => OnQuotaChangeRedirect)); bool found = false; foreach (CodeInstruction instruction in instructions) { if (CodeInstructionExtensions.Calls(instruction, original)) { yield return new CodeInstruction(OpCodes.Call, (object)target); found = true; } else { yield return instruction; } } if (!found) { Logger.Error("[Patch] Unable to patch quota change."); } } private static void OnQuotaChangeRedirect(TimeOfDay script, int newProfitQuota, int overtimeBonus, int fulfilledQuota) { int num = overtimeBonus; try { num = (int)((double)overtimeBonus * (1.0 + SkillManager.GetTeamMultiplier(SkillType.OvertimeBonus))); } finally { script.SyncNewProfitQuotaClientRpc(newProfitQuota, num, fulfilledQuota); } } } } namespace CookieProgression { internal static class Config { private record BoundSkill(ConfigEntry<bool> Enabled, ConfigEntry<int> MaxLevel, ConfigEntry<int> Multiplier); private record BoundEnemy(ConfigEntry<EnemyExpType> ExpType, ConfigEntry<int> Range, ConfigEntry<int> BaseExp); public enum EnemyExpType { Disabled, AoE, Attacker } private static readonly Dictionary<SkillType, BoundSkill> SkillBindings = new Dictionary<SkillType, BoundSkill>(); private static readonly Dictionary<Type, BoundEnemy> EnemyBindings = new Dictionary<Type, BoundEnemy>(); private static bool s_dirty = false; internal static void Setup(ConfigFile file) { Guard.NotNull<ConfigFile>(file, "file"); foreach (BoundSkill value in SkillBindings.Values) { value.Enabled.SettingChanged -= OnSkillChanged; value.MaxLevel.SettingChanged -= OnSkillChanged; value.Multiplier.SettingChanged -= OnSkillChanged; } SkillBindings.Clear(); SkillType[] array = (SkillType[])Enum.GetValues(typeof(SkillType)); foreach (SkillType skill in array) { BindSkill(file, skill); } foreach (BoundSkill value2 in SkillBindings.Values) { value2.Enabled.SettingChanged += OnSkillChanged; value2.MaxLevel.SettingChanged += OnSkillChanged; value2.Multiplier.SettingChanged += OnSkillChanged; } EnemyBindings.Clear(); foreach (Type item in (from type in Reflect.AllTypesAssignableTo(typeof(EnemyAI)) where type != typeof(EnemyAI) select type).OrderBy(GetEnemyFriendlyName)) { BindEnemy(file, item); } } private static void OnSkillChanged(object? sender, EventArgs e) { if (!Networking.IsConnected || !Networking.Instance.IsServer) { return; } s_dirty = true; Networking.EnqueueTask((Action<Networking>)delegate(Networking instance) { if (!s_dirty || !instance.IsServer) { return; } s_dirty = false; AbstractServer server = instance.Server; SkillManager skills = default(SkillManager); foreach (ServerPlayer player in server.Players) { if (((AbstractPlayer)player).TryGet<SkillManager>(ref skills)) { SetSkills(skills); } } }); } internal static void SetSkills(SkillManager manager) { manager.SetDefinitions(from x in SkillBindings where x.Value.Enabled.Value select (x.Key, Math.Clamp(x.Value.MaxLevel.Value, 1, 99999), Math.Clamp(x.Value.Multiplier.Value, 1, 1000000))); } internal static (EnemyExpType, int Range, int BaseExp) GetEnemyExp(Type enemy) { if (EnemyBindings.TryGetValue(enemy, out BoundEnemy value)) { return (value.ExpType.Value, Math.Max(value.Range.Value, 0), Math.Max(value.BaseExp.Value, 0)); } Logger.Warning("Enemy [" + enemy.FullName + "] doesn't have a bound config entry."); return (EnemyExpType.Disabled, 0, 0); } private static void BindSkill(ConfigFile file, SkillType skill) { string name = skill.GetName(); Logger.Info("Found skill type [" + name + "]"); int defaultMaxLevel = skill.GetDefaultMaxLevel(); int defaultMultiplier = skill.GetDefaultMultiplier(); ConfigEntry<bool> enabled = file.Bind<bool>(name, "Enable " + name, true, "Enable the " + name + " skill."); ConfigEntry<int> maxLevel = file.Bind<int>(name, name + " Max Level", defaultMaxLevel, "Maximum level for " + name); ConfigEntry<int> multiplier = file.Bind<int>(name, name + " Multiplier", defaultMultiplier, $"How much does the {name} skill increase per level? ({10000:N0} = 100% or 100s)"); SkillBindings[skill] = new BoundSkill(enabled, maxLevel, multiplier); } private static void BindEnemy(ConfigFile file, Type enemy) { string enemyFriendlyName = GetEnemyFriendlyName(enemy); Logger.Info("Found enemy type [" + enemyFriendlyName + "] (aka. " + enemy.FullName + ")"); string text = default(string); string text2 = (PluginUtils.TryGetPluginId(enemy.Assembly, ref text) ? ("Internal: " + enemy.FullName + "\nModded Enemy from " + text + "\n\n") : ((!(enemy.Assembly == typeof(EnemyAI).Assembly)) ? ("Internal: " + enemy.FullName + "\nUnknown Enemy in " + enemy.Assembly.FullName + "\n\n") : ("Internal: " + enemy.FullName + "\nVanilla Enemy\n\n"))); ConfigEntry<EnemyExpType> expType = file.Bind<EnemyExpType>(enemyFriendlyName, enemyFriendlyName + " Mode", GetDefaultEnemyMode(enemy), text2 + "Exp distribution from killing " + enemyFriendlyName + ".\n\nDisabled = Does not award exp.\nAoE = Awards exp within a range.\nAttacker = Awards exp to the attacker."); ConfigEntry<int> range = file.Bind<int>(enemyFriendlyName, enemyFriendlyName + " Range", GetDefaultEnemyExpRange(enemy), text2 + "Exp distribution range in units, only used if mode is [AoE]"); ConfigEntry<int> baseExp = file.Bind<int>(enemyFriendlyName, enemyFriendlyName + " Base Exp", GetDefaultEnemyBaseExp(enemy), text2 + "The base exp that " + enemyFriendlyName + " awards when killed."); EnemyBindings[enemy] = new BoundEnemy(expType, range, baseExp); } internal static string GetEnemyFriendlyName(Type type) { string fullName = type.FullName; if (1 == 0) { } string result = fullName switch { "BaboonBirdAI" => "Baboon Hawk", "BushWolfEnemy" => "Kidnapper Fox", "ButlerBeesEnemyAI" => "Butler Bees", "ButlerEnemyAI" => "Butler", "CaveDwellerAI" => "Maneater", "ClaySurgeonAI" => "Barber", "DocileLocustBeesAI" => "Roaming Locust", "DoublewingAI" => "Manticoil", "FlowerSnakeEnemy" => "Tulip Snake", "JesterAI" => "Jester", "LassoManAI" => "Lasso (Unused)", "MaskedPlayerEnemy" => "Masked", "NutcrackerEnemyAI" => "Nutcracker", "PufferAI" => "Puffer", "RadMechAI" => "Old Bird", "SandSpiderAI" => "Spider", "SandWormAI" => "Earth Leviathan", "BlobAI" => "Hygrodere", "CentipedeAI" => "Snare Flea", "CrawlerAI" => "Thumper", "RedLocustBees" => "Circuit Bee", "DressGirlAI" => "Ghost Girl", "FlowermanAI" => "Bracken", "ForestGiantAI" => "Forest Keeper", "HoarderBugAI" => "Hoarding Bug", "MouthDogAI" => "Eyeless Dog", "SpringManAI" => "Coil-Head", "TestEnemy" => "Test (Unused)", "Kittenji.HerobrineMod.HerobrineAI" => "Herobrine", "LethalCompanyVileVendingMachine.VileVendingMachineServer" => "Vile Vending Machine", "BaldiEnemy.BaldiEnemy" => "Baldi", "LethalCompanyHarpGhost.HarpGhost.HarpGhostAIServer" => "Harp Ghost", "LethalCompanyHarpGhost.EnforcerGhost.EnforcerGhostAIServer" => "Enforcer Ghost", "LethalCompanyHarpGhost.BagpipesGhost.BagpipesGhostAIServer" => "Bagpipes Ghost", "ScarletMansion.KnightGhostVariant" => "Knight (Ghost)", "ScarletMansion.KnightVariant" => "Knight", "ScarletMansion.GamePatch.Enemies.KnightV2Variant" => "Knight (v2)", "ScarletMansion.GamePatch.Enemies.MaidVariant" => "Sakuya (Maid)", "ImmortalSnail.SnailAI" => "Immortal Snail", "HarbingerBehaviour.AICode.HarbingerAI" => "Harbinger", "ShyGuy.AI.ShyGuyAI" => "Shy Guy", "DontTouchMe.DTMEntityAI" => "Dont Touch Me", "Moonswept.CleanerAI" => "Cleaner", "Moonswept.MobileTurretAI" => "Mobile Turret", "LCOffice.Patches.ShrimpEnemyAI" => "Shrimp (Enemy)", "LCOffice.Patches.ShrimpAI" => "Shrimp", "SmallfryEnemy.SmallfryEnemy" => "Smallfry", "LCPeeper.PeeperAI" => "Peeper", "Menstalker_ybdkSKB.Menstalker_ybdkSKB" => "Menstalker", "Locker.MonoBehaviours.LockerAI" => "Locker", "LethalThings.RoombaAI" => "Roomba", "LethalThings.MonoBehaviours.FishFriend" => "Fish Friend", "LethalThings.MonoBehaviours.Maggie" => "Maggie", "LethalThings.MonoBehaviours.RobotAI" => "Robot", "NightmareFoxyLC.FoxyAi" => "Nightmare Foxy", "NightmareFreddy.NightmareFreddy.NightmareFreddyAi" => "Nightmare Freddy", "NightmareFreddy.Freddles.FreddlesAi" => "Freddles", "GiantSpecimens.Enemy.DriftwoodGiantAI" => "Driftwood Giant", "GiantSpecimens.Enemy.PinkGiantAI" => "Pink Giant", "GiantSpecimens.Enemy.StellarSovereignAI" => "Stellar Sovereign", _ => type.Name, }; if (1 == 0) { } return result; } internal static int GetDefaultEnemyBaseExp(Type type) { string fullName = type.FullName; if (1 == 0) { } int result = fullName switch { "BaboonBirdAI" => 30, "BushWolfEnemy" => 75, "ButlerEnemyAI" => 75, "CaveDwellerAI" => 250, "DoublewingAI" => 20, "FlowerSnakeEnemy" => 10, "MaskedPlayerEnemy" => 40, "NutcrackerEnemyAI" => 80, "SandSpiderAI" => 60, "CentipedeAI" => 30, "CrawlerAI" => 75, "FlowermanAI" => 80, "ForestGiantAI" => 200, "HoarderBugAI" => 30, "MouthDogAI" => 120, "LethalCompanyHarpGhost.HarpGhost.HarpGhostAIServer" => 60, "LethalCompanyHarpGhost.EnforcerGhost.EnforcerGhostAIServer" => 175, "LethalCompanyHarpGhost.BagpipesGhost.BagpipesGhostAIServer" => 100, "SmallfryEnemy.SmallfryEnemy" => 30, "LCPeeper.PeeperAI" => 10, "LethalThings.RoombaAI" => 50, "NightmareFreddy.Freddles.FreddlesAi" => 15, _ => 0, }; if (1 == 0) { } return result; } internal static int GetDefaultEnemyExpRange(Type type) { string fullName = type.FullName; if (1 == 0) { } int result = fullName switch { "ForestGiantAI" => 20, "LCPeeper.PeeperAI" => 1, "LethalThings.RoombaAI" => 15, "NightmareFreddy.Freddles.FreddlesAi" => 15, "SmallfryEnemy.SmallfryEnemy" => 5, _ => (GetDefaultEnemyMode(type) == EnemyExpType.AoE) ? 10 : 0, }; if (1 == 0) { } return result; } internal static EnemyExpType GetDefaultEnemyMode(Type type) { string fullName = type.FullName; if (1 == 0) { } EnemyExpType result = fullName switch { "BaboonBirdAI" => EnemyExpType.AoE, "BushWolfEnemy" => EnemyExpType.AoE, "ButlerEnemyAI" => EnemyExpType.AoE, "CaveDwellerAI" => EnemyExpType.AoE, "DoublewingAI" => EnemyExpType.Attacker, "FlowerSnakeEnemy" => EnemyExpType.Attacker, "MaskedPlayerEnemy" => EnemyExpType.AoE, "NutcrackerEnemyAI" => EnemyExpType.AoE, "SandSpiderAI" => EnemyExpType.AoE, "CentipedeAI" => EnemyExpType.AoE, "CrawlerAI" => EnemyExpType.AoE, "FlowermanAI" => EnemyExpType.AoE, "ForestGiantAI" => EnemyExpType.AoE, "HoarderBugAI" => EnemyExpType.AoE, "MouthDogAI" => EnemyExpType.AoE, "LethalCompanyHarpGhost.HarpGhost.HarpGhostAIServer" => EnemyExpType.AoE, "LethalCompanyHarpGhost.EnforcerGhost.EnforcerGhostAIServer" => EnemyExpType.AoE, "LethalCompanyHarpGhost.BagpipesGhost.BagpipesGhostAIServer" => EnemyExpType.AoE, "SmallfryEnemy.SmallfryEnemy" => EnemyExpType.AoE, "LCPeeper.PeeperAI" => EnemyExpType.AoE, "LethalThings.RoombaAI" => EnemyExpType.AoE, "NightmareFreddy.Freddles.FreddlesAi" => EnemyExpType.AoE, _ => EnemyExpType.Disabled, }; if (1 == 0) { } return result; } } internal static class Logger { private static ILogger s_logger = (ILogger)(object)Unity.Shared; public static ILogger Source { get { return s_logger; } [param: AllowNull] set { s_logger = (ILogger)(((object)value) ?? ((object)Unity.Shared)); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Debug(object message) { Source.Debug(message); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Info(object message) { Source.Info(message); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Warning(object message) { Source.Warning(message); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Error(object message) { Source.Error(message); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Fatal(object message) { Source.Fatal(message); } } [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInPlugin("CookieProgression", "CookieProgression", "0.1.2")] public sealed class Plugin : BaseUnityPlugin, ICookieDependency { private static AssetBundle? s_menuBundle; public static AssetBundle MenuBundle => s_menuBundle ?? throw new InvalidOperationException("Use before initialize."); bool ICookieDependency.TrackOtherClients => false; private void Awake() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_004b: Unknown result type (might be due to invalid IL or missing references) Logger.Source = (ILogger)new BepInLoggerSource(((BaseUnityPlugin)this).Logger); using Stream stream = typeof(Plugin).Assembly.GetManifestResourceStream("CookieProgression.res.skillmenu") ?? throw new InvalidOperationException("Embedded resource returned null."); s_menuBundle = AssetBundle.LoadFromStream(stream); new Harmony("CookieProgression").PatchAll(typeof(Plugin).Assembly); PluginUtils.Register((ICookieDependency)(object)this); Config.Setup(((BaseUnityPlugin)this).Config); SkillManager.Bootstrap(); for (int i = 1; i <= 20; i++) { int experience = ExperienceGroups.Lethal.GetExperience(i); int level = ExperienceGroups.Lethal.GetLevel(experience); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Lvl. {level} = {experience}"); } ((BaseUnityPlugin)this).Logger.LogInfo((object)"CookieProgression v0.1.2 loaded."); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Icon, Ideas and Game Balance by Kaede"); GameClient.OnShutdown += delegate { SkillMenu.OnDestroy(); }; } void ICookieDependency.OnPlayerTracked(AbstractPlayer player) { ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Started tracking {player}"); player.Attach<SkillManager>(new SkillManager(player)); } } internal static class PluginInfo { public const string Guid = "CookieProgression"; public const string Name = "CookieProgression"; public const string Version = "0.1.2"; } } namespace CookieProgression.UI { [HarmonyPatch] [HarmonyWrapSafe] public sealed class SkillMenu { internal static bool IsMenuOpen; internal static SkillMenu? Instance; private readonly GameObject _mainPanel; private readonly GameObject _infoPanel; private readonly List<GameObject> _skillButtons = new List<GameObject>(); public SkillManager Manager { get; } internal static void OnInitialize(SkillManager client) { if (IsMenuOpen) { try { Instance?.OnBackButton(); } catch { } IsMenuOpen = false; } Instance = new SkillMenu(client); } internal static void OnDestroy() { if (Instance != null && IsMenuOpen) { try { Instance.OnBackButton(); } catch { } IsMenuOpen = false; } Instance = null; } public void OpenSkillMenu() { if (!Object.op_Implicit((Object)(object)_mainPanel)) { OnDestroy(); return; } IsMenuOpen = true; _mainPanel.SetActive(true); } private SkillMenu(SkillManager manager) { //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Expected O, but got Unknown //IL_00c7: Expected O, but got Unknown //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Expected O, but got Unknown Guard.NotNull<SkillManager>(manager, "manager"); Guard.IsTrue(manager.Player.IsClient, (string)null, "manager.Player.IsClient"); Manager = manager; _mainPanel = Object.Instantiate<GameObject>(Plugin.MenuBundle.LoadAsset<GameObject>("SkillMenu")); ((Object)_mainPanel).name = "SkillMenu"; _mainPanel.SetActive(false); _infoPanel = ((Component)_mainPanel.transform.GetChild(1)).gameObject; _infoPanel.SetActive(false); GameObject gameObject = ((Component)_mainPanel.transform.GetChild(4)).gameObject; Button component = gameObject.GetComponent<Button>(); ButtonClickedEvent val = new ButtonClickedEvent(); ButtonClickedEvent val2 = val; component.onClick = val; ButtonClickedEvent val3 = val2; ((UnityEvent)val3).AddListener(new UnityAction(OnBackButton)); foreach (SkillDefinition definition in manager.Definitions) { Logger.Info($"Creating button for {definition.Type}."); GameObject val4 = SetupUpgradeButton(definition); if (val4 != null) { _skillButtons.Add(val4); } } } [HarmonyPostfix] [HarmonyPatch(typeof(QuickMenuManager), "Update")] private static void OnUpdate() { if (Instance != null && Object.op_Implicit((Object)(object)Instance._mainPanel)) { if (!IsMenuOpen) { Instance._mainPanel.SetActive(false); return; } Instance.UpdateUnspec(); Instance._mainPanel.SetActive(true); GameObject val = GameObject.Find("Systems/UI/Canvas/QuickMenu/MainButtons"); val.SetActive(false); GameObject val2 = GameObject.Find("Systems/UI/Canvas/QuickMenu/PlayerList"); val2.SetActive(false); GameObject gameObject = ((Component)Instance._mainPanel.transform.GetChild(2)).gameObject; gameObject = ((Component)gameObject.transform.GetChild(1)).gameObject; TextMeshProUGUI component = gameObject.GetComponent<TextMeshProUGUI>(); ((TMP_Text)component).SetText(Instance.Manager.UnusedSkillPoints.ToString(), true); } } [HarmonyPostfix] [HarmonyPatch(typeof(QuickMenuManager), "CloseQuickMenu")] private static void OnClose() { IsMenuOpen = false; } internal void OnBackButton() { IsMenuOpen = false; _mainPanel.SetActive(false); GameObject val = GameObject.Find("Systems/UI/Canvas/QuickMenu/MainButtons"); val.SetActive(true); GameObject val2 = GameObject.Find("Systems/UI/Canvas/QuickMenu/PlayerList"); val2.SetActive(true); } private void UpdateUnspec() { GameObject gameObject = ((Component)_infoPanel.transform.GetChild(6)).gameObject; GameObject gameObject2 = ((Component)_infoPanel.transform.GetChild(7)).gameObject; GameObject gameObject3 = ((Component)_infoPanel.transform.GetChild(8)).gameObject; GameObject gameObject4 = ((Component)_infoPanel.transform.GetChild(9)).gameObject; gameObject4.SetActive(false); StartOfRound instance = StartOfRound.Instance; if (instance != null && instance.inShipPhase) { EndOfGameStats gameStats = instance.gameStats; if (gameStats != null && gameStats.daysSpent == 0) { gameObject4.SetActive(false); gameObject.SetActive(true); gameObject2.SetActive(true); gameObject3.SetActive(true); return; } } gameObject4.SetActive(true); ((TMP_Text)gameObject4.GetComponent<TextMeshProUGUI>()).SetText("Unspec on first day in orbit.", true); gameObject.SetActive(false); gameObject2.SetActive(false); gameObject3.SetActive(false); } private GameObject? SetupUpgradeButton(SkillDefinition definition) { //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Expected O, but got Unknown //IL_00f4: Expected O, but got Unknown //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Expected O, but got Unknown GameObject gameObject = ((Component)_mainPanel.transform.GetChild(0)).gameObject; if (!Object.op_Implicit((Object)(object)gameObject)) { Logger.Error("Couldn't find template button!"); return null; } GameObject val = Object.Instantiate<GameObject>(gameObject); ((Object)val).name = definition.Type.ToString(); GameObject gameObject2 = ((Component)_mainPanel.transform.GetChild(3)).gameObject; GameObject gameObject3 = ((Component)gameObject2.transform.GetChild(1)).gameObject; val.transform.SetParent(gameObject3.transform, false); GameObject gameObject4 = ((Component)val.transform.GetChild(0)).gameObject; ((TMP_Text)gameObject4.GetComponent<TextMeshProUGUI>()).SetText(definition.ShortName, true); LoadSkillData(definition, val); val.SetActive(true); Button component = val.GetComponent<Button>(); ButtonClickedEvent val2 = new ButtonClickedEvent(); ButtonClickedEvent val3 = val2; component.onClick = val2; ButtonClickedEvent val4 = val3; SkillType type = definition.Type; ((UnityEvent)val4).AddListener((UnityAction)delegate { UpdateSkillPanel(type); }); return val; } public void LoadAllSkillData() { foreach (SkillDefinition definition in Manager.Definitions) { GameObject val = _skillButtons.Find((GameObject x) => string.Equals(((Object)x).name, definition.Type.ToString(), StringComparison.Ordinal)); if (val != null) { LoadSkillData(definition, val); } } } public void LoadSkillData(SkillDefinition definition) { foreach (GameObject skillButton in _skillButtons) { if (string.Equals(((Object)skillButton).name, definition.Type.ToString(), StringComparison.Ordinal)) { LoadSkillData(definition, skillButton); } } } private void LoadSkillData(SkillDefinition definition, GameObject button) { SkillType type = definition.Type; string text = Manager.GetAllocated(definition.Type).ToString(); GameObject gameObject = ((Component)button.transform.GetChild(1)).gameObject; ((TMP_Text)gameObject.GetComponent<TextMeshProUGUI>()).SetText(text, true); GameObject gameObject2 = ((Component)button.transform.GetChild(2)).gameObject; ((TMP_Text)gameObject2.GetComponent<TextMeshProUGUI>()).SetText("(" + type.Format(Manager.GetMultiplier(type)) + " " + definition.Name + ")", true); ((TMP_Text)button.GetComponentInChildren<TextMeshProUGUI>()).SetText(definition.ShortName + ":", true); } private void UpdateSkillPanel(SkillType type) { //IL_01ec: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Expected O, but got Unknown //IL_01f9: Expected O, but got Unknown //IL_0207: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Expected O, but got Unknown //IL_0219: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_0221: Expected O, but got Unknown //IL_0226: Expected O, but got Unknown //IL_0234: Unknown result type (might be due to invalid IL or missing references) //IL_023e: Expected O, but got Unknown //IL_0246: Unknown result type (might be due to invalid IL or missing references) //IL_024b: Unknown result type (might be due to invalid IL or missing references) //IL_024e: Expected O, but got Unknown //IL_0253: Expected O, but got Unknown //IL_0261: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Expected O, but got Unknown //IL_0273: Unknown result type (might be due to invalid IL or missing references) //IL_0278: Unknown result type (might be due to invalid IL or missing references) //IL_027b: Expected O, but got Unknown //IL_0280: Expected O, but got Unknown //IL_028e: Unknown result type (might be due to invalid IL or missing references) //IL_0298: Expected O, but got Unknown //IL_02a0: Unknown result type (might be due to invalid IL or missing references) //IL_02a5: Unknown result type (might be due to invalid IL or missing references) //IL_02a8: Expected O, but got Unknown //IL_02ad: Expected O, but got Unknown //IL_02bb: Unknown result type (might be due to invalid IL or missing references) //IL_02c5: Expected O, but got Unknown //IL_02cd: Unknown result type (might be due to invalid IL or missing references) //IL_02d2: Unknown result type (might be due to invalid IL or missing references) //IL_02d5: Expected O, but got Unknown //IL_02da: Expected O, but got Unknown //IL_02e8: Unknown result type (might be due to invalid IL or missing references) //IL_02f2: Expected O, but got Unknown if (!Manager.TryGetDefinition(type, out SkillDefinition definition)) { Logger.Warning($"Skill {type} doesn't have a definiton and is unable to populate info panel with data. (CLIENT IS VERY OUT OF SYNC)"); return; } if (!_infoPanel.activeSelf) { _infoPanel.SetActive(true); } TextMeshProUGUI component = ((Component)_infoPanel.transform.GetChild(0)).gameObject.GetComponent<TextMeshProUGUI>(); TextMeshProUGUI component2 = ((Component)_infoPanel.transform.GetChild(1)).gameObject.GetComponent<TextMeshProUGUI>(); TextMeshProUGUI component3 = ((Component)_infoPanel.transform.GetChild(2)).gameObject.GetComponent<TextMeshProUGUI>(); ((TMP_Text)component).SetText(definition.Name, true); if (definition.MaxLevel == 99999) { ((TMP_Text)component2).SetText(Manager.GetAllocated(type).ToString(), true); } else { ((TMP_Text)component2).SetText($"{Manager.GetAllocated(type)} / {definition.MaxLevel}", true); } ((TMP_Text)component3).SetText(definition.Description, true); GameObject gameObject = ((Component)_infoPanel.transform.GetChild(3)).gameObject; GameObject gameObject2 = ((Component)_infoPanel.transform.GetChild(4)).gameObject; GameObject gameObject3 = ((Component)_infoPanel.transform.GetChild(5)).gameObject; GameObject gameObject4 = ((Component)_infoPanel.transform.GetChild(6)).gameObject; GameObject gameObject5 = ((Component)_infoPanel.transform.GetChild(7)).gameObject; GameObject gameObject6 = ((Component)_infoPanel.transform.GetChild(8)).gameObject; Button component4 = gameObject.GetComponent<Button>(); ButtonClickedEvent val = new ButtonClickedEvent(); ButtonClickedEvent val2 = val; component4.onClick = val; ButtonClickedEvent val3 = val2; ((UnityEvent)val3).AddListener((UnityAction)delegate { ChangeSkillPoints(type, 5); }); Button component5 = gameObject2.GetComponent<Button>(); ButtonClickedEvent val4 = new ButtonClickedEvent(); val2 = val4; component5.onClick = val4; ButtonClickedEvent val5 = val2; ((UnityEvent)val5).AddListener((UnityAction)delegate { ChangeSkillPoints(type, 2); }); Button component6 = gameObject3.GetComponent<Button>(); ButtonClickedEvent val6 = new ButtonClickedEvent(); val2 = val6; component6.onClick = val6; ButtonClickedEvent val7 = val2; ((UnityEvent)val7).AddListener((UnityAction)delegate { ChangeSkillPoints(type, 1); }); Button component7 = gameObject4.GetComponent<Button>(); ButtonClickedEvent val8 = new ButtonClickedEvent(); val2 = val8; component7.onClick = val8; ButtonClickedEvent val9 = val2; ((UnityEvent)val9).AddListener((UnityAction)delegate { ChangeSkillPoints(type, -5); }); Button component8 = gameObject5.GetComponent<Button>(); ButtonClickedEvent val10 = new ButtonClickedEvent(); val2 = val10; component8.onClick = val10; ButtonClickedEvent val11 = val2; ((UnityEvent)val11).AddListener((UnityAction)delegate { ChangeSkillPoints(type, -2); }); Button component9 = gameObject6.GetComponent<Button>(); ButtonClickedEvent val12 = new ButtonClickedEvent(); val2 = val12; component9.onClick = val12; ButtonClickedEvent val13 = val2; ((UnityEvent)val13).AddListener((UnityAction)delegate { ChangeSkillPoints(type, -1); }); } private void ChangeSkillPoints(SkillType type, int amount) { if (!Manager.TryGetDefinition(type, out SkillDefinition definition)) { Logger.Warning($"Skill {type} doesn't have a definiton. (CLIENT IS VERY OUT OF SYNC)"); return; } if (IngamePlayerSettings.Instance != null) { IngamePlayerSettings instance = IngamePlayerSettings.Instance; InputAction val = instance.playerInput.actions.FindAction("Sprint", false); if (val != null && val.IsPressed()) { amount *= 10; } InputAction val2 = instance.playerInput.actions.FindAction("Crouch", false); if (val2 != null && val2.IsPressed()) { amount = ((amount < 1) ? (-Manager.GetAllocated(type)) : Manager.UnusedSkillPoints); } } Manager.SetAlloacted(type, Math.Max(Manager.GetAllocated(type) + amount, 0)); UpdateSkillPanel(type); foreach (GameObject skillButton in _skillButtons) { if (string.Equals(((Object)skillButton).name, definition.Type.ToString(), StringComparison.Ordinal)) { LoadSkillData(definition, skillButton); } } } } } namespace CookieProgression.Skills { public sealed class SkillDefinition { public static readonly int EncodingSize = FastBufferWriter.GetWriteSize<SkillType>() + FastBufferWriter.GetWriteSize<int>() + FastBufferWriter.GetWriteSize<int>(); public SkillType Type { get; } public int MaxLevel { get; } public int Multiplier { get; } public bool IsNegative { get; } public bool IsTeamShared { get; } public string Name { get; } public string ShortName { get; } public string Description { get; } public SkillDefinition(SkillType type, int maxLevel, int multiplier) { Guard.MustBeGreaterThan<int>(maxLevel, 0, "maxLevel"); Guard.MustBeGreaterThan<int>(multiplier, 0, "multiplier"); Type = type; MaxLevel = maxLevel; Multiplier = multiplier; IsNegative = type.IsNegative(); IsTeamShared = type.IsTeamShared(); Name = type.GetName(); ShortName = type.GetShortName(); Description = type.GetDescription(); if (IsNegative && IsTeamShared) { throw new InvalidOperationException($"SkillType {type} is both negative and team shared."); } } public double GetFinalMultiplier(int level) { return (double)Multiplier / 10000.0 * (double)level; } public ulong GetRawMultiplier(int level) { return (ulong)(Multiplier * (uint)level); } public static SkillDefinition Decode(FastBufferReader reader) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) SkillType type = default(SkillType); ((FastBufferReader)(ref reader)).ReadValueSafe<SkillType>(ref type, default(ForEnums)); int maxLevel = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref maxLevel, default(ForPrimitives)); int multiplier = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref multiplier, default(ForPrimitives)); return new SkillDefinition(type, maxLevel, multiplier); } public void Encode(FastBufferWriter writer) { //IL_000e: 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_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0042: 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) SkillType type = Type; ((FastBufferWriter)(ref writer)).WriteValueSafe<SkillType>(ref type, default(ForEnums)); int maxLevel = MaxLevel; ((FastBufferWriter)(ref writer)).WriteValueSafe<int>(ref maxLevel, default(ForPrimitives)); maxLevel = Multiplier; ((FastBufferWriter)(ref writer)).WriteValueSafe<int>(ref maxLevel, default(ForPrimitives)); } } public sealed class SkillManager : IPlayerComponent { private readonly Dictionary<SkillType, SkillDefinition> _definitions = new Dictionary<SkillType, SkillDefinition>(); private readonly Dictionary<SkillType, int> _previousAllocations = new Dictionary<SkillType, int>(); private readonly Dictionary<SkillType, int> _allocations = new Dictionary<SkillType, int>(); private readonly Dictionary<SkillType, int> _loaded = new Dictionary<SkillType, int>(); private static readonly Dictionary<SkillType, ulong> TeamValues; public AbstractPlayer Player { get; } public IExperienceGroup ExpGroup { get; } = ExperienceGroups.Lethal; public int Exp { get; private set; } public int Level => ExpGroup.GetLevel(Exp); public int UsedExp => ExpGroup.GetExperience(Level); public int RequiredExp => ExpGroup.GetExperience(Level + 1); public bool HasMoreLevels => NeededExp != 0; public int NeededExp => RequiredExp - UsedExp; public int UnusedExp => Exp - UsedExp; public int SkillPoints { get { int level = Level; int num = level / 5; int num2 = level / 10; int num3 = level / 100 * 2; return 5 + (level - 1 + num + num2 + num3) * 2; } } public int Allocations { get; private set; } public int UnusedSkillPoints => Math.Max(SkillPoints - Allocations, 0); public IEnumerable<SkillDefinition> Definitions => _definitions.Values; public string ComponentId => "SkillManager"; internal static void Bootstrap() { } static SkillManager() { TeamValues = new Dictionary<SkillType, ulong>(); ClientNetworking.Register<TeamSkillS2C>(TeamSkillS2C.Type, (Action<ClientPlayer, TeamSkillS2C>)delegate(ClientPlayer player, TeamSkillS2C payload) { SkillManager skillManager5 = default(SkillManager); if (((AbstractPlayer)player).TryGet<SkillManager>(ref skillManager5)) { TeamValues[payload.SkillType] = Math.Max(payload.Multiplier, 0uL); Logger.Info($"[Server says team] {payload.SkillType} totals {payload.Multiplier}"); if (skillManager5._definitions.TryGetValue(payload.SkillType, out SkillDefinition value)) { SkillMenu.Instance?.LoadSkillData(value); } } }); ClientNetworking.Register<SetSkillS2C>(SetSkillS2C.Type, (Action<ClientPlayer, SetSkillS2C>)delegate(ClientPlayer player, SetSkillS2C payload) { SkillManager skillManager4 = default(SkillManager); if (((AbstractPlayer)player).TryGet<SkillManager>(ref skillManager4)) { skillManager4._allocations[payload.SkillType] = payload.Points; Logger.Info($"[Server says] {payload.SkillType} is {payload.Points}"); skillManager4.UpdateAllocations(updating: false); } }); ClientNetworking.Register<DefineSkillsS2C>(DefineSkillsS2C.Type, (Action<ClientPlayer, DefineSkillsS2C>)delegate(ClientPlayer player, DefineSkillsS2C payload) { SkillManager skillManager3 = default(SkillManager); if (((AbstractPlayer)player).TryGet<SkillManager>(ref skillManager3)) { SkillMenu.OnDestroy(); skillManager3._previousAllocations.Clear(); skillManager3._definitions.Clear(); if (!((AbstractClientPlayer)player).IsLocal) { TeamValues.Clear(); } foreach (SkillDefinition definition in payload.Definitions) { Logger.Info($"[Server defines] {definition.Type}"); skillManager3._definitions[definition.Type] = definition; } skillManager3.UpdateAllocations(updating: false); SkillMenu.OnInitialize(skillManager3); } }); ClientNetworking.Register<SetExpS2C>(SetExpS2C.Type, (Action<ClientPlayer, SetExpS2C>)delegate(ClientPlayer player, SetExpS2C payload) { SkillManager skillManager2 = default(SkillManager); if (((AbstractPlayer)player).TryGet<SkillManager>(ref skillManager2)) { int level = skillManager2.Level; skillManager2.Exp = Math.Max(payload.Exp, 0); if (level < skillManager2.Level) { MenuPatches.ShowLevelPopup(); } } }); ServerNetworking.Register<AllocateSkillC2S>(AllocateSkillC2S.Type, (Action<ServerPlayer, AllocateSkillC2S>)delegate(ServerPlayer player, AllocateSkillC2S payload) { SkillManager skillManager = default(SkillManager); if (((AbstractPlayer)player).TryGet<SkillManager>(ref skillManager)) { Logger.Info($"[Client asks] {payload.SkillType} is {payload.Points}"); skillManager.SetAlloacted(payload.SkillType, payload.Points); } }); } internal SkillManager(AbstractPlayer player) { Guard.NotNull<AbstractPlayer>(player, "player"); Player = player; } public bool TryGetDefinition(SkillType type, [NotNullWhen(true)] out SkillDefinition? definition) { return _definitions.TryGetValue(type, out definition); } public void UpdateTeamValue(SkillType type) { AbstractPlayer player = Player; ServerPlayer val = (ServerPlayer)(object)((player is ServerPlayer) ? player : null); if (val == null || !_definitions.TryGetValue(type, out SkillDefinition value)) { return; } ulong num = 0uL; List<ServerPlayer> list = new List<ServerPlayer>(); SkillManager skillManager = default(SkillManager); foreach (ServerPlayer player2 in val.Server.PlayerManager.Players) { if (!((AbstractPlayer)player2).TryGet<SkillManager>(ref skillManager)) { if (player2 != val) { continue; } skillManager = this; } list.Add(player2); num += skillManager.GetRawMultiplier(type); } TeamValues[type] = Math.Min(num, (ulong)(value.MaxLevel * value.Multiplier)); ServerNetworking.Send<TeamSkillS2C>((IEnumerable<ServerPlayer>)list, new TeamSkillS2C(type, num)); } public void UpdateAllocations(bool updating) { int num = 0; foreach (KeyValuePair<SkillType, SkillDefinition> definition in _definitions) { definition.Deconstruct(out var key, out var value); SkillType skillType = key; SkillDefinition skillDefinition = value; int valueOrDefault = _previousAllocations.GetValueOrDefault(skillType, -1); int valueOrDefault2 = _allocations.GetValueOrDefault(skillType, 0); if (valueOrDefault != valueOrDefault2) { _previousAllocations[skillType] = valueOrDefault2; if (updating) { AbstractPlayer player = Player; ServerPlayer val = (ServerPlayer)(object)((player is ServerPlayer) ? player : null); if (val != null) { ServerNetworking.Send<SetSkillS2C>(val, new SetSkillS2C(skillType, valueOrDefault2)); if (skillDefinition.IsTeamShared) { UpdateTeamValue(skillType); } } else { ClientNetworking.Send<AllocateSkillC2S>(new AllocateSkillC2S(skillType, valueOrDefault2)); } } } num = ((!skillDefinition.IsNegative) ? (num + valueOrDefault2) : (num - valueOrDefault2)); } if (Player.IsClient) { SkillMenu.Instance?.LoadAllSkillData(); } Allocations = num; } public void SetAlloacted(SkillType type, int points) { Guard.MustBeGreaterThanOrEqualTo<int>(points, 0, "points"); if (_definitions.TryGetValue(type, out SkillDefinition value)) { points = Math.Min(points, value.MaxLevel); int valueOrDefault = _allocations.GetValueOrDefault(type, 0); if (value.IsNegative) { int val = valueOrDefault - UnusedSkillPoints; valueOrDefault = Math.Max(points, val); } else { int val2 = valueOrDefault + UnusedSkillPoints; valueOrDefault = Math.Min(points, val2); } _allocations[type] = valueOrDefault; UpdateAllocations(updating: true); } } public void AddExp(int experience) { AbstractPlayer player = Player; ServerPlayer val = (ServerPlayer)(object)((player is ServerPlayer) ? player : null); if (val != null) { Logger.Info($"{Player} +{experience} Exp"); Exp += experience; ServerNetworking.Send<SetExpS2C>(val, new SetExpS2C(Exp)); } } public void SetExp(int experience) { AbstractPlayer player = Player; ServerPlayer val = (ServerPlayer)(object)((player is ServerPlayer) ? player : null); if (val != null) { Logger.Info($"{Player} -> {experience} Exp"); Exp = experience; ServerNetworking.Send<SetExpS2C>(val, new SetExpS2C(Exp)); } } public int GetAllocated(SkillType type) { return _allocations.GetValueOrDefault(type, 0); } public static double GetTeamMultiplier(SkillType type) { return (double)TeamValues.GetValueOrDefault(type) / 10000.0; } public double GetMultiplier(SkillType type) { if (!_definitions.TryGetValue(type, out SkillDefinition value)) { return 0.0; } if (value.IsTeamShared) { return (double)TeamValues.GetValueOrDefault(type) / 10000.0; } int valueOrDefault = _allocations.GetValueOrDefault(type, 0); return value.GetFinalMultiplier(valueOrDefault); } internal ulong GetRawMultiplier(SkillType type) { if (!_definitions.TryGetValue(type, out SkillDefinition value)) { return 0uL; } int valueOrDefault = _allocations.GetValueOrDefault(type, 0); return value.GetRawMultiplier(valueOrDefault); } internal void SetDefinitions(IEnumerable<(SkillType type, int MaxLevel, int Multiplier)> definitions) { AbstractPlayer player = Player; ServerPlayer val = (ServerPlayer)(object)((player is ServerPlayer) ? player : null); if (val == null) { return; } _previousAllocations.Clear(); _definitions.Clear(); TeamValues.Clear(); foreach (var (skillType, maxLevel, multiplier) in definitions) { _definitions.Add(skillType, new SkillDefinition(skillType, maxLevel, multiplier)); } ServerNetworking.Send<DefineSkillsS2C>(val, new DefineSkillsS2C(Definitions)); UpdateAllocations(updating: true); } public bool ShouldPersist(AbstractPlayer player) { return !player.IsClient; } public bool OnPlayerAttach(AbstractPlayer player) { if (Player != player || player is OtherClientPlayer) { return false; } if (player.IsClient) { SkillMenu.OnInitialize(this); } else { SetExp(Exp); foreach (var (key, value) in _loaded) { _allocations[key] = value; } Config.SetSkills(this); } return true; } public bool OnPlayerDetach(AbstractPlayer player, bool forced) { if (player.IsClient) { TeamValues.Clear(); SkillMenu.OnDestroy(); } else { ServerPlayer val = (ServerPlayer)(object)((player is ServerPlayer) ? player : null); if (val != null && !val.Server.IsStopping) { _allocations.Clear(); foreach (SkillDefinition value in _definitions.Values) { UpdateTeamValue(value.Type); } } } return true; } public void OnPlayerSave(AbstractPlayer player, string path) { Guard.NotNullOrWhiteSpace(path, "path"); Guard.IsFalse(player.IsClient, (string)null, "player.IsClient"); string text = path + "/save.es3"; ES3.Save<int>("exp", Exp, text); SkillType[] array = (SkillType[])Enum.GetValues(typeof(SkillType)); foreach (SkillType skillType in array) { if (_definitions.ContainsKey(skillType)) { ES3.Save<int>($"skill.{skillType}", _allocations.GetValueOrDefault(skillType), text); } else { ES3.Save<int>($"skill.{skillType}", 0, text); } } } public void OnPlayerLoad(AbstractPlayer player, string path) { Guard.NotNullOrWhiteSpace(path, "path"); Guard.IsFalse(player.IsClient, (string)null, "player.IsClient"); string text = path + "/save.es3"; if (ES3.FileExists(text)) { Exp = ES3.Load<int>("exp", text, 0); SkillType[] array = (SkillType[])Enum.GetValues(typeof(SkillType)); foreach (SkillType skillType in array) { _loaded[skillType] = ES3.Load<int>($"skill.{skillType}", text, 0); } } } } public enum SkillType { MaxHealth, HealthRegen, Stamina, StaminaRegen, Strength, JumpHeight, SprintSpeed, SwimStamina, SwimSpeed, Oxygen, Battery, Slots, Exp, MonsterExp, SellExp, SellValue, ShipDoor, OvertimeBonus, Lockpick, Scrap, Neg } public static class SkillTypeExtensions { public static bool IsNegative(this SkillType type) { if (1 == 0) { } bool result = type == SkillType.Neg; if (1 == 0) { } return result; } public static bool IsTeamShared(this SkillType type) { if (1 == 0) { } bool result = (uint)(type - 14) <= 5u; if (1 == 0) { } return result; } public static string GetName(this SkillType type) { if (1 == 0) { } string result = type switch { SkillType.MaxHealth => "Max Health", SkillType.HealthRegen => "Health Regen", SkillType.Stamina => "Stamina", SkillType.StaminaRegen => "Stamina Regen", SkillType.Strength => "Strength", SkillType.JumpHeight => "Jump Strength", SkillType.SprintSpeed => "Sprint Speed", SkillType.SwimSpeed => "Swim Speed", SkillType.SwimStamina => "Swim Stamina", SkillType.Oxygen => "Oxygen", SkillType.Battery => "Battery", SkillType.Slots => "Utility Belt", SkillType.Exp => "Exp Bonus", SkillType.MonsterExp => "Monster Exp Bonus", SkillType.SellExp => "Sell Base Exp", SkillType.SellValue => "Sell Value", SkillType.ShipDoor => "Ship Door Hydraulics", SkillType.OvertimeBonus => "Overtime Bonus", SkillType.Lockpick => "Lockpick Engineer", SkillType.Scrap => "Scrap", _ => (!type.IsNegative()) ? "Nothing there" : "Nothing There", }; if (1 == 0) { } return result; } public static string GetShortName(this SkillType type) { if (1 == 0) { } string result = type switch { SkillType.MaxHealth => "MHP", SkillType.HealthRegen => "HPR", SkillType.Stamina => "STA", SkillType.StaminaRegen => "AGI", SkillType.Strength => "STR", SkillType.JumpHeight => "JMP", SkillType.SprintSpeed => "SPD", SkillType.SwimSpeed => "SWM", SkillType.SwimStamina => "WSC", SkillType.Oxygen => "OXY", SkillType.Battery => "BAT", SkillType.Slots => "BLT", SkillType.Exp => "EXP", SkillType.MonsterExp => "MXP", SkillType.SellExp => "SXP", SkillType.SellValue => "VAL", SkillType.ShipDoor => "HYD", SkillType.OvertimeBonus => "BON", SkillType.Lockpick => "TKR", SkillType.Scrap => "SCP", _ => (!type.IsNegative()) ? "???" : "!?!", }; if (1 == 0) { } return result; } public static string GetDescription(this SkillType type) { if (1 == 0) { } string result = type switch { SkillType.MaxHealth => "The countless injuries you obtained from past expeditions steeled your body making you more durable.", SkillType.HealthRegen => "Hours of exposure to the Apparatus mutated your blood cells to regenerate your health faster than before.", SkillType.Stamina => "Hitting that Company Gym™ is finally paying out! Increasing your ability to jump and run more!", SkillType.StaminaRegen => "The Company infused your blood with coffeine making you regen your Stamina faster than before!", SkillType.Strength => "You infuse your blood with pure testosterone to make you carry heavy scrap with ease.", SkillType.JumpHeight => "Releasing your inner bunny spirit animal makes you jump higher.", SkillType.SprintSpeed => "The company empowers you with pure steroids, run, spaceman.", SkillType.SwimSpeed => "Your training for the Mud Puddle swimming competition in the Backyard Olympics made you an excellent swimmer!", SkillType.SwimStamina => "Installing flippers on the Suit makes it less exhausting moving through the water.", SkillType.Oxygen => "The company installed basic, yet useful Oxygen tanks to your suit making you able to stay underwater for longer.", SkillType.Battery => "Playing with the electrical outlet as a kid, has made you find a way to overcharge your batteries at the Charging Station.", SkillType.Slots => "You figured out by combining useful materials on the ship to make a custom utility belt helping you to carry more scrap and items with you!", SkillType.Exp => "Knowledge is Power! You try to learn as much and quickly as possible and thus accelerating your growth!", SkillType.MonsterExp => "Violence is Power! Slay your enemies and get more experience by doing so. Also works on Co-workers!", SkillType.SellExp => "Extensive studying on the Company's boss during sell time makes you all smarter! It could also just be the fear of getting eaten pumping a lot of Adrenaline into your brain...", SkillType.SellValue => "You and your team learn how to trick the Company to give you more Credits than the scrap is worth.", SkillType.ShipDoor => "You and your team's combined engineering on the ship's door increased the strength of the Hydraulics and now stays closed for longer.", SkillType.OvertimeBonus => "By committing fraud you trick the company to give you more money after each completed Quota.", SkillType.Lockpick => "By working on the company provided Lockpicker, you made it faster at locking doors and unlocking doors quicker!", SkillType.Scrap => "The Company Issued scrap prospects to each employee to raise awareness of what is scrap and what is not! Increasing the amount of scrap per moon.", _ => type.IsNegative() ? "This skill is missing a description but it sure does seem angry ònó" : ((!type.IsTeamShared()) ? "This skill is missing a description uwu" : "This skill is missing a description yet yuu still share it despite not knowing what it is uwu"), }; if (1 == 0) { } return result; } public static string Format(this SkillType type, double multiplier) { return type.GetFormat().Format(multiplier); } public static string Format(this SkillFormat format, double multiplier) { if (1 == 0) { } string result = format switch { SkillFormat.Modifier => $"+{multiplier * 100.0:0.##}%", SkillFormat.Mulitply => $"x{multiplier:0.##}", SkillFormat.SubtractSeconds => $"-{multiplier * 100.0:0.##}s", SkillFormat.Value => $"+{multiplier * 100.0:0.##}", _ => multiplier.ToString(), }; if (1 == 0) { } return result; } public static SkillFormat GetFormat(this SkillType type) { if (1 == 0) { } SkillFormat result; switch (type) { case SkillType.Slots: case SkillType.Scrap: result = SkillFormat.Value; break; case SkillType.SellExp: result = SkillFormat.Mulitply; break; default: result = SkillFormat.Modifier; break; } if (1 == 0) { } return result; } public static int GetDefaultMaxLevel(this SkillType type) { if (1 == 0) { } int result = type switch { SkillType.HealthRegen => 100, SkillType.StaminaRegen => 80, SkillType.Strength => 80, SkillType.JumpHeight => 100, SkillType.SprintSpeed => 250, SkillType.SwimSpeed => 200, SkillType.SwimStamina => 50, SkillType.Slots => 30, SkillType.ShipDoor => 200, SkillType.OvertimeBonus => 1000, SkillType.Lockpick => 50, SkillType.Neg => 99999, _ => (!type.IsNegative()) ? 99999 : 100, }; if (1 == 0) { } return result; } public static int GetDefaultMultiplier(this SkillType type) { if (1 == 0) { } int result = type switch { SkillType.MaxHealth => 400, SkillType.HealthRegen => 1, SkillType.Stamina => 100, SkillType.StaminaRegen => 100, SkillType.Strength => 75, SkillType.JumpHeight => 100, SkillType.SprintSpeed => 80, SkillType.SwimSpeed => 200, SkillType.SwimStamina => 100, SkillType.Oxygen => 50, SkillType.Battery => 100, SkillType.Slots => 10, SkillType.Exp => 100, SkillType.MonsterExp => 400, SkillType.SellExp => 2000, SkillType.SellValue => 20, SkillType.ShipDoor => 100, SkillType.OvertimeBonus => 20, SkillType.Lockpick => 500, SkillType.Scrap => 5, _ => 100, }; if (1 == 0) { } return result; } } } namespace CookieProgression.Payloads { public sealed class AllocateSkillC2S : NetworkPayload<AllocateSkillC2S> { private static readonly int StaticEncodingSize = FastBufferWriter.GetWriteSize<SkillType>() + FastBufferWriter.GetWriteSize<int>(); public static NetworkPayloadType<AllocateSkillC2S> Type { get; } = new NetworkPayloadType<AllocateSkillC2S>("AllocateSkill", (NetworkSide)2); public override NetworkPayloadType<AllocateSkillC2S> PayloadType => Type; public SkillType SkillType { get; } public int Points { get; } private AllocateSkillC2S(FastBufferReader reader) { //IL_000e: 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_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) SkillType skillType = default(SkillType); ((FastBufferReader)(ref reader)).ReadValueSafe<SkillType>(ref skillType, default(ForEnums)); int num = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num, default(ForPrimitives)); SkillType = skillType; Points = num; } public AllocateSkillC2S(SkillType type, int points) { SkillType = type; Points = points; } public override void Encode(FastBufferWriter writer) { //IL_000e: 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_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) SkillType skillType = SkillType; ((FastBufferWriter)(ref writer)).WriteValueSafe<SkillType>(ref skillType, default(ForEnums)); int points = Points; ((FastBufferWriter)(ref writer)).WriteValueSafe<int>(ref points, default(ForPrimitives)); } public override int GetEstimatedSize() { return StaticEncodingSize; } } public sealed class DefineSkillsS2C : NetworkPayload<DefineSkillsS2C> { public static NetworkPayloadType<DefineSkillsS2C> Type { get; } = new NetworkPayloadType<DefineSkillsS2C>("DefineSkills", (NetworkSide)1); public override NetworkPayloadType<DefineSkillsS2C> PayloadType => Type; public IReadOnlyList<SkillDefinition> Definitions { get; } private DefineSkillsS2C(FastBufferReader reader) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) List<SkillDefinition> list = new List<SkillDefinition>(); int num = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num, default(ForPrimitives)); while (num-- > 0) { list.Add(SkillDefinition.Decode(reader)); } Definitions = list.AsReadOnly(); } public DefineSkillsS2C(IEnumerable<SkillDefinition> definitions) { Definitions = new List<SkillDefinition>(definitions).AsReadOnly(); } public override void Encode(FastBufferWriter writer) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) int count = Definitions.Count; ((FastBufferWriter)(ref writer)).WriteValueSafe<int>(ref count, default(ForPrimitives)); foreach (SkillDefinition definition in Definitions) { definition.Encode(writer); } } public override int GetEstimatedSize() { return FastBufferWriter.GetWriteSize<int>() + SkillDefinition.EncodingSize * Definitions.Count; } } public sealed class SetExpS2C : NetworkPayload<SetExpS2C> { public static NetworkPayloadType<SetExpS2C> Type { get; } = new NetworkPayloadType<SetExpS2C>("SetExp", (NetworkSide)1); public override NetworkPayloadType<SetExpS2C> PayloadType => Type; public int Exp { get; } private SetExpS2C(FastBufferReader reader) { //IL_000e: 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) int num = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num, default(ForPrimitives)); Exp = num; } public SetExpS2C(int exp) { Exp = exp; } public override void Encode(FastBufferWriter writer) { //IL_000e: 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) int exp = Exp; ((FastBufferWriter)(ref writer)).WriteValueSafe<int>(ref exp, default(ForPrimitives)); } public override int GetEstimatedSize() { return FastBufferWriter.GetWriteSize<int>(); } } public sealed class SetSkillS2C : NetworkPayload<SetSkillS2C> { private static readonly int StaticEncodingSize = FastBufferWriter.GetWriteSize<SkillType>() + FastBufferWriter.GetWriteSize<int>(); public static NetworkPayloadType<SetSkillS2C> Type { get; } = new NetworkPayloadType<SetSkillS2C>("SetSkill", (NetworkSide)1); public override NetworkPayloadType<SetSkillS2C> PayloadType => Type; public SkillType SkillType { get; } public int Points { get; } private SetSkillS2C(FastBufferReader reader) { //IL_000e: 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_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) SkillType skillType = default(SkillType); ((FastBufferReader)(ref reader)).ReadValueSafe<SkillType>(ref skillType, default(ForEnums)); int num = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num, default(ForPrimitives)); SkillType = skillType; Points = num; } public SetSkillS2C(SkillType type, int points) { SkillType = type; Points = points; } public override void Encode(FastBufferWriter writer) { //IL_000e: 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_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) SkillType skillType = SkillType; ((FastBufferWriter)(ref writer)).WriteValueSafe<SkillType>(ref skillType, default(ForEnums)); int points = Points; ((FastBufferWriter)(ref writer)).WriteValueSafe<int>(ref points, default(ForPrimitives)); } public override int GetEstimatedSize() { return StaticEncodingSize; } } public sealed class TeamSkillS2C : NetworkPayload<TeamSkillS2C> { private static readonly int StaticEncodingSize = FastBufferWriter.GetWriteSize<SkillType>() + FastBufferWriter.GetWriteSize<ulong>(); public static NetworkPayloadType<TeamSkillS2C> Type { get; } = new NetworkPayloadType<TeamSkillS2C>("TeamSkill", (NetworkSide)1); public override NetworkPayloadType<TeamSkillS2C> PayloadType => Type; public SkillType SkillType { get; } public ulong Multiplier { get; } private TeamSkillS2C(FastBufferReader reader) { //IL_000e: 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_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) SkillType skillType = default(SkillType); ((FastBufferReader)(ref reader)).ReadValueSafe<SkillType>(ref skillType, default(ForEnums)); ulong num = default(ulong); ((FastBufferReader)(ref reader)).ReadValueSafe<ulong>(ref num, default(ForPrimitives)); SkillType = skillType; Multiplier = num; } public TeamSkillS2C(SkillType type, ulong multiplier) { SkillType = type; Multiplier = multiplier; } public override void Encode(FastBufferWriter writer) { //IL_000e: 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_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) SkillType skillType = SkillType; ((FastBufferWriter)(ref writer)).WriteValueSafe<SkillType>(ref skillType, default(ForEnums)); ulong multiplier = Multiplier; ((FastBufferWriter)(ref writer)).WriteValueSafe<ulong>(ref multiplier, default(ForPrimitives)); } public override int GetEstimatedSize() { return StaticEncodingSize; } } public sealed class UpdateConfigS2C : NetworkPayload<UpdateConfigS2C> { public static NetworkPayloadType<UpdateConfigS2C> Type { get; } = new NetworkPayloadType<UpdateConfigS2C>("UpdateConfig", (NetworkSide)1); public override NetworkPayloadType<UpdateConfigS2C> PayloadType => Type; public override void Encode(FastBufferWriter writer) { throw new NotImplementedException(); } public override int GetEstimatedSize() { throw new NotImplementedException(); } } } namespace CookieProgression.Patches { [HarmonyPatch] [HarmonyWrapSafe] internal static class BatteryPatch { [HarmonyPatch(typeof(GrabbableObject), "SyncBatteryServerRpc")] [HarmonyTranspiler] private static IEnumerable<CodeInstruction> OnBatteryCharge(IEnumerable<CodeInstruction> instructions) { MethodInfo original = AccessUtils.MethodInfo((LambdaExpression)(Expression<Func<Action<int>>>)(() => ((GrabbableObject)null).SyncBatteryClientRpc)); MethodInfo replacement = AccessUtils.MethodInfo((LambdaExpression)(Expression<Func<Action<GrabbableObject, int>>>)(() => OnBatteryChargeRedirect)); bool found = false; foreach (CodeInstruction instruction in instructions) { if (CodeInstructionExtensions.Calls(instruction, original)) { yield return new CodeInstruction(OpCodes.Call, (object)replacement); found = true; } else { yield return instruction; } } if (!found) { Logger.Error("[Patch] Unable to patch item charge."); } } private static void OnBatteryChargeRedirect(GrabbableObject gObject, int charge) { int num = charge; try { if (!Networking.IsConnected || !Networking.Instance.IsServer) { return; } AbstractServer server = Networking.Instance.Server; PlayerControllerB playerHeldBy = gObject.playerHeldBy; ServerPlayer val = default(ServerPlayer); if (charge == 100 && playerHeldBy != null && server.PlayerManager.TryGetPlayer(playerHeldBy.actualClientId, ref val)) { Logger.Info(string.Format("About to charge: {0} to {1} for {2}", gObject.itemProperties.itemName, charge, playerHeldBy.playerUsername ?? "<unknown>")); SkillManager skillManager = default(SkillManager); if (((AbstractPlayer)val).TryGet<SkillManager>(ref skillManager)) { double num2 = 1.0 + skillManager.GetMultiplier(SkillType.Battery); num = (int)((double)charge * num2); Logger.Info($"Charged {playerHeldBy.playerUsername}'s {gObject.itemProperties.itemName}'s battery to {num}% ({charge}x{num2})"); } } } catch (Exception arg) { Logger.Error($"Exception while handling item charger.\n{arg}"); } finally { gObject.SyncBatteryClientRpc(num); } } } [HarmonyPatch] [HarmonyWrapSafe] internal static class ExpPatches { private static readonly List<GrabbableObject> CollectedScrap = new List<GrabbableObject>(); private static readonly Dictionary<EnemyAI, (ulong, long)> Attackers = new Dictionary<EnemyAI, (ulong, long)>(); private static readonly Dictionary<ulong, (ulong, long, int)> Violence = new Dictionary<ulong, (ulong, long, int)>(); [HarmonyPatch(typeof(PlayerControllerB), "SetItemInElevator")] [HarmonyPrefix] private static void OnPlacedScrap(PlayerControllerB __instance, bool droppedInShipRoom, GrabbableObject gObject) { if (!Networking.IsConnected || !Networking.Instance.IsServer || !droppedInShipRoom || gObject.isInShipRoom == droppedInShipRoom || gObject.scrapPersistedThroughRounds) { return; } AbstractServer server = Networking.Instance.Server; if (gObject.itemProperties.isScrap && !CollectedScrap.Contains(gObject)) { CollectedScrap.Add(gObject); ServerPlayer val = default(ServerPlayer); SkillManager skillManager = default(SkillManager); if (server.PlayerManager.TryGetPlayer(__instance.actualClientId, ref val) && ((AbstractPlayer)val).TryGet<SkillManager>(ref skillManager)) { int scrapValue = gObject.scrapValue; double num = 1.0 + skillManager.GetMultiplier(SkillType.Exp); int num2 = (int)((double)scrapValue * num); skillManager.AddExp(num2); Logger.Info($"Awarded net:{((AbstractPlayer)val).NetworkId} {num2} exp ({scrapValue}x{num:f2}) from collecting scrap {gObject.itemProperties.itemName}."); } else { Logger.Error($"Lost {gObject.scrapValue} credits worth of exp for net:{__instance.actualClientId}"); } } } [HarmonyPatch(typeof(EnemyAI), "HitEnemy")] [HarmonyPostfix] private static void OnHitEnemy(EnemyAI __instance, PlayerControllerB? playerWhoHit) { if (Networking.IsConnected && Networking.Instance.IsServer && playerWhoHit != null) { Attackers[__instance] = (playerWhoHit.actualClientId, Stopwatch.GetTimestamp()); } } [HarmonyPatch(typeof(EnemyAI), "KillEnemy")] [HarmonyPostfix] private static void OnEnemyDeath(EnemyAI __instance) { //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) if (!Networking.IsConnected || !Networking.Instance.IsServer) { return; } (Config.EnemyExpType, int Range, int BaseExp) enemyExp = Config.GetEnemyExp(((object)__instance).GetType()); Config.EnemyExpType item = enemyExp.Item1; int item2 = enemyExp.Range; int item3 = enemyExp.BaseExp; string enemyFriendlyName = Config.GetEnemyFriendlyName(((object)__instance).GetType()); Logger.Info($"[{enemyFriendlyName}] Mode: {item}, Range: {item2}, Exp: {item3}"); if (item == Config.EnemyExpType.Disabled || item3 < 1) { Logger.Info("[" + enemyFriendlyName + "] cannot award exp."); } ulong num = ulong.MaxValue; if (Attackers.TryGetValue(__instance, out var value)) { (ulong, long) tuple = value; ulong item4 = tuple.Item1; long item5 = tuple.Item2; TimeSpan timeSpan = TimeSpan.FromSeconds((double)(Stopwatch.GetTimestamp() - item5) / (double)Stopwatch.Frequency); if (timeSpan <= TimeSpan.FromSeconds(10.0)) { num = item4; } } else if (item == Config.EnemyExpType.Attacker) { Logger.Info($"[{enemyFriendlyName}] died without an attacker, lost {item3} exp."); return; } AbstractServer server = Networking.Instance.Server; PlayerControllerB val = default(PlayerControllerB); SkillManager skillManager = default(SkillManager); foreach (ServerPlayer player in server.PlayerManager.Players) { if (!PlayerUtils.TryGetPlayerScript(((AbstractPlayer)player).NetworkId, ref val) || val.isPlayerDead) { continue; } bool flag = item == Config.EnemyExpType.AoE && Vector3.Distance(((Component)__instance).transform.position, ((Component)val).transform.position) <= (float)item2; if (((AbstractPlayer)player).TryGet<SkillManager>(ref skillManager) && (((AbstractPlayer)player).NetworkId == num || flag)) { int num2 = item3; double num3 = (1.0 + skillManager.GetMultiplier(SkillType.Exp)) * (1.0 + skillManager.GetMultiplier(SkillType.MonsterExp)); int num4 = (int)((double)num2 * num3); skillManager.AddExp(num4); if (((AbstractPlayer)player).NetworkId == num) { Logger.Info($"Awarded net:{((AbstractPlayer)player).NetworkId} {num4} exp ({num2}x{num3:f2}) from killing a {enemyFriendlyName}."); } else { Logger.Info($"Awarded net:{((AbstractPlayer)player).NetworkId} {num4} exp ({num2}x{num3:f2}) from a {enemyFriendlyName} dying within 10 units."); } } } } [HarmonyPatch(typeof(PlayerControllerB), "DamagePlayerFromOtherClientServerRpc")] [HarmonyTranspiler] private static IEnumerable<CodeInstruction> OnPlayerHit(IEnumerable<CodeInstruction> instructions) { MethodInfo original = AccessUtils.MethodInfo((LambdaExpression)(Expression<Func<Action<int, Vector3, int, int>>>)(() => ((PlayerControllerB)null).DamagePlayerFromOtherClientClientRpc)); MethodInfo replacement = AccessUtils.MethodInfo((LambdaExpression)(Expression<Func<Action<PlayerControllerB, int, Vector3, int, int>>>)(() => OnPlayerHitRedirect)); bool found = false; foreach (CodeInstruction instruction in instructions) { if (CodeInstructionExtensions.Calls(instruction, original)) { yield return new CodeInstruction(OpCodes.Call, (object)replacement); Logger.Info(string.Format("[Patch] Redirected call {0} -> {1} in {2}", original, replacement, "DamagePlayerFromOtherClientServerRpc")); found = true; } else { yield return instruction; } } if (!found) { Logger.Error("[Patch] Unable to patch player on player violence."); } } private static void OnPlayerHitRedirect(PlayerControllerB script, int damageAmount, Vector3 hitDirection, int playerWhoHit, int newHealthAmount) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) script.DamagePlayerFromOtherClientClientRpc(damageAmount, hitDirection, playerWhoHit, newHealthAmount); try { PlayerControllerB val = default(PlayerControllerB); if (PlayerUtils.TryGetPlayerScript(playerWhoHit, ref val)) { Violence[script.actualClientId] = (val.actualClientId, Stopwatch.GetTimestamp(), damageAmount); Logger.Info($"{val.playerUsername} hit {script.playerUsername} for {damageAmount} damage."); } } catch (Exception arg) { Logger.Error($"Exception while handling player on player violence.\n{arg}"); } } [HarmonyPatch(typeof(PlayerControllerB), "KillPlayerServerRpc")] [HarmonyTranspiler] private static IEnumerable<CodeInstruction> OnPlayerDeath(IEnumerable<CodeInstruction> instructions) { MethodInfo original = AccessUtils.MethodInfo((LambdaExpression)(Expression<Func<Action<int, bool, Vector3, int, int, Vector3>>>)(() => ((PlayerControllerB)null).KillPlayerClientRpc)); MethodInfo replacement = AccessUtils.MethodInfo((LambdaExpression)(Expression<Func<Action<PlayerControllerB, int, bool, Vector3, int, int, Vector3>>>)(() => OnPlayerDeathRedirect)); bool found = false; foreach (CodeInstruction instruction in instructions) { if (CodeInstructionExtensions.Calls(instruction, original)) { yield return new CodeInstruction(OpCodes.Call, (object)replacement); Logger.Info(string.Format("[Patch] Redirected call {0} -> {1} in {2}", original, replacement, "KillPlayerServerRpc")); found = true; } else { yield return instruction; } } if (!found) { Logger.Error("[Patch] Unable to patch player death."); } } private static void OnPlayerDeathRedirect(PlayerControllerB script, int playerId, bool spawnBody, Vector3 bodyVelocity, int causeOfDeath, int deathAnimation, Vector3 positionOffset) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) script.KillPlayerClientRpc(playerId, spawnBody, bodyVelocity, causeOfDeath, deathAnimation, positionOffset); try { MetaPatches.OnPlayerDeath(script); } catch (Exception arg) { Logger.Error($"Exception while handling meta player death.\n{arg}"); } try { if (!Networking.IsConnected || !Networking.Instance.IsServer || !Violence.TryGetValue(script.actualClientId, out var value)) { return; } (ulong, long, int) tuple = value; ulong item = tuple.Item1; long item2 = tuple.Item2; int item3 = tuple.Item3; TimeSpan timeSpan = TimeSpan.FromSeconds((double)(Stopwatch.GetTimestamp() - item2) / (double)Stopwatch.Frequency); if (!(timeSpan > TimeSpan.FromTicks(1000000L * (long)Math.Max(item3, 5)))) { AbstractServer server = Networking.Instance.Server; ServerPlayer val = default(ServerPlayer); SkillManager skillManager = default(SkillManager); if (server.PlayerManager.TryGetPlayer(item, ref val) && ((AbstractPlayer)val).TryGet<SkillManager>(ref skillManager)) { int num = 5; double num2 = (1.0 + skillManager.GetMultiplier(SkillType.Exp)) * (1.0 + skillManager.GetMultiplier(SkillType.MonsterExp)); int num3 = (int)((double)num * num2); skillManager.AddExp(num3); Logger.Info($"Awarded net:{((AbstractPlayer)val).NetworkId} {num3} ({num}x{num2:f2}) exp for killing their friend {script.playerUsername} (net:{script.actualClientId}) ohno"); } } } catch (Exception arg2) { Logger.Error($"Exception while handling player death.\n{arg2}"); } } [HarmonyPatch(typeof(DepositItemsDesk), "SellItemsOnServer")] [HarmonyPriority(300)] [HarmonyPrefix] private static void OnSellExp(DepositItemsDesk __instance) { if (!((NetworkBehaviour)__instance).IsServer) { return; } int num = 0; foreach (GrabbableObject item in __instance.itemsOnCounter) { if (item.itemProperties.isScrap) { num++; } } OnScrapSold(num); } private static void OnScrapSold(int scrapSold) { try { if (!Networking.IsConnected || !Networking.Instance.IsServer) { return; } AbstractServer server = Networking.Instance.Server; if (scrapSold == 0) { Logger.Warning("Patch incompatability: scrap sold was 0 - unless you really did only sell 0 scrap."); return; } SkillManager skillManager = default(SkillManager); foreach (ServerPlayer player in server.PlayerManager.Players) { if (((AbstractPlayer)player).TryGet<SkillManager>(ref skillManager)) { double num = (double)scrapSold * skillManager.GetMultiplier(SkillType.SellExp); double num2 = 1.0 + skillManager.GetMultiplier(SkillType.Exp); int num3 = (int)(num * num2); skillManager.AddExp(num3); Logger.Info($"Awarded net:{((AbstractPlayer)player).NetworkId} {num3} exp ({num:0.#}x{num2:f2}) from selling {scrapSold} scrap."); } } } catch (Exception arg) { Logger.Error($"Exception while handling player exp distribution.\n{arg}"); } } [HarmonyPatch(typeof(StartOfRound), "EndOfGame")] [HarmonyPostfix] private static IEnumerator OnRoundReset(IEnumerator result) { CollectedScrap.Clear(); Attackers.Clear(); Violence.Clear(); while (result.MoveNext()) { yield return result.Current; } } } [HarmonyPatch] [HarmonyWrapSafe] internal static class MenuPatches { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static UnityAction <>9__21_0; internal void <MakeSkillMenuButton>b__21_0() { SkillMenu.Instance?.OpenSkillMenu(); } } private static GameObject? _skillMenuButton; private static GameObject? _xpBar; private static GameObject? _xpInfoContainer; private static GameObject? _xpBarProgress; private static TextMeshProUGUI? _xpText; private static TextMeshProUGUI? _xpLevel; private static TextMeshProUGUI? _profit; private static GameObject? _popupBar; private static TextMeshProUGUI? _popupText; private static GameObject? _levelText; private static bool _popupTimer; private static bool _popupLevelTimer; internal static void Destroy() { _skillMenuButton = null; _xpBar = null; _xpInfoContainer = null; _xpBarProgress = null; _xpText = null; _xpLevel = null; _profit = null; _popupBar = null; _popupText = null; _levelText = null; _popupTimer = false; _popupLevelTimer = false; } [HarmonyPostfix] [HarmonyPatch(typeof(QuickMenuManager), "OpenQuickMenu")] private static void OnOpenMenu(QuickMenuManager __instance) { if (__instance.isMenuOpen) { if (!Object.op_Implicit((Object)(object)_xpInfoContainer) || !Object.op_Implicit((Object)(object)_xpBar) || !Object.op_Implicit((Object)(object)_xpBarProgress)) { MakeNewXPBar(); } if (!Object.op_Implicit((Object)(object)_skillMenuButton)) { MakeSkillMenuButton(); } _xpBar.SetActive(true); _xpBarProgress.SetActive(true); } } [HarmonyPostfix] [HarmonyPatch(typeof(QuickMenuManager), "Update")] private static void OnUpdate(QuickMenuManager __instance) { if (Object.op_Implicit((Object)(object)_xpInfoContainer) && Object.op_Implicit((Object)(object)_xpBar) && Object.op_Implicit((Object)(object)_xpBarProgress) && SkillMenu.Instance != null) { SkillManager manager = SkillMenu.Instance.Manager; bool activeSelf = __instance.mainButtonsPanel.activeSelf; _xpInfoContainer.SetActive(activeSelf); if (manager.HasMoreLevels) { ((TMP_Text)_xpText).SetText($"{manager.UnusedExp} / {manager.NeededExp}", true); _xpBarProgress.GetComponent<Image>().fillAmount = (float)manager.UnusedExp / (float)manager.NeededExp; } else { ((TMP_Text)_xpText).SetText("MAX", true); _xpBarProgress.GetComponent<Image>().fillAmount = 1f; } ((TMP_Text)_xpLevel).SetText($"Level: {manager.Level}", true); ((TMP_Text)_profit).SetText($"You've made.. {Random.Range(1000, 10000)}$", true); } } [HarmonyPostfix] [HarmonyPatch(typeof(HUDManager), "PingScan_performed")] private static void TestScan() { if (!Networking.IsConnected) { return; } Networking instance = Networking.Instance; if (!instance.IsServer) { return; } AbstractServer server = instance.Server; SkillManager skillManager = default(SkillManager); foreach (ServerPlayer player in server.Players) { if (!((AbstractPlayer)player).TryGet<SkillManager>(ref skillManager)) { } } } public static void ShowXpPopup() { if (SkillMenu.Instance != null) { if (!Object.op_Implicit((Object)(object)_popupBar)) { MakePopupBar(); } SkillManager manager = SkillMenu.Instance.Manager; GameObject val = GameObject.Find("/Systems/UI/Canvas/IngamePlayerHUD/BottomMiddle/XPUpdate/XPBarProgress"); if (manager.HasMoreLevels) { ((TMP_Text)_popupText).SetText($"{manager.UnusedExp} / {manager.NeededExp}", true); val.GetComponent<Image>().fillAmount = (float)manager.UnusedExp / (float)manager.NeededExp; } else { ((TMP_Text)_popupText).SetText("MAX", true); val.GetComponent<Image>().fillAmount = 1f; } _popupTimer = true; if (!_popupBar.activeSelf) { ((MonoBehaviour)GameNetworkManager.Instance).StartCoroutine(OnXpPopup()); } } } public static void ShowLevelPopup() { if (!Object.op_Implicit((Object)(object)_levelText)) { MakeLevelUp(); } _popupLevelTimer = true; if (!_levelText.gameObject.activeSelf) { ((MonoBehaviour)GameNetworkManager.Instance).StartCoroutine(OnLevelPopup()); } } private static IEnumerator OnXpPopup() { _popupBar.SetActive(true); while (_popupTimer) { _popupTimer = false; yield return (object)new WaitForSeconds(2f); } GameObject? popupBar = _popupBar; if (popupBar != null) { popupBar.SetActive(false); } } private static IEnumerator OnLevelPopup() { _levelText.gameObject.SetActive(true); while (_popupLevelTimer) { _popupLevelTimer = false; yield return (object)new WaitForSeconds(5f); } GameObject? levelText = _levelText; if (levelText != null) { levelText.gameObject.SetActive(false); } } public static void MakeNewXPBar() { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_02b9: Unknown result type (might be due to invalid IL or missing references) //IL_02cd: Unknown result type (might be due to invalid IL or missing references) //IL_02e1: Unknown result type (might be due to invalid IL or missing references) //IL_02eb: Unknown result type (might be due to invalid IL or missing references) //IL_035f: Unknown result type (might be due to invalid IL or missing references) //IL_03de: Unknown result type (might be due to invalid IL or missing references) //IL_0421: Unknown result type (might be due to invalid IL or missing references) GameObject val = GameObject.Find("/Systems/UI/Canvas/QuickMenu"); GameObject val2 = GameObject.Find("/Systems/UI/Canvas/EndgameStats/LevelUp/Total"); if (!Object.op_Implicit((Object)(object)_xpInfoContainer)) { _xpInfoContainer = new GameObject("XpInfoContainer"); _xpInfoContainer.transform.SetParent(val.transform, false); _xpInfoContainer.transform.localScale = new Vector3(0.75f, 0.75f, 0.75f); _xpInfoContainer.transform.Translate(-1.7f, 0.9f, 0f); } if (!Object.op_Implicit((Object)(object)_xpBar)) { GameObject val3 = GameObject.Find("/Systems/UI/Canvas/EndgameStats/LevelUp/LevelUpBox"); _xpBar = Object.Instantiate<GameObject>(val3); _xpBar.transform.SetParent(_xpInfoContainer.transform, false); ((Object)_xpBar).name = "XPBar"; _xpText = Object.Instantiate<GameObject>(val2).GetComponent<TextMeshProUGUI>(); ((TMP_Text)_xpText).transform.SetParent(_xpBar.transform, false); ((TMP_Text)_xpText).transform.Translate(-0.75f, 0.21f, 0f); ((Object)_xpText).name = "XPText"; ((TMP_Text)_xpText).alignment = (TextAlignmentOptions)514; ((TMP_Text)_xpText).SetText("0/40", true); ((Graphic)_xpText).color = new Color(1f, 0.6f, 0f, 1f); _xpLevel = Object.Instantiate<GameObject>(val2).GetComponent<TextMeshProUGUI>(); ((TMP_Text)_xpLevel).transform.SetParent(_xpInfoContainer.transform, false); ((TMP_Text)_xpLevel).transform.position = new Vector3(_xpBar.transform.position.x, _xpBar.transform.position.y, _xpBar.transform.position.z); ((TMP_Text)_xpLevel).transform.Translate(-0.3f, 0.2f, 0f); ((Object)_xpLevel).name = "XPLevel"; ((TMP_Text)_xpLevel).alignment = (TextAlignmentOptions)514; ((TMP_Text)_xpLevel).SetText("Level: 0", true); ((Graphic)_xpLevel).color = new Color(1f, 0.6f, 0f, 1f); _profit = Object.Instantiate<GameObject>(val2).GetComponent<TextMeshProUGUI>(); ((TMP_Text)_profit).transform.SetParent(_xpInfoContainer.transform, false); ((TMP_Text)_profit).transform.position = new Vector3(_xpBar.transform.position.x, _xpBar.transform.position.y, _xpBar.transform.position.z); ((TMP_Text)_profit).transform.Translate(-0.1f, -0.2f, 0f); ((Object)_profit).name = "XPProfit"; ((TMP_Text)_profit).alignment = (TextAlignmentOptions)514; ((TMP_Text)_profit).SetText("You've made.. 0$.", true); ((Graphic)_profit).color = new Color(1f, 0.6f, 0f, 1f); } if (!Object.op_Implicit((Object)(object)_xpBarProgress)) { GameObject val4 = GameObject.Find("/Systems/UI/Canvas/EndgameStats/LevelUp/LevelUpMeter"); _xpBarProgress = Object.Instantiate<GameObject>(val4); _xpBarProgress.transform.SetParent(_xpBar.transform, false); _xpBarProgress.transform.SetAsFirstSibling(); _xpBarProgress.transform.localScale = new Vector3(0.597f, 5.21f, 1f); _xpBarProgress.transform.Translate(-0.8f, 0.2f, 0f); _xpBarProgress.transform.localPosition = new Vector3(0f, 0f, 0f); ((Object)_xpBarProgress).name = "XPBarProgress"; _xpBarProgress.GetComponent<Image>().fillAmount = 0f; } } private static void MakeSkillMenuButton() { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: 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_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Expected O, but got Unknown //IL_013e: Expected O, but got Unknown //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Expected O, but got Unknown GameObject val = GameObject.Find("Systems/UI/Canvas/QuickMenu/MainButtons/Resume"); _skillMenuButton = Object.Instantiate<GameObject>(val); GameObject val2 = GameObject.Find("Systems/UI/Canvas/QuickMenu/MainButtons"); _skillMenuButton.transform.SetParent(val2.transform, false); _skillMenuButton.transform.position = new Vector3(0.55f + _xpBar.transform.position.x, 1.09f + _xpBar.transform.position.y, _xpBar.transform.position.z); ((Object)_skillMenuButton).name = "Skills"; ((TMP_Text)_skillMenuButton.GetComponentInChildren<TextMeshProUGUI>()).SetText("> Skills", true); Transform transform = ((TMP_Text)_xpText).transform; _skillMenuButton.transform.localPosition = new Vector3(transform.position.x, transform.position.y, transform.position.z); Transform transform2 = _skillMenuButton.transform; transform2.position += new Vector3(-0.15f, 1.056f); Button component = _skillMenuButton.GetComponent<Button>(); ButtonClickedEvent val3 = new ButtonClickedEvent(); ButtonClickedEvent val4 = val3; component.onClick = val3; ButtonClickedEvent val5 = val4; object obj = <>c.<>9__21_0; if (obj == null) { UnityAction val6 = delegate { SkillMenu.Instance?.OpenSkillMenu(); }; <>c.<>9__21_0 = val6; obj = (object)val6; } ((UnityEvent)val5).AddListener((UnityAction)obj); Button component2 = _xpBar.GetComponent<Button>(); if (component2 == null) { _xpBar.AddComponent<Button>().onClick = val5; } component2 = _xpBarProgress.GetComponent<Button>(); if (component2 == null) { _xpBarProgress.AddComponent<Button>().onClick = val5; } } private static void MakePopupBar() { //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: 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_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) MakeNewXPBar(); GameObject val = GameObject.Find("/Systems/UI/Canvas/QuickMenu/XpInfoContainer/XPBar"); _popupBar = Object.Instantiate<GameObject>(val); ((Object)_popupBar).name = "XPUpdate"; _popupText = _popupBar.GetComponentInChildren<TextMeshProUGUI>(); GameObject val2 = GameObject.Find("/Systems/UI/Canvas/IngamePlayerHUD/BottomMiddle"); _popupBar.transform.SetParent(val2.transform, false); _popupBar.transform.localScale = new Vector3(0.4f, 0.4f, 0.4f); GameObject val3 = GameObject.Find("/Systems/UI/Canvas/IngamePlayerHUD/BottomMiddle/XPUpdate/XPLevel"); Object.Destroy((Object)(object)val3); GameObject val4 = GameObject.Find("/Systems/UI/Canvas/IngamePlayerHUD/BottomMiddle/XPUpdate/XPProfit"); Object.Destroy((Object)(object)val4); _popupBar.transform.Translate(3.1f, -2.1f, 0f); Vector3 localPosition = _popupBar.transform.localPosition; _popupBar.transform.localPosition = new Vector3(localPosition.x, localPosition.y + 5f, localPosition.z); _popupBar.SetActive(false); } public static void MakeLevelUp() { _levelText = Object.Instantiate<GameObject>(Plugin.MenuBundle.LoadAsset<GameObject>("LevelUp")); ((TMP_Text)((Component)_levelText.transform.GetChild(0)).GetComponent<TextMeshProUGUI>()).text = "Level Up! Spend your skill points."; _levelText.gameObject.SetActive(false); } } [HarmonyPatch] [HarmonyWrapSafe] internal static class MetaPatches { [HarmonyPatch(typeof(StartOfRound), "FirePlayersAfterDeadlineClientRpc")] [HarmonyPostfix] private static void OnPlayerFired() { if (!Networking.IsConnected || !Networking.Instance.IsServer) { return; } AbstractServer server = Networking.Instance.Server; SkillManager skillManager = default(SkillManager); foreach (ServerPlayer player in server.Players) { if (((AbstractPlayer)player).TryGet<SkillManager>(ref skillManager)) { skillManager.SetExp(skillManager.UsedExp); } } } internal static void OnPlayerDeath(PlayerControllerB script) { if (Networking.IsConnected && Networking.Instance.IsServer) { AbstractServer server = Networking.Instance.Server; ServerPlayer val = default(ServerPlayer); SkillManager skillManager = default(SkillManager); if (server.PlayerManager.TryGetPlayer(script.actualClientId, ref val) && ((AbstractPlayer)val).TryGet<SkillManager>(ref skillManager)) { skillManager.SetExp(skillManager.UsedExp); } } } } [HarmonyPatch] [HarmonyWrapSafe] internal static class ScrapPatch { [HarmonyPatch(typeof(RoundManager), "SpawnScrapInLevel")] [HarmonyTranspiler] private static IEnumerable<CodeInstruction> OnSpawnScrapInLevel(IEnumerable<CodeInstruction> instructions) { FieldInfo currentLevel = AccessTools.DeclaredField(typeof(RoundManager), "currentLevel"); FieldInfo minScrap = AccessTools.DeclaredField(typeof(SelectableLevel), "minScrap"); FieldInfo maxScrap = AccessTools.DeclaredField(typeof(SelectableLevel), "maxScrap"); MethodInfo getMul = AccessUtils.MethodInfo((LambdaExpression)(Expression<Func<Func<SkillType, double>>>)(() => SkillManager.GetTeamMultiplier)); int step = 0; foreach (CodeInstruction instruction in instructions) { yield return instruction; if (CodeInstructionExte