Please disclose if your mod was created primarily using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of CookieProgression v0.1.2
CookieProgression.dll
Decompiled a year 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