using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using GeneticsArtifact.CheatManager; using GeneticsArtifact.SgdEngine; using GeneticsArtifact.SgdEngine.Actuators; using GeneticsArtifact.SgdEngine.Decision; using GeneticsArtifact.Telemetry; using HG.Reflection; using On.RoR2; using On.RoR2.UI.MainMenu; using R2API; using R2API.ScriptableObjects; using R2API.Utils; using RiskOfOptions; using RiskOfOptions.OptionConfigs; using RiskOfOptions.Options; using RoR2; using RoR2.UI; using RoR2.UI.MainMenu; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Networking; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: OptIn] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("GeneticsArtifact")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+cc54579cf71aa1261b0afa656fad0c505125048a")] [assembly: AssemblyProduct("GeneticsArtifact")] [assembly: AssemblyTitle("GeneticsArtifact")] [assembly: AssemblyVersion("1.0.0.0")] namespace GeneticsArtifact { public class ArtifactOfGenetics { public static ArtifactDef artifactDef; public static ArtifactCode artifactCode; public static ArtifactCompoundDef geneArtifactCompoundDef; internal static void Init() { //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_0103: 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_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) LanguageAPI.Add("GENETIC_ARTIFACT_NAME_TOKEN", "Artifact of Genetics"); LanguageAPI.Add("GENETIC_ARTIFACT_DESCRIPTION_TOKEN", "Monsters will spawn with adjusted stats. Adjustments are determined by a genetic algorithm."); artifactDef = ScriptableObject.CreateInstance(); artifactDef.nameToken = "GENETIC_ARTIFACT_NAME_TOKEN"; artifactDef.descriptionToken = "GENETIC_ARTIFACT_DESCRIPTION_TOKEN"; artifactDef.smallIconSelectedSprite = GeneticsArtifactPlugin.geneticAssetBundle.LoadAsset("Assets/Genetics/Selected.png"); artifactDef.smallIconDeselectedSprite = GeneticsArtifactPlugin.geneticAssetBundle.LoadAsset("Assets/Genetics/Unselected.png"); artifactDef.pickupModelPrefab = GeneticsArtifactPlugin.geneticAssetBundle.LoadAsset("Assets/Genetics/PickupGene.prefab"); ContentAddition.AddArtifactDef(artifactDef); geneArtifactCompoundDef = ScriptableObject.CreateInstance(); geneArtifactCompoundDef.modelPrefab = GeneticsArtifactPlugin.geneticAssetBundle.LoadAsset("Assets/Genetics/CompoundGene.prefab"); geneArtifactCompoundDef.value = 15; ArtifactCodeAPI.AddCompound(geneArtifactCompoundDef); artifactCode = ScriptableObject.CreateInstance(); artifactCode.topRow = new Vector3Int(3, 5, 3); artifactCode.middleRow = new Vector3Int(1, geneArtifactCompoundDef.value, 1); artifactCode.bottomRow = new Vector3Int(3, 5, 3); ArtifactCodeAPI.AddCode(artifactDef, artifactCode); } } public class ConfigManager { private const float CalibratedTelemetryDegradationThreshold = 0.3f; private const float CalibratedTelemetryRecoveryThreshold = 0.25f; private const float LegacyTelemetryDegradationThreshold = 0.7f; private const float LegacyTelemetryRecoveryThreshold = 0.35f; private const float DefaultSgdHpFloor = 0.5f; private const float DefaultSgdHpCap = 2f; private const float DefaultSgdMsFloor = 0.8f; private const float DefaultSgdMsCap = 1.25f; private const float DefaultSgdAsFloor = 0.6f; private const float DefaultSgdAsCap = 1.6667f; private const float DefaultSgdDmgFloor = 0.6f; private const float DefaultSgdDmgCap = 1.6667f; private static ConfigFile _configFile; public static ConfigEntry timeLimit; public static ConfigEntry deathLimit; public static ConfigEntry governorType; public static ConfigEntry geneVarianceLimit; public static ConfigEntry geneCap; public static ConfigEntry geneFloor; public static ConfigEntry geneProductLimit; public static ConfigEntry maintainIfDisabled; public static ConfigEntry enableGeneLimitOverrides; public static ConfigEntry geneLimitOverrides; public static ConfigEntry sgdNormTargetTimeToDieSeconds; public static ConfigEntry sgdNormTargetTtkSeconds; public static ConfigEntry sgdNormHitRateScalePerSecond; public static ConfigEntry sgdHpFloor; public static ConfigEntry sgdHpCap; public static ConfigEntry sgdMsFloor; public static ConfigEntry sgdMsCap; public static ConfigEntry sgdAsFloor; public static ConfigEntry sgdAsCap; public static ConfigEntry sgdDmgFloor; public static ConfigEntry sgdDmgCap; public static ConfigEntry telemetryEnabled; public static ConfigEntry telemetryAnonymousUserId; public static ConfigEntry telemetryParticipantId; public static ConfigEntry telemetryExperimentId; public static ConfigEntry telemetryConditionOrder; public static ConfigEntry telemetryRunAttemptIndex; public static ConfigEntry telemetryConfiguredRunSeed; public static ConfigEntry telemetrySampleIntervalSeconds; public static ConfigEntry telemetryFlushIntervalSeconds; public static ConfigEntry telemetryMaxQueueSize; public static ConfigEntry telemetryJumpThreshold; public static ConfigEntry telemetryVirtualGapEpsilon; public static ConfigEntry telemetryStableErrorEpsilon; public static ConfigEntry telemetryDegradationThreshold; public static ConfigEntry telemetryRecoveryThreshold; public static ConfigEntry telemetryMinimumSessionSeconds; public static ConfigEntry researchAutoRotateDdaAlgorithms; public static ConfigEntry researchLastRunDdaAlgorithm; public static ConfigEntry researchAutoRotateRunSeeds; public static ConfigEntry researchRunSeedCycle; public static ConfigEntry researchCurrentRunSeedIndex; public static ConfigEntry researchCurrentRunSeed; public static ConfigEntry diagnosticsEnableGeneTokenCalcHooks; public static ConfigEntry diagnosticsEnableGeneticEngineHooks; public static ConfigEntry diagnosticsEnableSgdHooks; public static ConfigEntry diagnosticsEnableSgdActuatorsHooks; public static ConfigEntry diagnosticsEnableTelemetryHooks; public static ConfigEntry diagnosticsEnableRunModeRotatorHooks; public static void Init(ConfigFile configFile) { //IL_0011: 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_0032: Expected O, but got Unknown //IL_0032: Expected O, but got Unknown //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Expected O, but got Unknown //IL_0068: Expected O, but got Unknown //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Expected O, but got Unknown //IL_009c: Expected O, but got Unknown //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Expected O, but got Unknown //IL_00d5: Expected O, but got Unknown //IL_00e5: 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_0112: Expected O, but got Unknown //IL_0112: Expected O, but got Unknown //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Expected O, but got Unknown //IL_014f: Expected O, but got Unknown //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Expected O, but got Unknown //IL_018c: Expected O, but got Unknown //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Expected O, but got Unknown //IL_01c9: Expected O, but got Unknown //IL_01d9: Unknown result type (might be due to invalid IL or missing references) //IL_01f8: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Expected O, but got Unknown //IL_0202: Expected O, but got Unknown //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Unknown result type (might be due to invalid IL or missing references) //IL_0231: Expected O, but got Unknown //IL_0231: Expected O, but got Unknown //IL_0241: Unknown result type (might be due to invalid IL or missing references) //IL_0264: Unknown result type (might be due to invalid IL or missing references) //IL_026e: Expected O, but got Unknown //IL_026e: Expected O, but got Unknown //IL_027e: Unknown result type (might be due to invalid IL or missing references) //IL_02a1: Unknown result type (might be due to invalid IL or missing references) //IL_02ab: Expected O, but got Unknown //IL_02ab: Expected O, but got Unknown //IL_02bb: Unknown result type (might be due to invalid IL or missing references) //IL_02de: Unknown result type (might be due to invalid IL or missing references) //IL_02e8: Expected O, but got Unknown //IL_02e8: Expected O, but got Unknown //IL_02f8: Unknown result type (might be due to invalid IL or missing references) //IL_031b: Unknown result type (might be due to invalid IL or missing references) //IL_0325: Expected O, but got Unknown //IL_0325: Expected O, but got Unknown //IL_0335: Unknown result type (might be due to invalid IL or missing references) //IL_0358: Unknown result type (might be due to invalid IL or missing references) //IL_0362: Expected O, but got Unknown //IL_0362: Expected O, but got Unknown //IL_0372: Unknown result type (might be due to invalid IL or missing references) //IL_0395: Unknown result type (might be due to invalid IL or missing references) //IL_039f: Expected O, but got Unknown //IL_039f: Expected O, but got Unknown //IL_03af: Unknown result type (might be due to invalid IL or missing references) //IL_03d2: Unknown result type (might be due to invalid IL or missing references) //IL_03dc: Expected O, but got Unknown //IL_03dc: Expected O, but got Unknown //IL_03ec: Unknown result type (might be due to invalid IL or missing references) //IL_040f: Unknown result type (might be due to invalid IL or missing references) //IL_0419: Expected O, but got Unknown //IL_0419: Expected O, but got Unknown //IL_0429: Unknown result type (might be due to invalid IL or missing references) //IL_044c: Unknown result type (might be due to invalid IL or missing references) //IL_0456: Expected O, but got Unknown //IL_0456: Expected O, but got Unknown //IL_0466: Unknown result type (might be due to invalid IL or missing references) //IL_0489: Unknown result type (might be due to invalid IL or missing references) //IL_0493: Expected O, but got Unknown //IL_0493: Expected O, but got Unknown //IL_04a3: Unknown result type (might be due to invalid IL or missing references) //IL_04c6: Unknown result type (might be due to invalid IL or missing references) //IL_04d0: Expected O, but got Unknown //IL_04d0: Expected O, but got Unknown //IL_04e0: Unknown result type (might be due to invalid IL or missing references) //IL_04f1: Unknown result type (might be due to invalid IL or missing references) //IL_04fb: Expected O, but got Unknown //IL_04fb: Expected O, but got Unknown //IL_050b: Unknown result type (might be due to invalid IL or missing references) //IL_0520: Unknown result type (might be due to invalid IL or missing references) //IL_052a: Expected O, but got Unknown //IL_052a: Expected O, but got Unknown //IL_0577: Unknown result type (might be due to invalid IL or missing references) //IL_058c: Unknown result type (might be due to invalid IL or missing references) //IL_0596: Expected O, but got Unknown //IL_0596: Expected O, but got Unknown //IL_05a6: Unknown result type (might be due to invalid IL or missing references) //IL_05bb: Unknown result type (might be due to invalid IL or missing references) //IL_05c5: Expected O, but got Unknown //IL_05c5: Expected O, but got Unknown //IL_05d5: Unknown result type (might be due to invalid IL or missing references) //IL_05ea: Unknown result type (might be due to invalid IL or missing references) //IL_05f4: Expected O, but got Unknown //IL_05f4: Expected O, but got Unknown //IL_0604: Unknown result type (might be due to invalid IL or missing references) //IL_061f: Unknown result type (might be due to invalid IL or missing references) //IL_0629: Expected O, but got Unknown //IL_0629: Expected O, but got Unknown //IL_0639: Unknown result type (might be due to invalid IL or missing references) //IL_064e: Unknown result type (might be due to invalid IL or missing references) //IL_0658: Expected O, but got Unknown //IL_0658: Expected O, but got Unknown //IL_0668: Unknown result type (might be due to invalid IL or missing references) //IL_068b: Unknown result type (might be due to invalid IL or missing references) //IL_0695: Expected O, but got Unknown //IL_0695: Expected O, but got Unknown //IL_06a5: Unknown result type (might be due to invalid IL or missing references) //IL_06c8: Unknown result type (might be due to invalid IL or missing references) //IL_06d2: Expected O, but got Unknown //IL_06d2: Expected O, but got Unknown //IL_06e2: Unknown result type (might be due to invalid IL or missing references) //IL_0702: Unknown result type (might be due to invalid IL or missing references) //IL_070c: Expected O, but got Unknown //IL_070c: Expected O, but got Unknown //IL_071c: Unknown result type (might be due to invalid IL or missing references) //IL_073f: Unknown result type (might be due to invalid IL or missing references) //IL_0749: Expected O, but got Unknown //IL_0749: Expected O, but got Unknown //IL_0759: Unknown result type (might be due to invalid IL or missing references) //IL_077c: Unknown result type (might be due to invalid IL or missing references) //IL_0786: Expected O, but got Unknown //IL_0786: Expected O, but got Unknown //IL_0796: Unknown result type (might be due to invalid IL or missing references) //IL_07b9: Unknown result type (might be due to invalid IL or missing references) //IL_07c3: Expected O, but got Unknown //IL_07c3: Expected O, but got Unknown //IL_07d3: Unknown result type (might be due to invalid IL or missing references) //IL_07f6: Unknown result type (might be due to invalid IL or missing references) //IL_0800: Expected O, but got Unknown //IL_0800: Expected O, but got Unknown //IL_0810: Unknown result type (might be due to invalid IL or missing references) //IL_0833: Unknown result type (might be due to invalid IL or missing references) //IL_083d: Expected O, but got Unknown //IL_083d: Expected O, but got Unknown //IL_084d: Unknown result type (might be due to invalid IL or missing references) //IL_0870: Unknown result type (might be due to invalid IL or missing references) //IL_087a: Expected O, but got Unknown //IL_087a: Expected O, but got Unknown //IL_088a: Unknown result type (might be due to invalid IL or missing references) //IL_089b: Unknown result type (might be due to invalid IL or missing references) //IL_08a5: Expected O, but got Unknown //IL_08a5: Expected O, but got Unknown //IL_08b5: Unknown result type (might be due to invalid IL or missing references) //IL_08f4: Unknown result type (might be due to invalid IL or missing references) //IL_08fe: Expected O, but got Unknown //IL_08fe: Expected O, but got Unknown //IL_090e: Unknown result type (might be due to invalid IL or missing references) //IL_091f: Unknown result type (might be due to invalid IL or missing references) //IL_0929: Expected O, but got Unknown //IL_0929: Expected O, but got Unknown //IL_0939: Unknown result type (might be due to invalid IL or missing references) //IL_094e: Unknown result type (might be due to invalid IL or missing references) //IL_0958: Expected O, but got Unknown //IL_0958: Expected O, but got Unknown //IL_0968: Unknown result type (might be due to invalid IL or missing references) //IL_0983: Unknown result type (might be due to invalid IL or missing references) //IL_098d: Expected O, but got Unknown //IL_098d: Expected O, but got Unknown //IL_099d: Unknown result type (might be due to invalid IL or missing references) //IL_09b2: Unknown result type (might be due to invalid IL or missing references) //IL_09bc: Expected O, but got Unknown //IL_09bc: Expected O, but got Unknown //IL_09cc: Unknown result type (might be due to invalid IL or missing references) //IL_09dd: Unknown result type (might be due to invalid IL or missing references) //IL_09e7: Expected O, but got Unknown //IL_09e7: Expected O, but got Unknown //IL_09f7: Unknown result type (might be due to invalid IL or missing references) //IL_0a08: Unknown result type (might be due to invalid IL or missing references) //IL_0a12: Expected O, but got Unknown //IL_0a12: Expected O, but got Unknown //IL_0a22: Unknown result type (might be due to invalid IL or missing references) //IL_0a33: Unknown result type (might be due to invalid IL or missing references) //IL_0a3d: Expected O, but got Unknown //IL_0a3d: Expected O, but got Unknown //IL_0a4d: Unknown result type (might be due to invalid IL or missing references) //IL_0a5e: Unknown result type (might be due to invalid IL or missing references) //IL_0a68: Expected O, but got Unknown //IL_0a68: Expected O, but got Unknown //IL_0a78: Unknown result type (might be due to invalid IL or missing references) //IL_0a89: Unknown result type (might be due to invalid IL or missing references) //IL_0a93: Expected O, but got Unknown //IL_0a93: Expected O, but got Unknown //IL_0aa3: Unknown result type (might be due to invalid IL or missing references) //IL_0ab4: Unknown result type (might be due to invalid IL or missing references) //IL_0abe: Expected O, but got Unknown //IL_0abe: Expected O, but got Unknown _configFile = configFile; governorType = configFile.Bind(new ConfigDefinition("GeneEngineDriver Variables", "Learning Governor Type"), 0, new ConfigDescription("How the algorithm decides when to learn: 0 - Default, 1 - Time Only, 2 - Death Count Only", (AcceptableValueBase)(object)new AcceptableValueRange(0, 2), Array.Empty())); timeLimit = configFile.Bind(new ConfigDefinition("GeneEngineDriver Variables", "Time Limit"), 60, new ConfigDescription("How many seconds between learnings:", (AcceptableValueBase)(object)new AcceptableValueRange(5, 300), Array.Empty())); deathLimit = configFile.Bind(new ConfigDefinition("GeneEngineDriver Variables", "Death Limit"), 40, new ConfigDescription("How many monster deaths between learnings:", (AcceptableValueBase)(object)new AcceptableValueRange(10, 100), Array.Empty())); maintainIfDisabled = configFile.Bind(new ConfigDefinition("GeneEngineDriver Variables", "Keep Mutations While Disabled"), false, new ConfigDescription("Should the stat mods still be applied if the artifact is disabled mid-run:", (AcceptableValueBase)(object)new AcceptableValueList(new bool[2] { true, false }), Array.Empty())); geneCap = configFile.Bind(new ConfigDefinition("Mutation Variables", "Gene Value Cap"), 10f, new ConfigDescription("Maximum multiplier for any stat:", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 50f), Array.Empty())); geneFloor = configFile.Bind(new ConfigDefinition("Mutation Variables", "Gene Value Floor"), 0.01f, new ConfigDescription("Minimum multiplier for any stat:", (AcceptableValueBase)(object)new AcceptableValueRange(0.01f, 1f), Array.Empty())); geneProductLimit = configFile.Bind(new ConfigDefinition("Mutation Variables", "Gene Product Cap"), 1.5f, new ConfigDescription("Maximum product of all stat multipliers:", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 10f), Array.Empty())); geneVarianceLimit = configFile.Bind(new ConfigDefinition("Mutation Variables", "Gene Variation Limit"), 0.1f, new ConfigDescription("How much a monster can differ from it`s master as a percent: 0.1 is 10% (Bulwark will be 5x this)", (AcceptableValueBase)(object)new AcceptableValueRange(0.01f, 1f), Array.Empty())); enableGeneLimitOverrides = configFile.Bind(new ConfigDefinition("Mutation Override Variables", "Enable Mutation Overrides"), false, new ConfigDescription("Should the mutation overrides be applied, use with caution", (AcceptableValueBase)(object)new AcceptableValueList(new bool[2] { true, false }), Array.Empty())); geneLimitOverrides = configFile.Bind(new ConfigDefinition("Mutation Override Variables", "Gene Limit Overrides"), "MoveSpeed,0.5,2|InvalidName,0.8,NaN", new ConfigDescription("Format is as follows: GeneName1,Floor1,Cap1|GeneName2,Floor2,Cap2 where GeneName is in (MaxHealth,MoveSpeed,AttackSpeed,AttackDamage) and Floor and Cap are parseable numerics", (AcceptableValueBase)null, Array.Empty())); sgdNormTargetTimeToDieSeconds = configFile.Bind(new ConfigDefinition("SGD Sensor Normalization", "Target Time To Die (seconds)"), 10f, new ConfigDescription("Target survival horizon used for normalizing incoming DPS against V_p(defense). Higher => less sensitive.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 60f), Array.Empty())); sgdNormTargetTtkSeconds = configFile.Bind(new ConfigDefinition("SGD Sensor Normalization", "Target Time To Kill (seconds)"), 8f, new ConfigDescription("Target TTK used for normalizing AvgTTK. Higher => less sensitive.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 60f), Array.Empty())); sgdNormHitRateScalePerSecond = configFile.Bind(new ConfigDefinition("SGD Sensor Normalization", "Hit Rate Scale (per second)"), 1.5f, new ConfigDescription("Scale for normalizing hit rate (hits/sec) into [0..1]. Higher => less sensitive.", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 10f), Array.Empty())); sgdHpFloor = configFile.Bind(new ConfigDefinition("SGD Axis Limits", "HP Floor"), 0.5f, new ConfigDescription("Minimum SGD multiplier for MaxHealth axis. Default is log-symmetric with HP Cap around 1.0.", (AcceptableValueBase)(object)new AcceptableValueRange(0.01f, 1f), Array.Empty())); sgdHpCap = configFile.Bind(new ConfigDefinition("SGD Axis Limits", "HP Cap"), 2f, new ConfigDescription("Maximum SGD multiplier for MaxHealth axis. Default is log-symmetric with HP Floor around 1.0.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 50f), Array.Empty())); sgdMsFloor = configFile.Bind(new ConfigDefinition("SGD Axis Limits", "MoveSpeed Floor"), 0.8f, new ConfigDescription("Minimum SGD multiplier for MoveSpeed axis. Kept narrow because move speed changes are highly perceptible.", (AcceptableValueBase)(object)new AcceptableValueRange(0.01f, 1f), Array.Empty())); sgdMsCap = configFile.Bind(new ConfigDefinition("SGD Axis Limits", "MoveSpeed Cap"), 1.25f, new ConfigDescription("Maximum SGD multiplier for MoveSpeed axis. Kept narrow because move speed changes are highly perceptible.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 50f), Array.Empty())); sgdAsFloor = configFile.Bind(new ConfigDefinition("SGD Axis Limits", "AttackSpeed Floor"), 0.6f, new ConfigDescription("Minimum SGD multiplier for AttackSpeed axis. Default is log-symmetric with AttackSpeed Cap around 1.0.", (AcceptableValueBase)(object)new AcceptableValueRange(0.01f, 1f), Array.Empty())); sgdAsCap = configFile.Bind(new ConfigDefinition("SGD Axis Limits", "AttackSpeed Cap"), 1.6667f, new ConfigDescription("Maximum SGD multiplier for AttackSpeed axis. Default is log-symmetric with AttackSpeed Floor around 1.0.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 50f), Array.Empty())); sgdDmgFloor = configFile.Bind(new ConfigDefinition("SGD Axis Limits", "AttackDamage Floor"), 0.6f, new ConfigDescription("Minimum SGD multiplier for AttackDamage axis. Default is log-symmetric with AttackDamage Cap around 1.0.", (AcceptableValueBase)(object)new AcceptableValueRange(0.01f, 1f), Array.Empty())); sgdDmgCap = configFile.Bind(new ConfigDefinition("SGD Axis Limits", "AttackDamage Cap"), 1.6667f, new ConfigDescription("Maximum SGD multiplier for AttackDamage axis. Default is log-symmetric with AttackDamage Floor around 1.0.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 50f), Array.Empty())); telemetryEnabled = configFile.Bind(new ConfigDefinition("Research Telemetry", "Telemetry Enabled"), true, new ConfigDescription("Send anonymous DDA research telemetry to the configured PostHog project. Disable to opt out.", (AcceptableValueBase)null, Array.Empty())); telemetryAnonymousUserId = configFile.Bind(new ConfigDefinition("Research Telemetry", "Anonymous User Id"), "", new ConfigDescription("Anonymous UUID for grouping runs from the same installation. Generated automatically if empty.", (AcceptableValueBase)null, Array.Empty())); if (string.IsNullOrWhiteSpace(telemetryAnonymousUserId.Value)) { telemetryAnonymousUserId.Value = "anon-" + Guid.NewGuid().ToString("N"); configFile.Save(); } telemetryParticipantId = configFile.Bind(new ConfigDefinition("Research Telemetry", "Participant Id"), "", new ConfigDescription("Explicit participant code for thesis experiments. Leave empty to reuse Anonymous User Id.", (AcceptableValueBase)null, Array.Empty())); telemetryExperimentId = configFile.Bind(new ConfigDefinition("Research Telemetry", "Experiment Id"), "thesis_v1", new ConfigDescription("Experiment label used to segment telemetry in a single PostHog project.", (AcceptableValueBase)null, Array.Empty())); telemetryConditionOrder = configFile.Bind(new ConfigDefinition("Research Telemetry", "Condition Order"), "FLS,GA,SGD", new ConfigDescription("Planned condition order for the current participant, e.g. FLS,GA,SGD.", (AcceptableValueBase)null, Array.Empty())); telemetryRunAttemptIndex = configFile.Bind(new ConfigDefinition("Research Telemetry", "Run Attempt Index"), 1, new ConfigDescription("Explicit attempt number within the current participant/condition.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 1000), Array.Empty())); telemetryConfiguredRunSeed = configFile.Bind(new ConfigDefinition("Research Telemetry", "Configured Run Seed"), "", new ConfigDescription("Optional planned run seed or scenario label. Runtime seed is logged separately when available.", (AcceptableValueBase)null, Array.Empty())); telemetrySampleIntervalSeconds = configFile.Bind(new ConfigDefinition("Research Telemetry", "Sample Interval Seconds"), 10f, new ConfigDescription("How often to sample runtime DDA telemetry.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 120f), Array.Empty())); telemetryFlushIntervalSeconds = configFile.Bind(new ConfigDefinition("Research Telemetry", "Flush Interval Seconds"), 20f, new ConfigDescription("How often to flush queued telemetry events to PostHog.", (AcceptableValueBase)(object)new AcceptableValueRange(5f, 300f), Array.Empty())); telemetryMaxQueueSize = configFile.Bind(new ConfigDefinition("Research Telemetry", "Max Queue Size"), 512, new ConfigDescription("Maximum in-memory telemetry events kept before oldest events are dropped.", (AcceptableValueBase)(object)new AcceptableValueRange(32, 5000), Array.Empty())); telemetryJumpThreshold = configFile.Bind(new ConfigDefinition("Research Telemetry", "Jump Threshold"), 0.1f, new ConfigDescription("Absolute multiplier delta treated as a sharp difficulty jump.", (AcceptableValueBase)(object)new AcceptableValueRange(0.01f, 1f), Array.Empty())); telemetryVirtualGapEpsilon = configFile.Bind(new ConfigDefinition("Research Telemetry", "Virtual Gap Epsilon"), 0.5f, new ConfigDescription("Acceptance threshold epsilon_v for |V_c - V_p| in H3.", (AcceptableValueBase)(object)new AcceptableValueRange(0.01f, 10f), Array.Empty())); telemetryStableErrorEpsilon = configFile.Bind(new ConfigDefinition("Research Telemetry", "Stable Error Epsilon"), 0.1f, new ConfigDescription("Stable corridor epsilon_stable for mean alignment error in H4.", (AcceptableValueBase)(object)new AcceptableValueRange(0.01f, 1f), Array.Empty())); telemetryDegradationThreshold = configFile.Bind(new ConfigDefinition("Research Telemetry", "Degradation Threshold"), 0.3f, new ConfigDescription("Stress signal threshold that starts a degradation episode. Calibrated from the pilot distribution around degradation_signal p90.", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 1f), Array.Empty())); telemetryRecoveryThreshold = configFile.Bind(new ConfigDefinition("Research Telemetry", "Recovery Threshold"), 0.25f, new ConfigDescription("Stress signal threshold that ends a degradation episode. Keep below Degradation Threshold to preserve hysteresis.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 0.9f), Array.Empty())); telemetryMinimumSessionSeconds = configFile.Bind(new ConfigDefinition("Research Telemetry", "Minimum Session Seconds"), 300f, new ConfigDescription("Sessions shorter than this are marked as quality-excluded in telemetry.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 7200f), Array.Empty())); researchAutoRotateDdaAlgorithms = configFile.Bind(new ConfigDefinition("Research DDA Rotation", "Auto Rotate Algorithms"), true, new ConfigDescription("Automatically rotate hidden DDA mode on each new run: SGD -> GA -> FLS -> SGD.", (AcceptableValueBase)null, Array.Empty())); researchLastRunDdaAlgorithm = configFile.Bind(new ConfigDefinition("Research DDA Rotation", "Last Run Algorithm"), "None", new ConfigDescription("Last hidden DDA algorithm launched by the research rotator. Do not edit during experiments unless you want to reset the sequence.", (AcceptableValueBase)(object)new AcceptableValueList(new string[4] { "None", "FLS", "GA", "SGD" }), Array.Empty())); researchAutoRotateRunSeeds = configFile.Bind(new ConfigDefinition("Research DDA Rotation", "Auto Rotate Run Seeds"), true, new ConfigDescription("When enabled, keeps one configured run seed for a full FLS -> GA -> SGD cycle, then advances to the next seed.", (AcceptableValueBase)null, Array.Empty())); researchRunSeedCycle = configFile.Bind(new ConfigDefinition("Research DDA Rotation", "Run Seed Cycle"), "8459684015804115075,8821573197706646788,2559340200192868678,97399012779323199,1444060760769064427", new ConfigDescription("Comma-separated list of planned run seeds for thesis experiments. Example: 12345,67890,13579. Empty disables forced seed assignment.", (AcceptableValueBase)null, Array.Empty())); researchCurrentRunSeedIndex = configFile.Bind(new ConfigDefinition("Research DDA Rotation", "Current Run Seed Index"), 0, new ConfigDescription("Index in Run Seed Cycle currently used by the hidden research rotator. Do not edit during experiments unless you want to reset the sequence.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 1000000), Array.Empty())); researchCurrentRunSeed = configFile.Bind(new ConfigDefinition("Research DDA Rotation", "Current Run Seed"), "", new ConfigDescription("Current planned run seed used for the active FLS -> GA -> SGD cycle. Stored to survive client restarts.", (AcceptableValueBase)null, Array.Empty())); diagnosticsEnableGeneTokenCalcHooks = configFile.Bind(new ConfigDefinition("Diagnostics", "Enable GeneTokenCalc Hooks"), false, new ConfigDescription("Enable RecalculateStats hooks (GeneTokenCalc). Keep disabled while diagnosing repeat-run startup errors.", (AcceptableValueBase)null, Array.Empty())); diagnosticsEnableGeneticEngineHooks = configFile.Bind(new ConfigDefinition("Diagnostics", "Enable GeneticEngine Hooks"), false, new ConfigDescription("Enable GeneticEngine hooks (GeneEngineDriver). Keep disabled while diagnosing repeat-run startup errors.", (AcceptableValueBase)null, Array.Empty())); diagnosticsEnableSgdHooks = configFile.Bind(new ConfigDefinition("Diagnostics", "Enable SGD Hooks"), true, new ConfigDescription("Enable SGD runtime + sensors hooks. Keep disabled while diagnosing repeat-run startup errors.", (AcceptableValueBase)null, Array.Empty())); diagnosticsEnableSgdActuatorsHooks = configFile.Bind(new ConfigDefinition("Diagnostics", "Enable SGD Actuators Hooks"), false, new ConfigDescription("Enable SGD actuators hooks. Keep disabled while diagnosing repeat-run startup errors.", (AcceptableValueBase)null, Array.Empty())); diagnosticsEnableTelemetryHooks = configFile.Bind(new ConfigDefinition("Diagnostics", "Enable Telemetry Hooks"), true, new ConfigDescription("Enable telemetry hooks (dda_sample/session_end/etc). Keep disabled while diagnosing repeat-run startup errors.", (AcceptableValueBase)null, Array.Empty())); diagnosticsEnableRunModeRotatorHooks = configFile.Bind(new ConfigDefinition("Diagnostics", "Enable Research Rotator Hooks"), true, new ConfigDescription("Enable research run mode rotator hooks. Keep disabled while diagnosing repeat-run startup errors.", (AcceptableValueBase)null, Array.Empty())); MigrateLegacyTelemetryThresholds(); } private static void MigrateLegacyTelemetryThresholds() { if (telemetryDegradationThreshold == null || telemetryRecoveryThreshold == null) { return; } bool flag = false; if (Approximately(telemetryDegradationThreshold.Value, 0.7f)) { telemetryDegradationThreshold.Value = 0.3f; flag = true; } if (Approximately(telemetryRecoveryThreshold.Value, 0.35f)) { telemetryRecoveryThreshold.Value = 0.25f; flag = true; } if (flag) { ManualLogSource geneticLogSource = GeneticsArtifactPlugin.geneticLogSource; if (geneticLogSource != null) { geneticLogSource.LogInfo((object)("[Telemetry] Migrated H4 thresholds to pilot-calibrated values: degradation=" + 0.3f.ToString("0.###", CultureInfo.InvariantCulture) + ", recovery=" + 0.25f.ToString("0.###", CultureInfo.InvariantCulture))); } Save(); } } private static bool Approximately(float a, float b) { return Math.Abs(a - b) <= 0.0001f; } public static void Save() { ConfigFile configFile = _configFile; if (configFile != null) { configFile.Save(); } } } public enum GovernorType { Default, TimeOnly, DeathsOnly } public class RiskOfOptionsCompat { public static void Init() { //IL_0014: 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_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Expected O, but got Unknown //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Expected O, but got Unknown //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Expected O, but got Unknown //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Expected O, but got Unknown //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Expected O, but got Unknown //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: 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_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Expected O, but got Unknown //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Expected O, but got Unknown //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Expected O, but got Unknown //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Expected O, but got Unknown //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Expected O, but got Unknown //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Expected O, but got Unknown //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Expected O, but got Unknown //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Expected O, but got Unknown //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Expected O, but got Unknown //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Expected O, but got Unknown //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: 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_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_01f8: Expected O, but got Unknown //IL_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Expected O, but got Unknown //IL_0202: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Unknown result type (might be due to invalid IL or missing references) //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_021d: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Expected O, but got Unknown //IL_0228: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Expected O, but got Unknown //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Unknown result type (might be due to invalid IL or missing references) //IL_0247: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Unknown result type (might be due to invalid IL or missing references) //IL_0262: Expected O, but got Unknown //IL_025d: Unknown result type (might be due to invalid IL or missing references) //IL_0267: Expected O, but got Unknown //IL_026c: Unknown result type (might be due to invalid IL or missing references) //IL_0271: Unknown result type (might be due to invalid IL or missing references) //IL_027c: Unknown result type (might be due to invalid IL or missing references) //IL_0287: Unknown result type (might be due to invalid IL or missing references) //IL_0297: Expected O, but got Unknown //IL_0292: Unknown result type (might be due to invalid IL or missing references) //IL_029c: Expected O, but got Unknown //IL_02a1: Unknown result type (might be due to invalid IL or missing references) //IL_02a6: Unknown result type (might be due to invalid IL or missing references) //IL_02b1: Unknown result type (might be due to invalid IL or missing references) //IL_02bc: Unknown result type (might be due to invalid IL or missing references) //IL_02cc: Expected O, but got Unknown //IL_02c7: Unknown result type (might be due to invalid IL or missing references) //IL_02d1: Expected O, but got Unknown //IL_02d6: Unknown result type (might be due to invalid IL or missing references) //IL_02db: Unknown result type (might be due to invalid IL or missing references) //IL_02e6: Unknown result type (might be due to invalid IL or missing references) //IL_02f1: Unknown result type (might be due to invalid IL or missing references) //IL_0301: Expected O, but got Unknown //IL_02fc: Unknown result type (might be due to invalid IL or missing references) //IL_0306: Expected O, but got Unknown //IL_030b: Unknown result type (might be due to invalid IL or missing references) //IL_0315: Expected O, but got Unknown //IL_031a: Unknown result type (might be due to invalid IL or missing references) //IL_0324: Expected O, but got Unknown ModSettingsManager.SetModIcon(ArtifactOfGenetics.artifactDef.smallIconSelectedSprite); ModSettingsManager.AddOption((BaseOption)new IntSliderOption(ConfigManager.governorType, new IntSliderConfig { min = 0, max = 2 })); ModSettingsManager.AddOption((BaseOption)new IntSliderOption(ConfigManager.timeLimit, new IntSliderConfig { min = 5, max = 300 })); ModSettingsManager.AddOption((BaseOption)new IntSliderOption(ConfigManager.deathLimit, new IntSliderConfig { min = 10, max = 100 })); ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(ConfigManager.maintainIfDisabled)); ModSettingsManager.AddOption((BaseOption)new SliderOption(ConfigManager.geneCap, new SliderConfig { min = 1f, max = 50f, formatString = "{0:#0.##}x" })); ModSettingsManager.AddOption((BaseOption)new SliderOption(ConfigManager.geneFloor, new SliderConfig { min = 0.01f, max = 1f, formatString = "{0:0.##}x" })); ModSettingsManager.AddOption((BaseOption)new SliderOption(ConfigManager.geneProductLimit, new SliderConfig { min = 1f, max = 10f, formatString = "{0:#0.##}x" })); ModSettingsManager.AddOption((BaseOption)new SliderOption(ConfigManager.geneVarianceLimit, new SliderConfig { min = 0.01f, max = 1f, formatString = "{0:#0.##%}" })); ModSettingsManager.AddOption((BaseOption)new SliderOption(ConfigManager.sgdHpFloor, new SliderConfig { min = 0.01f, max = 1f, formatString = "{0:0.##}x" })); ModSettingsManager.AddOption((BaseOption)new SliderOption(ConfigManager.sgdHpCap, new SliderConfig { min = 1f, max = 50f, formatString = "{0:#0.##}x" })); ModSettingsManager.AddOption((BaseOption)new SliderOption(ConfigManager.sgdMsFloor, new SliderConfig { min = 0.01f, max = 1f, formatString = "{0:0.##}x" })); ModSettingsManager.AddOption((BaseOption)new SliderOption(ConfigManager.sgdMsCap, new SliderConfig { min = 1f, max = 50f, formatString = "{0:#0.##}x" })); ModSettingsManager.AddOption((BaseOption)new SliderOption(ConfigManager.sgdAsFloor, new SliderConfig { min = 0.01f, max = 1f, formatString = "{0:0.##}x" })); ModSettingsManager.AddOption((BaseOption)new SliderOption(ConfigManager.sgdAsCap, new SliderConfig { min = 1f, max = 50f, formatString = "{0:#0.##}x" })); ModSettingsManager.AddOption((BaseOption)new SliderOption(ConfigManager.sgdDmgFloor, new SliderConfig { min = 0.01f, max = 1f, formatString = "{0:0.##}x" })); ModSettingsManager.AddOption((BaseOption)new SliderOption(ConfigManager.sgdDmgCap, new SliderConfig { min = 1f, max = 50f, formatString = "{0:#0.##}x" })); ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(ConfigManager.enableGeneLimitOverrides)); ModSettingsManager.AddOption((BaseOption)new StringInputFieldOption(ConfigManager.geneLimitOverrides)); } } public class GeneEngineDriver : NetworkBehaviour { public static GeneEngineDriver instance; public static List masterGenes; public static List livingGenes; public static List deadGenes; public static float timeSinceLastLearning; public static Dictionary geneLimitOverrides; public event EventHandler GEDPostLearningEvent; public static void RegisterHooks() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown Run.Start += new hook_Start(Run_Start); CharacterBody.Start += new hook_Start(CharacterBody_Start); HealthComponent.TakeDamage += new hook_TakeDamage(HealthComponent_TakeDamage); } private static void Run_Start(orig_Start orig, Run self) { orig.Invoke(self); if (NetworkServer.active && DdaAlgorithmState.ShouldRunGeneticEngine()) { ((Component)self).gameObject.AddComponent(); } } private static void CharacterBody_Start(orig_Start orig, CharacterBody self) { //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Invalid comparison between Unknown and I4 //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: 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) orig.Invoke(self); if (!NetworkServer.active || !DdaAlgorithmState.ShouldRunGeneticEngine()) { return; } if ((Object)(object)instance == (Object)null) { ((Component)Run.instance).gameObject.AddComponent(); GeneticsArtifactPlugin.geneticLogSource.LogWarning((object)"GeneEngineDriver Emergency Activation! Wasn't ready for a body yet."); } if ((int)self.teamComponent.teamIndex == 2 && Object.op_Implicit((Object)(object)self.inventory)) { if (!masterGenes.Exists((MasterGeneBehaviour x) => x.bodyIndex == self.bodyIndex)) { MasterGeneBehaviour masterGeneBehaviour = new MasterGeneBehaviour(); masterGeneBehaviour.Init(); masterGeneBehaviour.bodyIndex = self.bodyIndex; masterGenes.Add(masterGeneBehaviour); GeneticsArtifactPlugin.geneticLogSource.LogInfo((object)("Generated a Master Template for: " + BodyCatalog.GetBodyName(self.bodyIndex))); } MonsterGeneBehaviour monsterGeneBehaviour = ((Component)self).gameObject.AddComponent(); if (((Object)(object)RunArtifactManager.instance != (Object)null && RunArtifactManager.instance.IsArtifactEnabled(ArtifactOfGenetics.artifactDef)) || ConfigManager.researchAutoRotateDdaAlgorithms.Value) { monsterGeneBehaviour.MutateFromMaster(); monsterGeneBehaviour.characterBody.RecalculateStats(); } else { monsterGeneBehaviour.CopyFromMaster(); } } } private static void HealthComponent_TakeDamage(orig_TakeDamage orig, HealthComponent self, DamageInfo damageInfo) { orig.Invoke(self, damageInfo); if (!NetworkServer.active || !DdaAlgorithmState.ShouldRunGeneticEngine()) { return; } GameObject attacker = damageInfo.attacker; if (attacker != null) { if (!((Object)(object)attacker != (Object)null)) { return; } CharacterBody attackerBody = attacker.GetComponent(); if (attackerBody == null || !((Object)(object)attackerBody != (Object)null)) { return; } Inventory inventory = attackerBody.inventory; if (inventory != null && inventory.GetItemCount(GeneTokens.blockerDef) == 0) { MonsterGeneBehaviour monsterGeneBehaviour = livingGenes.Find((MonsterGeneBehaviour x) => (Object)(object)x.characterBody == (Object)(object)attackerBody); if ((Object)(object)monsterGeneBehaviour != (Object)null) { monsterGeneBehaviour.damageDealt += damageInfo.damage; } } return; } GameObject inflictor = damageInfo.inflictor; if (inflictor == null) { return; } if (!((Object)(object)inflictor != (Object)null)) { return; } CharacterBody inflictorBody = inflictor.GetComponent(); if (inflictorBody == null || !((Object)(object)inflictorBody != (Object)null)) { return; } Inventory inventory2 = inflictorBody.inventory; if (inventory2 != null && inventory2.GetItemCount(GeneTokens.blockerDef) == 0) { MonsterGeneBehaviour monsterGeneBehaviour2 = livingGenes.Find((MonsterGeneBehaviour x) => (Object)(object)x.characterBody == (Object)(object)inflictorBody); if ((Object)(object)monsterGeneBehaviour2 != (Object)null) { monsterGeneBehaviour2.damageDealt += damageInfo.damage; } } } public void Awake() { if ((Object)(object)instance == (Object)null) { instance = this; } if (NetworkServer.active) { masterGenes = new List(); livingGenes = new List(); deadGenes = new List(); RegenerateGeneLimitOverrides(); } } public void Update() { if (!NetworkServer.active) { return; } timeSinceLastLearning += Time.deltaTime; switch (ConfigManager.governorType.Value) { case 1: if (timeSinceLastLearning >= (float)ConfigManager.timeLimit.Value) { Learn(); } break; case 2: if (deadGenes.Count >= ConfigManager.deathLimit.Value) { Learn(); } break; default: if (timeSinceLastLearning >= (float)ConfigManager.timeLimit.Value || deadGenes.Count >= ConfigManager.deathLimit.Value) { Learn(); } break; } } public void Learn() { foreach (MasterGeneBehaviour masterGene in masterGenes) { masterGene.MutateFromChildren(); } deadGenes.Clear(); timeSinceLastLearning = 0f; this.GEDPostLearningEvent?.Invoke(this, new EventArgs()); } public void RegenerateGeneLimitOverrides() { geneLimitOverrides = new Dictionary(); if (!ConfigManager.enableGeneLimitOverrides.Value || string.IsNullOrEmpty(ConfigManager.geneLimitOverrides.Value)) { return; } string[] array = ConfigManager.geneLimitOverrides.Value.Trim().Split('|'); foreach (string text in array) { string[] array2 = text.Split(','); if (Enum.TryParse(array2[0], ignoreCase: true, out var result) && float.TryParse(array2[1], out var result2) && result2 <= 1f && float.TryParse(array2[2], out var result3) && result3 >= 1f) { try { geneLimitOverrides.Add(result, (result2, result3)); GeneticsArtifactPlugin.geneticLogSource.LogInfo((object)("Adding Valid GeneOverride: " + text)); } catch { goto IL_00be; } continue; } goto IL_00be; IL_00be: GeneticsArtifactPlugin.geneticLogSource.LogWarning((object)("Skipping Invalid GeneOverride: " + text)); } } } public class GeneTokenCalc { public static void RegisterHooks() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown RecalculateStatsAPI.GetStatCoefficients += new StatHookEventHandler(RecalculateStatsAPI_GetStatCoefficients); } private static void RecalculateStatsAPI_GetStatCoefficients(CharacterBody sender, StatHookEventArgs args) { Inventory inventory = sender.inventory; if (inventory != null && inventory.GetItemCount(GeneTokens.blockerDef) == 0) { args.baseHealthAdd += GetStatValueToAdd(sender, GeneStat.MaxHealth); args.baseMoveSpeedAdd += GetStatValueToAdd(sender, GeneStat.MoveSpeed); args.baseAttackSpeedAdd += GetStatValueToAdd(sender, GeneStat.AttackSpeed); args.baseDamageAdd += GetStatValueToAdd(sender, GeneStat.AttackDamage); } } public static float GetGeneMultiplier(CharacterBody body, GeneStat statType) { float num = 0.01f; Inventory inventory = body.inventory; float num2 = 1f + (num * (float?)((inventory != null) ? new int?(inventory.GetItemCount(GeneTokens.tokenDict[statType][GeneMod.Plus1])) : null)).GetValueOrDefault(); num = 0.01f; Inventory inventory2 = body.inventory; return num2 - (num * (float?)((inventory2 != null) ? new int?(inventory2.GetItemCount(GeneTokens.tokenDict[statType][GeneMod.Minus1])) : null)).GetValueOrDefault(); } public static float GetStatValueToAdd(CharacterBody body, GeneStat statType) { float num = 0f; switch (statType) { case GeneStat.MaxHealth: num = body.baseMaxHealth + body.levelMaxHealth * body.level; break; case GeneStat.MoveSpeed: num = body.baseMoveSpeed + body.levelMoveSpeed * body.level; break; case GeneStat.AttackSpeed: num = body.baseAttackSpeed + body.levelAttackSpeed * body.level; break; case GeneStat.AttackDamage: num = body.baseDamage + body.levelDamage * body.level; break; } return num * GetGeneMultiplier(body, statType) - num; } public static Dictionary GetTokensToAdd(Dictionary oldValues, Dictionary newValues) { Dictionary dictionary = new Dictionary(); Dictionary dictionary2 = new Dictionary(); foreach (GeneStat value in Enum.GetValues(typeof(GeneStat))) { dictionary2.Add(value, newValues[value] - oldValues[value]); } foreach (GeneStat value2 in Enum.GetValues(typeof(GeneStat))) { if (dictionary2[value2] > 0f) { dictionary.Add(GeneTokens.tokenDict[value2][GeneMod.Plus1], (int)(dictionary2[value2] * 100f)); } else { dictionary.Add(GeneTokens.tokenDict[value2][GeneMod.Minus1], (int)(dictionary2[value2] * -100f)); } } return dictionary; } } public class GeneTokens { public static Dictionary> tokenDict; public static ItemDef blockerDef; public static void Init() { LanguageAPI.Add("GENETIC_EMPTY_TOKEN", "This is better than null I guess"); tokenDict = new Dictionary>(); foreach (GeneStat value in Enum.GetValues(typeof(GeneStat))) { tokenDict.Add(value, new Dictionary()); foreach (GeneMod value2 in Enum.GetValues(typeof(GeneMod))) { ItemDef val = ScriptableObject.CreateInstance(); ((Object)val).name = "GENETOKEN_" + value.ToString().ToUpper() + "_" + value2.ToString().ToUpper(); val.nameToken = "GENETIC_EMPTY_TOKEN"; val.pickupToken = "GENETIC_EMPTY_TOKEN"; val.descriptionToken = "GENETIC_EMPTY_TOKEN"; val.loreToken = "GENETIC_EMPTY_TOKEN"; val.pickupIconSprite = null; val.pickupModelPrefab = null; val.tags = (ItemTag[])(object)new ItemTag[2] { (ItemTag)13, (ItemTag)12 }; Reflection.SetFieldValue((object)val, "deprecatedTier", (ItemTier)5); val.hidden = true; val.canRemove = false; ContentAddition.AddItemDef(val); tokenDict[value].Add(value2, val); } } blockerDef = ScriptableObject.CreateInstance(); ((Object)blockerDef).name = "GENETOKEN_BLOCKER"; blockerDef.nameToken = "GENETIC_EMPTY_TOKEN"; blockerDef.pickupToken = "GENETIC_EMPTY_TOKEN"; blockerDef.descriptionToken = "GENETIC_EMPTY_TOKEN"; blockerDef.loreToken = "GENETIC_EMPTY_TOKEN"; blockerDef.pickupIconSprite = null; blockerDef.pickupModelPrefab = null; blockerDef.tags = (ItemTag[])(object)new ItemTag[2] { (ItemTag)13, (ItemTag)12 }; Reflection.SetFieldValue((object)blockerDef, "deprecatedTier", (ItemTier)5); blockerDef.hidden = true; blockerDef.canRemove = false; ContentAddition.AddItemDef(blockerDef); } } public enum GeneStat { MaxHealth, MoveSpeed, AttackSpeed, AttackDamage } public enum GeneMod { Plus1, Minus1 } public class MasterGeneBehaviour { public BodyIndex bodyIndex; public Dictionary templateGenes; public event EventHandler MaGBPostCreationEvent; public event EventHandler MaGBPostMutationEvent; public void Init() { templateGenes = new Dictionary(); foreach (GeneStat value in Enum.GetValues(typeof(GeneStat))) { templateGenes.Add(value, 1f); } this.MaGBPostCreationEvent?.Invoke(this, new EventArgs()); } public void MutateFromChildren() { List list = GeneEngineDriver.deadGenes.Where((MonsterGeneBehaviour x) => x.bodyIndex == bodyIndex && x.score > 0f).ToList(); foreach (GeneStat value in Enum.GetValues(typeof(GeneStat))) { float num = 0f; float num2 = 0f; foreach (MonsterGeneBehaviour item in list) { num2 += item.currentGenes[value] * item.score; num += item.score; } if (num > 0f) { templateGenes[value] = (float)decimal.Round((decimal)(num2 / num), 2); } } this.MaGBPostMutationEvent?.Invoke(this, new EventArgs()); } } public class MonsterGeneBehaviour : MonoBehaviour { public BodyIndex bodyIndex; public Dictionary currentGenes; public CharacterBody characterBody; public float timeAlive; public float timeEngaged; public float damageDealt; public float score; public event EventHandler MoGBPostMutationEvent; public event EventHandler MoGBPostScoringEvent; public void Awake() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) characterBody = ((Component)this).gameObject.GetComponent(); bodyIndex = characterBody.bodyIndex; InitializeCurrentGenes(); GeneEngineDriver.livingGenes.Add(this); } public void Update() { timeAlive += Time.deltaTime; if (!characterBody.outOfCombat) { timeEngaged += Time.deltaTime; } } public void MutateFromMaster() { CopyFromMaster(); MutateSelf(); } public void CopyFromMaster() { MasterGeneBehaviour masterGeneBehaviour = GeneEngineDriver.masterGenes.Find((MasterGeneBehaviour x) => x.bodyIndex == bodyIndex); AdaptToNewGenes(masterGeneBehaviour.templateGenes); } public void MutateSelf() { Dictionary attempt = GenerateMutationAttempt(); attempt = CorrectOvermutation(attempt); AdaptToNewGenes(attempt); this.MoGBPostMutationEvent?.Invoke(this, new EventArgs()); } private Dictionary CorrectOvermutation(Dictionary attempt) { while (CalculateGeneProduct(attempt) > ConfigManager.geneProductLimit.Value) { attempt[attempt.Aggregate((KeyValuePair x, KeyValuePair y) => (!(x.Value > y.Value)) ? y : x).Key] -= 0.05f; } return attempt; } private float CalculateGeneProduct(Dictionary testValues) { float num = 1f; foreach (float value in testValues.Values) { num *= value; } return num; } public void LogDebugInfo() { GeneticsArtifactPlugin.geneticLogSource.LogInfo((object)(Stage.instance.sceneDef.baseSceneName + " " + ((Object)characterBody).name + " " + currentGenes[GeneStat.MaxHealth] + " " + currentGenes[GeneStat.MoveSpeed] + " " + currentGenes[GeneStat.AttackSpeed] + " " + currentGenes[GeneStat.AttackDamage])); } private void InitializeCurrentGenes() { currentGenes = new Dictionary(); foreach (GeneStat value in Enum.GetValues(typeof(GeneStat))) { currentGenes.Add(value, 1f); } } public void AdaptToNewGenes(Dictionary newGenes) { foreach (KeyValuePair item in GeneTokenCalc.GetTokensToAdd(currentGenes, newGenes)) { characterBody.inventory.GiveItem(item.Key, item.Value); } currentGenes = newGenes; } private Dictionary GenerateMutationAttempt() { Dictionary dictionary = new Dictionary(); float num = ConfigManager.geneVarianceLimit.Value * (float)((!(Stage.instance.sceneDef.baseSceneName == "artifactworld")) ? 1 : 5); foreach (GeneStat key in currentGenes.Keys) { float num2 = currentGenes[key]; if (ConfigManager.enableGeneLimitOverrides.Value && GeneEngineDriver.geneLimitOverrides.ContainsKey(key)) { dictionary.Add(key, (float)decimal.Round((decimal)Mathf.Clamp(Random.Range(num2 * (1f - num), num2 * (1f + num)), GeneEngineDriver.geneLimitOverrides[key].Item1, GeneEngineDriver.geneLimitOverrides[key].Item2), 2)); } else { dictionary.Add(key, (float)decimal.Round((decimal)Mathf.Clamp(Random.Range(num2 * (1f - num), num2 * (1f + num)), ConfigManager.geneFloor.Value, ConfigManager.geneCap.Value), 2)); } } return dictionary; } private void OnDestroy() { ScoreMe(); GeneEngineDriver.livingGenes.Remove(this); GeneEngineDriver.deadGenes.Add(this); } public float ScoreMe() { score = 0f; if (timeAlive > 0f && timeEngaged > 0f) { float num = timeEngaged / timeAlive; score = damageDealt * num; } this.MoGBPostScoringEvent?.Invoke(this, new EventArgs()); return score; } } [BepInPlugin("com.RicoValdezio.ArtifactOfGenetics", "PainGradient: Gradient-Descent DDA", "4.5.12")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] public class GeneticsArtifactPlugin : BaseUnityPlugin { public const string ModVer = "4.5.12"; public const string ModName = "PainGradient: Gradient-Descent DDA"; public const string ModGuid = "com.RicoValdezio.ArtifactOfGenetics"; public static GeneticsArtifactPlugin Instance; public static ManualLogSource geneticLogSource; public static AssetBundle geneticAssetBundle; private void Awake() { if ((Object)(object)Instance == (Object)null) { Instance = this; } geneticLogSource = ((BaseUnityPlugin)Instance).Logger; geneticAssetBundle = AssetBundle.LoadFromStream(Assembly.GetExecutingAssembly().GetManifestResourceStream("GeneticsArtifact.ArtifactResources.genetics")); ConfigManager.Init(((BaseUnityPlugin)this).Config); DdaCheatManager.Init(); ArtifactOfGenetics.Init(); GeneTokens.Init(); ManualLogSource obj = geneticLogSource; if (obj != null) { obj.LogInfo((object)("[DDA] Diagnostics flags: GeneTokenCalc=" + ConfigManager.diagnosticsEnableGeneTokenCalcHooks.Value + ", GeneticEngine=" + ConfigManager.diagnosticsEnableGeneticEngineHooks.Value + ", SGD=" + ConfigManager.diagnosticsEnableSgdHooks.Value + ", SgdActuators=" + ConfigManager.diagnosticsEnableSgdActuatorsHooks.Value + ", Telemetry=" + ConfigManager.diagnosticsEnableTelemetryHooks.Value + ", Rotator=" + ConfigManager.diagnosticsEnableRunModeRotatorHooks.Value)); } if (ConfigManager.diagnosticsEnableGeneTokenCalcHooks.Value) { GeneTokenCalc.RegisterHooks(); } if (ConfigManager.diagnosticsEnableGeneticEngineHooks.Value) { GeneEngineDriver.RegisterHooks(); } if (ConfigManager.diagnosticsEnableSgdHooks.Value) { SgdRuntimeDriver.RegisterHooks(); } if (ConfigManager.diagnosticsEnableSgdActuatorsHooks.Value) { SgdActuatorsHooks.RegisterHooks(); } if (ConfigManager.diagnosticsEnableTelemetryHooks.Value) { TelemetryRuntimeDriver.RegisterHooks(); } if (ConfigManager.diagnosticsEnableRunModeRotatorHooks.Value) { DdaRunModeRotator.RegisterHooks(); } foreach (PluginInfo value in Chainloader.PluginInfos.Values) { if (value.Metadata.GUID.Equals("com.rune580.riskofoptions")) { RiskOfOptionsCompat.Init(); break; } } } } } namespace GeneticsArtifact.Telemetry { internal readonly struct H3AxisQualitySnapshot { public readonly int PairCountHp; public readonly int PairCountMoveSpeed; public readonly int PairCountAttackSpeed; public readonly int PairCountAttackDamage; public readonly int NonzeroDvcCountHp; public readonly int NonzeroDvcCountMoveSpeed; public readonly int NonzeroDvcCountAttackSpeed; public readonly int NonzeroDvcCountAttackDamage; public readonly bool HasVarianceHp; public readonly bool HasVarianceMoveSpeed; public readonly bool HasVarianceAttackSpeed; public readonly bool HasVarianceAttackDamage; public H3AxisQualitySnapshot(int pairCountHp, int pairCountMoveSpeed, int pairCountAttackSpeed, int pairCountAttackDamage, int nonzeroDvcCountHp, int nonzeroDvcCountMoveSpeed, int nonzeroDvcCountAttackSpeed, int nonzeroDvcCountAttackDamage, bool hasVarianceHp, bool hasVarianceMoveSpeed, bool hasVarianceAttackSpeed, bool hasVarianceAttackDamage) { PairCountHp = pairCountHp; PairCountMoveSpeed = pairCountMoveSpeed; PairCountAttackSpeed = pairCountAttackSpeed; PairCountAttackDamage = pairCountAttackDamage; NonzeroDvcCountHp = nonzeroDvcCountHp; NonzeroDvcCountMoveSpeed = nonzeroDvcCountMoveSpeed; NonzeroDvcCountAttackSpeed = nonzeroDvcCountAttackSpeed; NonzeroDvcCountAttackDamage = nonzeroDvcCountAttackDamage; HasVarianceHp = hasVarianceHp; HasVarianceMoveSpeed = hasVarianceMoveSpeed; HasVarianceAttackSpeed = hasVarianceAttackSpeed; HasVarianceAttackDamage = hasVarianceAttackDamage; } } internal readonly struct H3AxisDecisionSnapshot { public readonly string Mode; public readonly int StepIndex; public readonly bool IsDecisionStep; public readonly string StepReason; public readonly string DeltaSource; public readonly float StepIntervalSeconds; public readonly SgdVirtualPowerSample ObservedVirtualPower; public readonly SgdVirtualPowerSample BaselineVirtualPower; public readonly SgdVirtualPowerSample VirtualPower; public readonly SgdVirtualPowerSample VirtualChallenge; public readonly SgdVirtualPowerSample DeltaVirtualPower; public readonly SgdVirtualPowerSample DeltaVirtualChallenge; public H3AxisDecisionSnapshot(string mode, int stepIndex, bool isDecisionStep, string stepReason, float stepIntervalSeconds, in SgdVirtualPowerSample observedVirtualPower, in SgdVirtualPowerSample baselineVirtualPower, in SgdVirtualPowerSample virtualPower, in SgdVirtualPowerSample virtualChallenge, in SgdVirtualPowerSample deltaVirtualPower, in SgdVirtualPowerSample deltaVirtualChallenge) { Mode = mode ?? ""; StepIndex = stepIndex; IsDecisionStep = isDecisionStep; StepReason = stepReason ?? "no_step"; DeltaSource = "decision_step"; StepIntervalSeconds = stepIntervalSeconds; ObservedVirtualPower = observedVirtualPower; BaselineVirtualPower = baselineVirtualPower; VirtualPower = virtualPower; VirtualChallenge = virtualChallenge; DeltaVirtualPower = deltaVirtualPower; DeltaVirtualChallenge = deltaVirtualChallenge; } } internal static class H3AxisDecisionState { private const float ChangeEpsilon = 0.0001f; private const float NonzeroDvcEpsilon = 1E-06f; private const float VarianceEpsilon = 1E-08f; private static bool _hasModeState; private static bool _hasBaselineVirtualPower; private static bool _hasPreviousDecision; private static string _mode = ""; private static int _stepIndex; private static int _lastSgdSteps; private static int _lastGaLearnSteps; private static SgdVirtualPowerSample _baselineVirtualPower; private static SgdVirtualPowerSample _previousDecisionVirtualPower; private static SgdVirtualPowerSample _previousDecisionVirtualChallenge; private static SgdVirtualPowerSample _lastObservedVirtualChallenge; private static int _pairCountHp; private static int _pairCountMoveSpeed; private static int _pairCountAttackSpeed; private static int _pairCountAttackDamage; private static int _nonzeroDvcCountHp; private static int _nonzeroDvcCountMoveSpeed; private static int _nonzeroDvcCountAttackSpeed; private static int _nonzeroDvcCountAttackDamage; private static float _sumDvpHp; private static float _sumDvpMoveSpeed; private static float _sumDvpAttackSpeed; private static float _sumDvpAttackDamage; private static float _sumDvpSqHp; private static float _sumDvpSqMoveSpeed; private static float _sumDvpSqAttackSpeed; private static float _sumDvpSqAttackDamage; private static float _sumDvcHp; private static float _sumDvcMoveSpeed; private static float _sumDvcAttackSpeed; private static float _sumDvcAttackDamage; private static float _sumDvcSqHp; private static float _sumDvcSqMoveSpeed; private static float _sumDvcSqAttackSpeed; private static float _sumDvcSqAttackDamage; public static void Reset() { _hasModeState = false; _hasBaselineVirtualPower = false; _hasPreviousDecision = false; _mode = ""; _stepIndex = 0; _lastSgdSteps = 0; _lastGaLearnSteps = 0; _baselineVirtualPower = default(SgdVirtualPowerSample); _previousDecisionVirtualPower = default(SgdVirtualPowerSample); _previousDecisionVirtualChallenge = default(SgdVirtualPowerSample); _lastObservedVirtualChallenge = default(SgdVirtualPowerSample); ResetAxisQuality(); } public static SgdVirtualPowerSample ComputeVirtualChallengeAxes(TelemetryDifficultySnapshot snapshot) { return new SgdVirtualPowerSample(ToVirtualChallenge(GeneStat.MaxHealth, snapshot.MaxHealth), ToVirtualChallenge(GeneStat.MoveSpeed, snapshot.MoveSpeed), ToVirtualChallenge(GeneStat.AttackSpeed, snapshot.AttackSpeed), ToVirtualChallenge(GeneStat.AttackDamage, snapshot.AttackDamage)); } public static H3AxisDecisionSnapshot BuildSnapshot(string mode, in SgdVirtualPowerSample observedVirtualPower, in SgdVirtualPowerSample virtualChallenge) { mode = (string.IsNullOrWhiteSpace(mode) ? DdaAlgorithmState.GetTelemetryMode() : mode); int totalStepsDone = SgdDecisionRuntimeState.TotalStepsDone; int totalLearnSteps = H3GaDecisionObserver.TotalLearnSteps; if (!_hasModeState || _mode != mode) { ResetModeState(mode, totalStepsDone, totalLearnSteps); } if (!_hasBaselineVirtualPower) { _baselineVirtualPower = Sanitize(in observedVirtualPower); _hasBaselineVirtualPower = true; } SgdVirtualPowerSample a = Sanitize(in observedVirtualPower); SgdVirtualPowerSample virtualChallenge2 = Sanitize(in virtualChallenge); SgdVirtualPowerSample virtualPower = Subtract(in a, in _baselineVirtualPower); string reason; bool flag = DetermineDecisionStep(mode, totalStepsDone, totalLearnSteps, in virtualChallenge2, out reason); SgdVirtualPowerSample deltaVirtualPower = default(SgdVirtualPowerSample); SgdVirtualPowerSample deltaVirtualChallenge = default(SgdVirtualPowerSample); int stepIndex = _stepIndex; bool hasPreviousDecision = _hasPreviousDecision; if (flag) { stepIndex = _stepIndex + 1; deltaVirtualPower = (hasPreviousDecision ? Subtract(in virtualPower, in _previousDecisionVirtualPower) : default(SgdVirtualPowerSample)); deltaVirtualChallenge = (hasPreviousDecision ? Subtract(in virtualChallenge2, in _previousDecisionVirtualChallenge) : default(SgdVirtualPowerSample)); if (hasPreviousDecision) { RecordAxisPair(in deltaVirtualPower, in deltaVirtualChallenge); } _stepIndex = stepIndex; _previousDecisionVirtualPower = virtualPower; _previousDecisionVirtualChallenge = virtualChallenge2; _hasPreviousDecision = true; } _lastSgdSteps = totalStepsDone; _lastGaLearnSteps = totalLearnSteps; _lastObservedVirtualChallenge = virtualChallenge2; return new H3AxisDecisionSnapshot(mode, stepIndex, flag, reason, GetStepIntervalSeconds(mode), in a, in _baselineVirtualPower, in virtualPower, in virtualChallenge2, in deltaVirtualPower, in deltaVirtualChallenge); } public static H3AxisQualitySnapshot GetQualitySnapshot() { return new H3AxisQualitySnapshot(_pairCountHp, _pairCountMoveSpeed, _pairCountAttackSpeed, _pairCountAttackDamage, _nonzeroDvcCountHp, _nonzeroDvcCountMoveSpeed, _nonzeroDvcCountAttackSpeed, _nonzeroDvcCountAttackDamage, HasVariance(_pairCountHp, _sumDvpHp, _sumDvpSqHp, _sumDvcHp, _sumDvcSqHp), HasVariance(_pairCountMoveSpeed, _sumDvpMoveSpeed, _sumDvpSqMoveSpeed, _sumDvcMoveSpeed, _sumDvcSqMoveSpeed), HasVariance(_pairCountAttackSpeed, _sumDvpAttackSpeed, _sumDvpSqAttackSpeed, _sumDvcAttackSpeed, _sumDvcSqAttackSpeed), HasVariance(_pairCountAttackDamage, _sumDvpAttackDamage, _sumDvpSqAttackDamage, _sumDvcAttackDamage, _sumDvcSqAttackDamage)); } private static void ResetModeState(string mode, int currentSgdSteps, int currentGaLearnSteps) { _hasModeState = true; _hasBaselineVirtualPower = false; _hasPreviousDecision = false; _mode = mode ?? ""; _stepIndex = 0; _lastSgdSteps = currentSgdSteps; _lastGaLearnSteps = currentGaLearnSteps; _baselineVirtualPower = default(SgdVirtualPowerSample); _previousDecisionVirtualPower = default(SgdVirtualPowerSample); _previousDecisionVirtualChallenge = default(SgdVirtualPowerSample); _lastObservedVirtualChallenge = default(SgdVirtualPowerSample); ResetAxisQuality(); } private static void ResetAxisQuality() { _pairCountHp = 0; _pairCountMoveSpeed = 0; _pairCountAttackSpeed = 0; _pairCountAttackDamage = 0; _nonzeroDvcCountHp = 0; _nonzeroDvcCountMoveSpeed = 0; _nonzeroDvcCountAttackSpeed = 0; _nonzeroDvcCountAttackDamage = 0; _sumDvpHp = 0f; _sumDvpMoveSpeed = 0f; _sumDvpAttackSpeed = 0f; _sumDvpAttackDamage = 0f; _sumDvpSqHp = 0f; _sumDvpSqMoveSpeed = 0f; _sumDvpSqAttackSpeed = 0f; _sumDvpSqAttackDamage = 0f; _sumDvcHp = 0f; _sumDvcMoveSpeed = 0f; _sumDvcAttackSpeed = 0f; _sumDvcAttackDamage = 0f; _sumDvcSqHp = 0f; _sumDvcSqMoveSpeed = 0f; _sumDvcSqAttackSpeed = 0f; _sumDvcSqAttackDamage = 0f; } private static void RecordAxisPair(in SgdVirtualPowerSample deltaVirtualPower, in SgdVirtualPowerSample deltaVirtualChallenge) { RecordAxisPair(deltaVirtualPower.Hp, deltaVirtualChallenge.Hp, ref _pairCountHp, ref _nonzeroDvcCountHp, ref _sumDvpHp, ref _sumDvpSqHp, ref _sumDvcHp, ref _sumDvcSqHp); RecordAxisPair(deltaVirtualPower.MoveSpeed, deltaVirtualChallenge.MoveSpeed, ref _pairCountMoveSpeed, ref _nonzeroDvcCountMoveSpeed, ref _sumDvpMoveSpeed, ref _sumDvpSqMoveSpeed, ref _sumDvcMoveSpeed, ref _sumDvcSqMoveSpeed); RecordAxisPair(deltaVirtualPower.AttackSpeed, deltaVirtualChallenge.AttackSpeed, ref _pairCountAttackSpeed, ref _nonzeroDvcCountAttackSpeed, ref _sumDvpAttackSpeed, ref _sumDvpSqAttackSpeed, ref _sumDvcAttackSpeed, ref _sumDvcSqAttackSpeed); RecordAxisPair(deltaVirtualPower.AttackDamage, deltaVirtualChallenge.AttackDamage, ref _pairCountAttackDamage, ref _nonzeroDvcCountAttackDamage, ref _sumDvpAttackDamage, ref _sumDvpSqAttackDamage, ref _sumDvcAttackDamage, ref _sumDvcSqAttackDamage); } private static void RecordAxisPair(float dvp, float dvc, ref int pairCount, ref int nonzeroDvcCount, ref float sumDvp, ref float sumDvpSq, ref float sumDvc, ref float sumDvcSq) { pairCount++; sumDvp += dvp; sumDvpSq += dvp * dvp; sumDvc += dvc; sumDvcSq += dvc * dvc; if (Mathf.Abs(dvc) > 1E-06f) { nonzeroDvcCount++; } } private static bool HasVariance(int n, float sumDvp, float sumDvpSq, float sumDvc, float sumDvcSq) { if (n < 2) { return false; } float num = n; float num2 = sumDvpSq / num - sumDvp / num * (sumDvp / num); float num3 = sumDvcSq / num - sumDvc / num * (sumDvc / num); if (num2 > 1E-08f) { return num3 > 1E-08f; } return false; } private static bool DetermineDecisionStep(string mode, int currentSgdSteps, int currentGaLearnSteps, in SgdVirtualPowerSample virtualChallenge, out string reason) { if (!_hasPreviousDecision) { reason = "initial"; return true; } if (mode == "FLS") { reason = "fls_sample_tick"; return true; } if (mode == "SGD" && currentSgdSteps > _lastSgdSteps) { reason = "sgd_step"; return true; } if (mode == "GA") { if (currentGaLearnSteps > _lastGaLearnSteps) { reason = "ga_learn"; return true; } if (HasChallengeChanged(in virtualChallenge, in _lastObservedVirtualChallenge)) { reason = "ga_snapshot_change"; return true; } } reason = "no_step"; return false; } private static float GetStepIntervalSeconds(string mode) { if (mode == "SGD") { return SgdDecisionRuntimeState.StepSeconds; } if (mode == "GA") { return Mathf.Max(0f, (ConfigManager.timeLimit != null) ? ((float)ConfigManager.timeLimit.Value) : 0f); } return Mathf.Max(1f, (ConfigManager.telemetrySampleIntervalSeconds != null) ? ConfigManager.telemetrySampleIntervalSeconds.Value : 1f); } private static bool HasChallengeChanged(in SgdVirtualPowerSample a, in SgdVirtualPowerSample b) { if (!(Mathf.Abs(a.Hp - b.Hp) > 0.0001f) && !(Mathf.Abs(a.MoveSpeed - b.MoveSpeed) > 0.0001f) && !(Mathf.Abs(a.AttackSpeed - b.AttackSpeed) > 0.0001f)) { return Mathf.Abs(a.AttackDamage - b.AttackDamage) > 0.0001f; } return true; } private static float ToVirtualChallenge(GeneStat stat, float multiplier) { if (float.IsNaN(multiplier) || float.IsInfinity(multiplier) || multiplier <= 0f) { multiplier = 1f; } return SafeLog(SgdAxisLimitProvider.Clamp(stat, multiplier)); } private static SgdVirtualPowerSample Sanitize(in SgdVirtualPowerSample sample) { return new SgdVirtualPowerSample(Sanitize(sample.Hp), Sanitize(sample.MoveSpeed), Sanitize(sample.AttackSpeed), Sanitize(sample.AttackDamage)); } private static float Sanitize(float value) { if (!float.IsNaN(value) && !float.IsInfinity(value)) { return value; } return 0f; } private static float SafeLog(float value) { if (float.IsNaN(value) || float.IsInfinity(value) || value <= 0f) { return 0f; } return Mathf.Log(value); } private static SgdVirtualPowerSample Subtract(in SgdVirtualPowerSample a, in SgdVirtualPowerSample b) { return new SgdVirtualPowerSample(a.Hp - b.Hp, a.MoveSpeed - b.MoveSpeed, a.AttackSpeed - b.AttackSpeed, a.AttackDamage - b.AttackDamage); } } internal static class H3GaDecisionObserver { private static GeneEngineDriver _subscribedDriver; public static int TotalLearnSteps { get; private set; } public static void Reset() { if ((Object)(object)_subscribedDriver != (Object)null) { _subscribedDriver.GEDPostLearningEvent -= OnLearned; } _subscribedDriver = null; TotalLearnSteps = 0; } public static void TickSubscribe() { GeneEngineDriver instance = GeneEngineDriver.instance; if (!((Object)(object)instance == (Object)null) && instance != _subscribedDriver) { if ((Object)(object)_subscribedDriver != (Object)null) { _subscribedDriver.GEDPostLearningEvent -= OnLearned; } _subscribedDriver = instance; _subscribedDriver.GEDPostLearningEvent += OnLearned; } } private static void OnLearned(object sender, EventArgs e) { TotalLearnSteps++; } } internal static class PostHogBatchClient { [CompilerGenerated] private sealed class d__0 : IEnumerator, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public int maxBatches; public float maxSeconds; private float 5__2; private int 5__3; private int 5__4; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__0(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; if (!ConfigManager.telemetryEnabled.Value) { return false; } 5__2 = Time.realtimeSinceStartup; 5__3 = 0; break; case 1: <>1__state = -1; 5__3++; if (TelemetryEventQueue.Count >= 5__4) { return false; } <>2__current = null; <>1__state = 2; return true; case 2: <>1__state = -1; break; } if (TelemetryEventQueue.Count > 0) { if (5__3 >= maxBatches) { ManualLogSource geneticLogSource = GeneticsArtifactPlugin.geneticLogSource; if (geneticLogSource != null) { geneticLogSource.LogWarning((object)("[Telemetry] PostHog flush stopped: maxBatches reached (" + maxBatches + "). Remaining=" + TelemetryEventQueue.Count)); } return false; } if (Time.realtimeSinceStartup - 5__2 > maxSeconds) { ManualLogSource geneticLogSource2 = GeneticsArtifactPlugin.geneticLogSource; if (geneticLogSource2 != null) { geneticLogSource2.LogWarning((object)("[Telemetry] PostHog flush stopped: timeout (" + maxSeconds + "s). Remaining=" + TelemetryEventQueue.Count)); } return false; } 5__4 = TelemetryEventQueue.Count; <>2__current = FlushQueuedEvents(); <>1__state = 1; return true; } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class d__1 : IEnumerator, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; private UnityWebRequest 5__2; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__1(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } 5__2 = null; <>1__state = -2; } private bool MoveNext() { //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Invalid comparison between Unknown and I4 //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Invalid comparison between Unknown and I4 //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Invalid comparison between Unknown and I4 //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Expected O, but got Unknown //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Expected O, but got Unknown //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Expected O, but got Unknown try { switch (<>1__state) { default: return false; case 0: { <>1__state = -1; if (!ConfigManager.telemetryEnabled.Value) { return false; } string text = "phc_oHSq642PWWQmaTGWDzmrvyHUm5BuuSkQaKgbStJBD9Sw"; if (string.IsNullOrWhiteSpace(text)) { return false; } if (!TelemetryEventQueue.TryDequeueBatchAsPostHogJson(text, out var payload, out var _)) { return false; } if (string.IsNullOrEmpty(payload)) { return false; } string text2 = NormalizeHost("https://us.i.posthog.com"); byte[] bytes = Encoding.UTF8.GetBytes(payload); 5__2 = new UnityWebRequest(text2 + "/batch/", "POST"); <>1__state = -3; 5__2.uploadHandler = (UploadHandler)new UploadHandlerRaw(bytes); 5__2.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer(); 5__2.SetRequestHeader("Content-Type", "application/json"); 5__2.timeout = 5; <>2__current = 5__2.SendWebRequest(); <>1__state = 1; return true; } case 1: <>1__state = -3; if ((int)5__2.result == 2 || (int)5__2.result == 3 || (int)5__2.result == 4) { TelemetryEventQueue.RestoreLastBatchForRetry(); ManualLogSource geneticLogSource = GeneticsArtifactPlugin.geneticLogSource; if (geneticLogSource != null) { geneticLogSource.LogWarning((object)("[Telemetry] PostHog flush failed: " + 5__2.error)); } } else { TelemetryEventQueue.MarkLastBatchSent(); } <>m__Finally1(); 5__2 = null; return false; } } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (5__2 != null) { ((IDisposable)5__2).Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [IteratorStateMachine(typeof(d__0))] public static IEnumerator FlushAllQueuedEvents(float maxSeconds = 8f, int maxBatches = 64) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__0(0) { maxSeconds = maxSeconds, maxBatches = maxBatches }; } [IteratorStateMachine(typeof(d__1))] public static IEnumerator FlushQueuedEvents() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__1(0); } private static string NormalizeHost(string host) { if (string.IsNullOrWhiteSpace(host)) { return "https://us.i.posthog.com"; } host = host.Trim(); while (host.EndsWith("/")) { host = host.Substring(0, host.Length - 1); } return host; } } internal readonly struct TelemetryDifficultySnapshot { public readonly string Mode; public readonly string ChallengeSource; public readonly string ChallengeSemantics; public readonly float MaxHealth; public readonly float MoveSpeed; public readonly float AttackSpeed; public readonly float AttackDamage; public TelemetryDifficultySnapshot(string mode, string challengeSource, string challengeSemantics, float maxHealth, float moveSpeed, float attackSpeed, float attackDamage) { Mode = mode; ChallengeSource = challengeSource ?? ""; ChallengeSemantics = challengeSemantics ?? ""; MaxHealth = Sanitize(maxHealth); MoveSpeed = Sanitize(moveSpeed); AttackSpeed = Sanitize(attackSpeed); AttackDamage = Sanitize(attackDamage); } public static TelemetryDifficultySnapshot Capture() { string telemetryMode = DdaAlgorithmState.GetTelemetryMode(); if (telemetryMode == "SGD") { return new TelemetryDifficultySnapshot(telemetryMode, "sgd_actuators", "ln_clamped_multiplier", SgdActuatorsRuntimeState.MaxHealthMultiplier, SgdActuatorsRuntimeState.MoveSpeedMultiplier, SgdActuatorsRuntimeState.AttackSpeedMultiplier, SgdActuatorsRuntimeState.AttackDamageMultiplier); } if (telemetryMode == "GA") { return CaptureGeneticAverages(); } return new TelemetryDifficultySnapshot(telemetryMode, "fls_fixed", "ln_clamped_multiplier_fixed_unity", 1f, 1f, 1f, 1f); } public float GetMultiplier(GeneStat stat) { return stat switch { GeneStat.MaxHealth => MaxHealth, GeneStat.MoveSpeed => MoveSpeed, GeneStat.AttackSpeed => AttackSpeed, GeneStat.AttackDamage => AttackDamage, _ => 1f, }; } private static TelemetryDifficultySnapshot CaptureGeneticAverages() { float hp = 0f; float ms = 0f; float attackSpeed = 0f; float attackDamage = 0f; int count = 0; if (GeneEngineDriver.masterGenes != null) { for (int i = 0; i < GeneEngineDriver.masterGenes.Count; i++) { MasterGeneBehaviour masterGeneBehaviour = GeneEngineDriver.masterGenes[i]; if (masterGeneBehaviour?.templateGenes != null) { AddGenes(masterGeneBehaviour.templateGenes, ref hp, ref ms, ref attackSpeed, ref attackDamage, ref count); } } } if (count == 0 && GeneEngineDriver.livingGenes != null) { for (int j = 0; j < GeneEngineDriver.livingGenes.Count; j++) { MonsterGeneBehaviour monsterGeneBehaviour = GeneEngineDriver.livingGenes[j]; if (monsterGeneBehaviour?.currentGenes != null) { AddGenes(monsterGeneBehaviour.currentGenes, ref hp, ref ms, ref attackSpeed, ref attackDamage, ref count); } } } if (count <= 0) { return new TelemetryDifficultySnapshot("GA", "ga_fallback_unity", "ln_clamped_multiplier", 1f, 1f, 1f, 1f); } string challengeSource = ((GeneEngineDriver.masterGenes != null && GeneEngineDriver.masterGenes.Count > 0) ? "ga_master_genes_avg" : "ga_living_genes_avg"); return new TelemetryDifficultySnapshot("GA", challengeSource, "ln_clamped_multiplier", hp / (float)count, ms / (float)count, attackSpeed / (float)count, attackDamage / (float)count); } private static void AddGenes(Dictionary genes, ref float hp, ref float ms, ref float attackSpeed, ref float attackDamage, ref int count) { hp += GetGeneOrDefault(genes, GeneStat.MaxHealth); ms += GetGeneOrDefault(genes, GeneStat.MoveSpeed); attackSpeed += GetGeneOrDefault(genes, GeneStat.AttackSpeed); attackDamage += GetGeneOrDefault(genes, GeneStat.AttackDamage); count++; } private static float GetGeneOrDefault(Dictionary genes, GeneStat stat) { if (genes == null || !genes.TryGetValue(stat, out var value)) { return 1f; } return Sanitize(value); } private static float Sanitize(float value) { if (float.IsNaN(value) || float.IsInfinity(value) || value <= 0f) { return 1f; } return Mathf.Clamp(value, 0.0001f, 100f); } } internal sealed class TelemetryEvent { public string EventName { get; } public DateTime TimestampUtc { get; } public Dictionary Properties { get; } public TelemetryEvent(string eventName, Dictionary properties) { EventName = eventName; TimestampUtc = DateTime.UtcNow; Properties = properties ?? new Dictionary(); } } internal static class TelemetryEventQueue { private const int DefaultBatchSize = 32; private static readonly Queue Events = new Queue(128); private static List _lastBatch; private static TelemetryEvent _lastEnqueuedEvent; private static TelemetryEvent _lastEnqueuedSample; public static int Count => Events.Count; public static TelemetryEvent LastEnqueuedEvent => _lastEnqueuedEvent; public static TelemetryEvent LastEnqueuedSample => _lastEnqueuedSample; public static void Enqueue(TelemetryEvent telemetryEvent) { if (telemetryEvent != null) { _lastEnqueuedEvent = telemetryEvent; if (telemetryEvent.EventName == "dda_sample") { _lastEnqueuedSample = telemetryEvent; } int num = ConfigManager.telemetryMaxQueueSize?.Value ?? 512; num = Mathf.Clamp(num, 32, 5000); while (Events.Count >= num) { Events.Dequeue(); } Events.Enqueue(telemetryEvent); } } public static bool TryDequeueBatchAsPostHogJson(string projectToken, out string payload, out int batchCount) { payload = ""; batchCount = 0; if (string.IsNullOrWhiteSpace(projectToken) || Events.Count == 0) { return false; } int num = (batchCount = Mathf.Min(32, Events.Count)); _lastBatch = new List(num); for (int i = 0; i < num; i++) { _lastBatch.Add(Events.Dequeue()); } payload = TelemetryJsonWriter.BuildPostHogBatch(projectToken.Trim(), _lastBatch); return !string.IsNullOrEmpty(payload); } public static string DequeueBatchAsPostHogJson(string projectToken) { if (!TryDequeueBatchAsPostHogJson(projectToken, out var payload, out var _)) { return ""; } return payload; } public static void MarkLastBatchSent() { _lastBatch = null; } public static void RestoreLastBatchForRetry() { if (_lastBatch != null && _lastBatch.Count != 0) { _ = _lastBatch.Count; for (int i = 0; i < _lastBatch.Count; i++) { Events.Enqueue(_lastBatch[i]); } _lastBatch = null; } } } internal static class TelemetryJsonWriter { public static string BuildPostHogBatch(string apiKey, IReadOnlyList events) { StringBuilder stringBuilder = new StringBuilder(4096); stringBuilder.Append('{'); WritePropertyName(stringBuilder, "api_key"); WriteString(stringBuilder, apiKey); stringBuilder.Append(','); WritePropertyName(stringBuilder, "historical_migration"); stringBuilder.Append("false"); stringBuilder.Append(','); WritePropertyName(stringBuilder, "batch"); stringBuilder.Append('['); for (int i = 0; i < events.Count; i++) { if (i > 0) { stringBuilder.Append(','); } WriteEvent(stringBuilder, events[i]); } stringBuilder.Append(']'); stringBuilder.Append('}'); return stringBuilder.ToString(); } private static void WriteEvent(StringBuilder sb, TelemetryEvent telemetryEvent) { sb.Append('{'); WritePropertyName(sb, "event"); WriteString(sb, telemetryEvent.EventName); sb.Append(','); WritePropertyName(sb, "timestamp"); WriteString(sb, telemetryEvent.TimestampUtc.ToString("O", CultureInfo.InvariantCulture)); sb.Append(','); WritePropertyName(sb, "properties"); WriteDictionary(sb, telemetryEvent.Properties); sb.Append('}'); } private static void WriteDictionary(StringBuilder sb, Dictionary values) { sb.Append('{'); bool flag = true; foreach (KeyValuePair value in values) { if (!flag) { sb.Append(','); } flag = false; WritePropertyName(sb, value.Key); WriteValue(sb, value.Value); } sb.Append('}'); } private static void WritePropertyName(StringBuilder sb, string name) { WriteString(sb, name); sb.Append(':'); } private static void WriteValue(StringBuilder sb, object value) { if (value == null) { sb.Append("null"); } else if (value is string value2) { WriteString(sb, value2); } else if (value is bool flag) { sb.Append(flag ? "true" : "false"); } else if (value is int || value is long || value is short || value is byte) { sb.Append(Convert.ToString(value, CultureInfo.InvariantCulture)); } else if (value is float value3) { WriteFloat(sb, value3); } else if (value is double value4) { WriteDouble(sb, value4); } else { WriteString(sb, Convert.ToString(value, CultureInfo.InvariantCulture)); } } private static void WriteFloat(StringBuilder sb, float value) { if (float.IsNaN(value) || float.IsInfinity(value)) { sb.Append('0'); } else { sb.Append(value.ToString("R", CultureInfo.InvariantCulture)); } } private static void WriteDouble(StringBuilder sb, double value) { if (double.IsNaN(value) || double.IsInfinity(value)) { sb.Append('0'); } else { sb.Append(value.ToString("R", CultureInfo.InvariantCulture)); } } private static void WriteString(StringBuilder sb, string value) { sb.Append('"'); if (!string.IsNullOrEmpty(value)) { foreach (char c in value) { switch (c) { case '\\': sb.Append("\\\\"); continue; case '"': sb.Append("\\\""); continue; case '\n': sb.Append("\\n"); continue; case '\r': sb.Append("\\r"); continue; case '\t': sb.Append("\\t"); continue; } if (c < ' ') { sb.Append("\\u"); int num = c; sb.Append(num.ToString("x4", CultureInfo.InvariantCulture)); } else if (c > '\u007f') { sb.Append("\\u"); int num = c; sb.Append(num.ToString("x4", CultureInfo.InvariantCulture)); } else { sb.Append(c); } } } sb.Append('"'); } } internal sealed class TelemetryRuntimeDriver : MonoBehaviour { [CompilerGenerated] private sealed class d__31 : IEnumerator, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public TelemetryRuntimeDriver <>4__this; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__31(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { int num = <>1__state; TelemetryRuntimeDriver telemetryRuntimeDriver = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; telemetryRuntimeDriver._isFlushing = true; <>2__current = PostHogBatchClient.FlushQueuedEvents(); <>1__state = 1; return true; case 1: <>1__state = -1; telemetryRuntimeDriver._isFlushing = false; return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private static TelemetryRuntimeDriver _activeDriver; private static TelemetrySessionState _pendingSurveySession; private static string _pendingSurveyEndReason = ""; private static bool _pendingSessionEndQueued; private readonly TelemetrySessionState _session = new TelemetrySessionState(); private float _sampleTimer; private float _flushTimer; private float _lastPlayerDeathAt = -1000f; private bool _isFlushing; public static bool HasActiveSession => GetSurveySession() != null; public static bool HasSubmittedSurvey => GetSurveySession()?.HasSurveyCompleted ?? false; public static void RegisterHooks() { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Expected O, but got Unknown //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Expected O, but got Unknown if (ConfigManager.diagnosticsEnableSgdHooks == null || !ConfigManager.diagnosticsEnableSgdHooks.Value) { Run.BeginGameOver += new hook_BeginGameOver(Run_BeginGameOver); Run.Start += new hook_Start(Run_Start); CharacterBody.OnDestroy += new hook_OnDestroy(CharacterBody_OnDestroy); } BaseMainMenuScreen.OnEnter += new hook_OnEnter(BaseMainMenuScreen_OnEnter); } internal static void NotifyRunBeginGameOver(GameEndingDef gameEndingDef) { RequestSurvey(((Object)(object)gameEndingDef != (Object)null && gameEndingDef.isWin) ? "victory" : "game_over"); } internal static void NotifyPlayerBodyDestroyed(CharacterBody body) { if (!((Object)(object)_activeDriver == (Object)null) && ConfigManager.telemetryEnabled.Value && !((Object)(object)body == (Object)null) && IsPlayerBody(body) && !(Time.time - _activeDriver._lastPlayerDeathAt < 1f)) { _activeDriver._lastPlayerDeathAt = Time.time; _activeDriver._session.RecordPlayerDeath(); TelemetryEventQueue.Enqueue(TelemetrySampleBuilder.BuildPlayerDeath(_activeDriver._session, body, null)); RequestSurvey("player_death"); _activeDriver.StartFlushIfIdle(); } } public static bool RecordPostSessionSurvey(int fairnessLikert, int continuityLikert, string comment) { TelemetrySessionState surveySession = GetSurveySession(); if (surveySession == null) { return false; } surveySession.RecordSurvey(fairnessLikert, continuityLikert, comment); if (ConfigManager.telemetryEnabled.Value) { TelemetryEventQueue.Enqueue(TelemetrySampleBuilder.BuildPostSessionSurvey(surveySession, surveySession.SurveyFairnessLikert, surveySession.SurveyContinuityLikert, surveySession.SurveyComment)); if (!surveySession.HasSessionEndQueued) { surveySession.MarkSessionEndQueued(); TelemetryEventQueue.Enqueue(TelemetrySampleBuilder.BuildSessionEnd(surveySession, "post_session_survey_submitted")); } CompletePendingSessionEndIfNeeded(); StartAnyFlushIfPossible(); } return true; } public static void RequestSurvey(string triggerReason) { if (ConfigManager.telemetryEnabled.Value && HasActiveSession && !HasSubmittedSurvey) { TelemetrySurveyWidget.Show(triggerReason); } } public static void SkipPendingSurvey() { TelemetrySessionState surveySession = GetSurveySession(); if (surveySession != null && !surveySession.HasSurveyCompleted) { surveySession.RecordSurveySkipped("ui_trigger=unknown"); if (ConfigManager.telemetryEnabled.Value) { TelemetryEventQueue.Enqueue(TelemetrySampleBuilder.BuildPostSessionSurveySkipped(surveySession, surveySession.SurveyComment)); } } if (surveySession != null && !surveySession.HasSessionEndQueued) { surveySession.MarkSessionEndQueued(); TelemetryEventQueue.Enqueue(TelemetrySampleBuilder.BuildSessionEnd(surveySession, "post_session_survey_skipped")); } CompletePendingSessionEndIfNeeded(); StartAnyFlushIfPossible(); } public static void SkipPendingSurvey(string comment) { TelemetrySessionState surveySession = GetSurveySession(); if (surveySession != null && !surveySession.HasSurveyCompleted) { surveySession.RecordSurveySkipped(comment); if (ConfigManager.telemetryEnabled.Value) { TelemetryEventQueue.Enqueue(TelemetrySampleBuilder.BuildPostSessionSurveySkipped(surveySession, surveySession.SurveyComment)); } } if (surveySession != null && !surveySession.HasSessionEndQueued) { surveySession.MarkSessionEndQueued(); TelemetryEventQueue.Enqueue(TelemetrySampleBuilder.BuildSessionEnd(surveySession, "post_session_survey_skipped")); } CompletePendingSessionEndIfNeeded(); StartAnyFlushIfPossible(); } private static void Run_Start(orig_Start orig, Run self) { orig.Invoke(self); if ((Object)(object)self != (Object)null && (Object)(object)((Component)self).gameObject != (Object)null && (Object)(object)((Component)self).gameObject.GetComponent() == (Object)null) { ((Component)self).gameObject.AddComponent(); } } private static void Run_BeginGameOver(orig_BeginGameOver orig, Run self, GameEndingDef gameEndingDef) { RequestSurvey(((Object)(object)gameEndingDef != (Object)null && gameEndingDef.isWin) ? "victory" : "game_over"); orig.Invoke(self, gameEndingDef); } private static void BaseMainMenuScreen_OnEnter(orig_OnEnter orig, BaseMainMenuScreen self, MainMenuController mainMenuController) { orig.Invoke(self, mainMenuController); EnsureMpEventSystemForMainMenu(); Cursor.visible = true; Cursor.lockState = (CursorLockMode)0; TryShowPendingSurveyFromMainMenu(); } private static void EnsureMpEventSystemForMainMenu() { try { MPEventSystem[] array = Object.FindObjectsOfType(); EventSystem[] array2 = Object.FindObjectsOfType(); MPEventSystem val = null; if (array != null) { MPEventSystem[] array3 = array; foreach (MPEventSystem val2 in array3) { if ((Object)(object)val2 != (Object)null && ((Object)val2).name == "MPEventSystem Player0") { val = val2; break; } } if ((Object)(object)val == (Object)null) { array3 = array; foreach (MPEventSystem val3 in array3) { if ((Object)(object)val3 != (Object)null && ((Behaviour)val3).enabled) { val = val3; break; } } } if ((Object)(object)val == (Object)null && array.Length != 0) { val = array[0]; } } if ((Object)(object)val != (Object)null && !((Behaviour)val).enabled) { ((Behaviour)val).enabled = true; } if (!((Object)(object)val != (Object)null) || array2 == null) { return; } EventSystem[] array4 = array2; foreach (EventSystem val4 in array4) { if (!((Object)(object)val4 == (Object)null) && !(val4 is MPEventSystem) && ((Behaviour)val4).enabled) { ((Behaviour)val4).enabled = false; } } } catch (Exception ex) { ManualLogSource geneticLogSource = GeneticsArtifactPlugin.geneticLogSource; if (geneticLogSource != null) { geneticLogSource.LogWarning((object)("[DDA] EnsureMpEventSystemForMainMenu failed: " + ex.GetType().Name + ": " + ex.Message)); } } } private static void TryShowPendingSurveyFromMainMenu() { if (ConfigManager.telemetryEnabled.Value && _pendingSurveySession != null && !_pendingSurveySession.HasSurveyCompleted) { RequestSurvey("pending_survey_main_menu"); } } private void Awake() { _activeDriver = this; _session.StartNewRun(); _sampleTimer = 0f; _flushTimer = 0f; _lastPlayerDeathAt = -1000f; if (ConfigManager.telemetryEnabled.Value) { TelemetryEventQueue.Enqueue(TelemetrySampleBuilder.BuildSessionStart(_session)); } } private void Update() { if (!ConfigManager.telemetryEnabled.Value) { return; } float deltaTime = Time.deltaTime; _sampleTimer += deltaTime; _flushTimer += deltaTime; H3GaDecisionObserver.TickSubscribe(); float num = Mathf.Max(1f, ConfigManager.telemetrySampleIntervalSeconds.Value); if (_sampleTimer >= num) { float sampleTimer = _sampleTimer; int num2 = Mathf.Max(1, Mathf.FloorToInt(_sampleTimer / num)); _sampleTimer -= (float)num2 * num; _session.RecordMissedSampleIntervals(num2 - 1); TelemetryEventQueue.Enqueue(TelemetrySampleBuilder.BuildSample(_session, sampleTimer)); if (_session.TryConsumeRecoveryEvent(out var recoverySeconds)) { TelemetryEventQueue.Enqueue(TelemetrySampleBuilder.BuildRecovery(_session, recoverySeconds)); } TelemetryDegradationTransition transition; while (_session.TryConsumeDegradationTransition(out transition)) { TelemetryEventQueue.Enqueue(TelemetrySampleBuilder.BuildDegradationTransition(_session, transition)); } } float num3 = Mathf.Max(5f, ConfigManager.telemetryFlushIntervalSeconds.Value); if (_flushTimer >= num3) { _flushTimer = 0f; StartFlushIfIdle(); } } private void OnDestroy() { if (ConfigManager.telemetryEnabled.Value && !string.IsNullOrEmpty(_session.SessionId)) { if (_session.HasSurvey) { if (!_session.HasSessionEndQueued) { _session.MarkSessionEndQueued(); TelemetryEventQueue.Enqueue(TelemetrySampleBuilder.BuildSessionEnd(_session, "run_destroyed")); } if ((Object)(object)GeneticsArtifactPlugin.Instance != (Object)null) { ((MonoBehaviour)GeneticsArtifactPlugin.Instance).StartCoroutine(PostHogBatchClient.FlushQueuedEvents()); } } else { _pendingSurveySession = _session; _pendingSurveyEndReason = "run_destroyed"; _pendingSessionEndQueued = false; } } if ((Object)(object)_activeDriver == (Object)(object)this) { _activeDriver = null; } } private static void CharacterBody_OnDestroy(orig_OnDestroy orig, CharacterBody self) { try { if (!((Object)(object)_activeDriver == (Object)null) && ConfigManager.telemetryEnabled.Value && !((Object)(object)self == (Object)null) && IsPlayerBody(self) && !(Time.time - _activeDriver._lastPlayerDeathAt < 1f)) { NotifyPlayerBodyDestroyed(self); } } finally { orig.Invoke(self); } } private static bool IsPlayerBody(CharacterBody body) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Invalid comparison between Unknown and I4 if ((Object)(object)body != (Object)null) { if (!body.isPlayerControlled) { if ((Object)(object)body.teamComponent != (Object)null) { return (int)body.teamComponent.teamIndex == 1; } return false; } return true; } return false; } private void StartFlushIfIdle() { if (!_isFlushing) { ((MonoBehaviour)this).StartCoroutine(FlushRoutine()); } } [IteratorStateMachine(typeof(d__31))] private IEnumerator FlushRoutine() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__31(0) { <>4__this = this }; } private static TelemetrySessionState GetSurveySession() { if ((Object)(object)_activeDriver != (Object)null && !string.IsNullOrEmpty(_activeDriver._session.SessionId)) { return _activeDriver._session; } if (_pendingSurveySession == null || string.IsNullOrEmpty(_pendingSurveySession.SessionId)) { return null; } return _pendingSurveySession; } private static void CompletePendingSessionEndIfNeeded() { if (_pendingSurveySession != null) { if (_pendingSessionEndQueued || _pendingSurveySession.HasSessionEndQueued) { _pendingSessionEndQueued = true; _pendingSurveySession = null; _pendingSurveyEndReason = ""; } else { _pendingSurveySession.MarkSessionEndQueued(); TelemetryEventQueue.Enqueue(TelemetrySampleBuilder.BuildSessionEnd(_pendingSurveySession, _pendingSurveyEndReason)); _pendingSessionEndQueued = true; _pendingSurveySession = null; _pendingSurveyEndReason = ""; } } } private static void StartAnyFlushIfPossible() { if ((Object)(object)_activeDriver != (Object)null) { _activeDriver.StartFlushIfIdle(); } else if ((Object)(object)GeneticsArtifactPlugin.Instance != (Object)null) { ((MonoBehaviour)GeneticsArtifactPlugin.Instance).StartCoroutine(PostHogBatchClient.FlushQueuedEvents()); } } } internal static class TelemetrySampleBuilder { [CompilerGenerated] private sealed class d__22 : IEnumerable, IEnumerable, IEnumerator, IEnumerator, IDisposable { private int <>1__state; private ItemIndex <>2__current; private int <>l__initialThreadId; private Inventory inventory; public Inventory <>3__inventory; private IEnumerator <>7__wrap1; ItemIndex IEnumerator.Current { [DebuggerHidden] get { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return <>2__current; } } [DebuggerHidden] public d__22(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } <>7__wrap1 = null; <>1__state = -2; } private bool MoveNext() { //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; if ((Object)(object)inventory == (Object)null) { return false; } if (!(typeof(Inventory).GetField("itemAcquisitionOrder", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(inventory) is IEnumerable enumerable)) { return false; } <>7__wrap1 = enumerable.GetEnumerator(); <>1__state = -3; break; case 1: <>1__state = -3; break; } while (<>7__wrap1.MoveNext()) { if (<>7__wrap1.Current is ItemIndex val) { <>2__current = val; <>1__state = 1; return true; } } <>m__Finally1(); <>7__wrap1 = null; return false; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (<>7__wrap1 is IDisposable disposable) { disposable.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__22 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__22(0); } d__.inventory = <>3__inventory; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } public static TelemetryEvent BuildSessionStart(TelemetrySessionState session) { Dictionary dictionary = BuildCommonProperties(session); dictionary["event_kind"] = "session_start"; dictionary["telemetry_enabled"] = ConfigManager.telemetryEnabled.Value; dictionary["sample_interval_seconds"] = ConfigManager.telemetrySampleIntervalSeconds.Value; dictionary["flush_interval_seconds"] = ConfigManager.telemetryFlushIntervalSeconds.Value; return new TelemetryEvent("dda_session_start", dictionary); } public static TelemetryEvent BuildSample(TelemetrySessionState session, float dt) { Dictionary dictionary = BuildCommonProperties(session); SgdSensorsSample s = (SgdSensorsRuntimeState.HasSample ? SgdSensorsRuntimeState.Sample : default(SgdSensorsSample)); SgdVirtualPowerSample observedVirtualPower = (SgdRuntimeState.HasVirtualPower ? SgdRuntimeState.VirtualPower : default(SgdVirtualPowerSample)); TelemetryDifficultySnapshot snapshot = TelemetryDifficultySnapshot.Capture(); AddSensorProperties(dictionary, in s); float num = EstimateMaxHealthSkill01(in s); float num2 = EstimateMoveSpeedSkill01(in s); float num3 = EstimateAttackSpeedSkill01(in s); float num4 = EstimateAttackDamageSkill01(in s); float num5 = Challenge01(GeneStat.MaxHealth, snapshot.MaxHealth); float num6 = Challenge01(GeneStat.MoveSpeed, snapshot.MoveSpeed); float num7 = Challenge01(GeneStat.AttackSpeed, snapshot.AttackSpeed); float num8 = Challenge01(GeneStat.AttackDamage, snapshot.AttackDamage); float num9 = num5 - num; float num10 = num6 - num2; float num11 = num7 - num3; float num12 = num8 - num4; AddAxisProperties(dictionary, "max_health", "hp", num, num5, num9, snapshot.MaxHealth, session.PreviousMaxHealthMultiplier, session.PreviousMaxHealthSkill01, session.PreviousMaxHealthChallenge01, session.HasPreviousSample, session.IsJump(snapshot.MaxHealth, session.PreviousMaxHealthMultiplier)); AddAxisProperties(dictionary, "move_speed", "moveSpeed", num2, num6, num10, snapshot.MoveSpeed, session.PreviousMoveSpeedMultiplier, session.PreviousMoveSpeedSkill01, session.PreviousMoveSpeedChallenge01, session.HasPreviousSample, session.IsJump(snapshot.MoveSpeed, session.PreviousMoveSpeedMultiplier)); AddAxisProperties(dictionary, "attack_speed", "attackSpeed", num3, num7, num11, snapshot.AttackSpeed, session.PreviousAttackSpeedMultiplier, session.PreviousAttackSpeedSkill01, session.PreviousAttackSpeedChallenge01, session.HasPreviousSample, session.IsJump(snapshot.AttackSpeed, session.PreviousAttackSpeedMultiplier)); AddAxisProperties(dictionary, "attack_damage", "damage", num4, num8, num12, snapshot.AttackDamage, session.PreviousAttackDamageMultiplier, session.PreviousAttackDamageSkill01, session.PreviousAttackDamageChallenge01, session.HasPreviousSample, session.IsJump(snapshot.AttackDamage, session.PreviousAttackDamageMultiplier)); SgdVirtualPowerSample virtualChallenge = H3AxisDecisionState.ComputeVirtualChallengeAxes(snapshot); H3AxisDecisionSnapshot h3AxisDecisionSnapshot = H3AxisDecisionState.BuildSnapshot(snapshot.Mode, in observedVirtualPower, in virtualChallenge); H3AxisQualitySnapshot qualitySnapshot = H3AxisDecisionState.GetQualitySnapshot(); SgdVirtualPowerSample virtualPower = h3AxisDecisionSnapshot.VirtualPower; SgdVirtualPowerSample deltaVirtualPower = h3AxisDecisionSnapshot.DeltaVirtualPower; SgdVirtualPowerSample deltaVirtualChallenge = h3AxisDecisionSnapshot.DeltaVirtualChallenge; float total = h3AxisDecisionSnapshot.VirtualChallenge.Total; float total2 = h3AxisDecisionSnapshot.VirtualPower.Total; float num13 = Mathf.Abs(total - total2); float num14 = Mathf.Abs(h3AxisDecisionSnapshot.VirtualChallenge.Hp - virtualPower.Hp); float num15 = Mathf.Abs(h3AxisDecisionSnapshot.VirtualChallenge.MoveSpeed - virtualPower.MoveSpeed); float num16 = Mathf.Abs(h3AxisDecisionSnapshot.VirtualChallenge.AttackSpeed - virtualPower.AttackSpeed); float num17 = Mathf.Abs(h3AxisDecisionSnapshot.VirtualChallenge.AttackDamage - virtualPower.AttackDamage); float num18 = (num14 + num15 + num16 + num17) * 0.25f; float total3 = h3AxisDecisionSnapshot.DeltaVirtualPower.Total; float total4 = h3AxisDecisionSnapshot.DeltaVirtualChallenge.Total; float num19 = (Mathf.Abs(num9) + Mathf.Abs(num10) + Mathf.Abs(num11) + Mathf.Abs(num12)) * 0.25f; float num20 = session.ComputeDegradationSignal(in s, num19); dictionary["virtual_power_total"] = total2; dictionary["virtual_power_hp"] = virtualPower.Hp; dictionary["virtual_power_move_speed"] = virtualPower.MoveSpeed; dictionary["virtual_power_attack_speed"] = virtualPower.AttackSpeed; dictionary["virtual_power_attack_damage"] = virtualPower.AttackDamage; dictionary["virtual_power_offense"] = virtualPower.AttackDamage; dictionary["virtual_power_defense"] = virtualPower.Hp; dictionary["virtual_power_mobility"] = virtualPower.MoveSpeed; dictionary["virtual_power_observed_total"] = h3AxisDecisionSnapshot.ObservedVirtualPower.Total; dictionary["virtual_power_observed_hp"] = h3AxisDecisionSnapshot.ObservedVirtualPower.Hp; dictionary["virtual_power_observed_move_speed"] = h3AxisDecisionSnapshot.ObservedVirtualPower.MoveSpeed; dictionary["virtual_power_observed_attack_speed"] = h3AxisDecisionSnapshot.ObservedVirtualPower.AttackSpeed; dictionary["virtual_power_observed_attack_damage"] = h3AxisDecisionSnapshot.ObservedVirtualPower.AttackDamage; dictionary["virtual_power_baseline_total"] = h3AxisDecisionSnapshot.BaselineVirtualPower.Total; dictionary["virtual_power_baseline_hp"] = h3AxisDecisionSnapshot.BaselineVirtualPower.Hp; dictionary["virtual_power_baseline_move_speed"] = h3AxisDecisionSnapshot.BaselineVirtualPower.MoveSpeed; dictionary["virtual_power_baseline_attack_speed"] = h3AxisDecisionSnapshot.BaselineVirtualPower.AttackSpeed; dictionary["virtual_power_baseline_attack_damage"] = h3AxisDecisionSnapshot.BaselineVirtualPower.AttackDamage; dictionary["virtual_challenge_total"] = total; dictionary["virtual_challenge_hp"] = h3AxisDecisionSnapshot.VirtualChallenge.Hp; dictionary["virtual_challenge_move_speed"] = h3AxisDecisionSnapshot.VirtualChallenge.MoveSpeed; dictionary["virtual_challenge_attack_speed"] = h3AxisDecisionSnapshot.VirtualChallenge.AttackSpeed; dictionary["virtual_challenge_attack_damage"] = h3AxisDecisionSnapshot.VirtualChallenge.AttackDamage; dictionary["virtual_gap_abs"] = num13; dictionary["virtual_gap_hp_abs"] = num14; dictionary["virtual_gap_move_speed_abs"] = num15; dictionary["virtual_gap_attack_speed_abs"] = num16; dictionary["virtual_gap_attack_damage_abs"] = num17; dictionary["virtual_gap_axes_mean_abs"] = num18; dictionary["delta_virtual_power"] = total3; dictionary["delta_virtual_power_hp"] = deltaVirtualPower.Hp; dictionary["delta_virtual_power_move_speed"] = deltaVirtualPower.MoveSpeed; dictionary["delta_virtual_power_attack_speed"] = deltaVirtualPower.AttackSpeed; dictionary["delta_virtual_power_attack_damage"] = deltaVirtualPower.AttackDamage; dictionary["delta_virtual_challenge"] = total4; dictionary["delta_virtual_challenge_hp"] = deltaVirtualChallenge.Hp; dictionary["delta_virtual_challenge_move_speed"] = deltaVirtualChallenge.MoveSpeed; dictionary["delta_virtual_challenge_attack_speed"] = deltaVirtualChallenge.AttackSpeed; dictionary["delta_virtual_challenge_attack_damage"] = deltaVirtualChallenge.AttackDamage; dictionary["is_within_stable_error_epsilon"] = num19 <= (ConfigManager.telemetryStableErrorEpsilon?.Value ?? 0.1f); dictionary["is_within_virtual_gap_epsilon"] = num13 <= (ConfigManager.telemetryVirtualGapEpsilon?.Value ?? 0.5f); dictionary["is_within_virtual_gap_axes_epsilon"] = num18 <= (ConfigManager.telemetryVirtualGapEpsilon?.Value ?? 0.5f); dictionary["is_within_virtual_gap_hp_epsilon"] = num14 <= (ConfigManager.telemetryVirtualGapEpsilon?.Value ?? 0.5f); dictionary["is_within_virtual_gap_move_speed_epsilon"] = num15 <= (ConfigManager.telemetryVirtualGapEpsilon?.Value ?? 0.5f); dictionary["is_within_virtual_gap_attack_speed_epsilon"] = num16 <= (ConfigManager.telemetryVirtualGapEpsilon?.Value ?? 0.5f); dictionary["is_within_virtual_gap_attack_damage_epsilon"] = num17 <= (ConfigManager.telemetryVirtualGapEpsilon?.Value ?? 0.5f); dictionary["h3_axis_model"] = "damage,attackSpeed,hp,moveSpeed"; dictionary["h3_axis_schema"] = "vp_vc_4_axes_decision_v2"; dictionary["h3_virtual_power_scale"] = "relative_to_session_baseline"; dictionary["h3_virtual_challenge_scale"] = "ln_clamped_multiplier"; dictionary["h3_challenge_source"] = snapshot.ChallengeSource; dictionary["h3_vc_semantics"] = snapshot.ChallengeSemantics; dictionary["h3_delta_source"] = h3AxisDecisionSnapshot.DeltaSource; dictionary["h3_is_decision_step"] = h3AxisDecisionSnapshot.IsDecisionStep; dictionary["h3_decision_step_index"] = h3AxisDecisionSnapshot.StepIndex; dictionary["h3_decision_step_reason"] = h3AxisDecisionSnapshot.StepReason; dictionary["h3_decision_step_interval_seconds"] = h3AxisDecisionSnapshot.StepIntervalSeconds; dictionary["dda_is_decision_step"] = h3AxisDecisionSnapshot.IsDecisionStep; dictionary["dda_decision_step_index"] = h3AxisDecisionSnapshot.StepIndex; dictionary["dda_decision_step_reason"] = h3AxisDecisionSnapshot.StepReason; dictionary["dda_decision_step_interval_seconds"] = h3AxisDecisionSnapshot.StepIntervalSeconds; dictionary["h3_axis_pair_count_hp"] = qualitySnapshot.PairCountHp; dictionary["h3_axis_pair_count_move_speed"] = qualitySnapshot.PairCountMoveSpeed; dictionary["h3_axis_pair_count_attack_speed"] = qualitySnapshot.PairCountAttackSpeed; dictionary["h3_axis_pair_count_attack_damage"] = qualitySnapshot.PairCountAttackDamage; dictionary["h3_axis_nonzero_dvc_count_hp"] = qualitySnapshot.NonzeroDvcCountHp; dictionary["h3_axis_nonzero_dvc_count_move_speed"] = qualitySnapshot.NonzeroDvcCountMoveSpeed; dictionary["h3_axis_nonzero_dvc_count_attack_speed"] = qualitySnapshot.NonzeroDvcCountAttackSpeed; dictionary["h3_axis_nonzero_dvc_count_attack_damage"] = qualitySnapshot.NonzeroDvcCountAttackDamage; dictionary["h3_axis_has_variance_hp"] = qualitySnapshot.HasVarianceHp; dictionary["h3_axis_has_variance_move_speed"] = qualitySnapshot.HasVarianceMoveSpeed; dictionary["h3_axis_has_variance_attack_speed"] = qualitySnapshot.HasVarianceAttackSpeed; dictionary["h3_axis_has_variance_attack_damage"] = qualitySnapshot.HasVarianceAttackDamage; dictionary["h3_axis_mean_abs_error"] = num19; dictionary["h3_legacy_virtual_gap_abs"] = num13; dictionary["sgd_vp_has_baseline"] = SgdDecisionRuntimeState.HasBaselineVirtualPower; dictionary["sgd_vp_baseline"] = SgdDecisionRuntimeState.BaselineVirtualPowerTotal; dictionary["sgd_vp_baseline_hp"] = SgdDecisionRuntimeState.BaselineVirtualPower.Hp; dictionary["sgd_vp_baseline_move_speed"] = SgdDecisionRuntimeState.BaselineVirtualPower.MoveSpeed; dictionary["sgd_vp_baseline_attack_speed"] = SgdDecisionRuntimeState.BaselineVirtualPower.AttackSpeed; dictionary["sgd_vp_baseline_attack_damage"] = SgdDecisionRuntimeState.BaselineVirtualPower.AttackDamage; dictionary["sgd_vp_delta_for_decision"] = SgdDecisionRuntimeState.LastVirtualPowerDeltaTotal; dictionary["sgd_vp_delta_hp_for_decision"] = SgdDecisionRuntimeState.LastVirtualPowerDelta.Hp; dictionary["sgd_vp_delta_move_speed_for_decision"] = SgdDecisionRuntimeState.LastVirtualPowerDelta.MoveSpeed; dictionary["sgd_vp_delta_attack_speed_for_decision"] = SgdDecisionRuntimeState.LastVirtualPowerDelta.AttackSpeed; dictionary["sgd_vp_delta_attack_damage_for_decision"] = SgdDecisionRuntimeState.LastVirtualPowerDelta.AttackDamage; dictionary["sgd_vc_decision_current"] = SgdDecisionRuntimeState.LastVirtualChallengeTotal; dictionary["sgd_vc_hp_decision_current"] = SgdDecisionRuntimeState.LastVirtualChallenge.Hp; dictionary["sgd_vc_move_speed_decision_current"] = SgdDecisionRuntimeState.LastVirtualChallenge.MoveSpeed; dictionary["sgd_vc_attack_speed_decision_current"] = SgdDecisionRuntimeState.LastVirtualChallenge.AttackSpeed; dictionary["sgd_vc_attack_damage_decision_current"] = SgdDecisionRuntimeState.LastVirtualChallenge.AttackDamage; dictionary["sgd_virtual_error_for_decision"] = SgdDecisionRuntimeState.LastVirtualErrorTotal; dictionary["sgd_virtual_error_hp_for_decision"] = SgdDecisionRuntimeState.LastVirtualError.Hp; dictionary["sgd_virtual_error_move_speed_for_decision"] = SgdDecisionRuntimeState.LastVirtualError.MoveSpeed; dictionary["sgd_virtual_error_attack_speed_for_decision"] = SgdDecisionRuntimeState.LastVirtualError.AttackSpeed; dictionary["sgd_virtual_error_attack_damage_for_decision"] = SgdDecisionRuntimeState.LastVirtualError.AttackDamage; dictionary["sgd_virtual_power_scale"] = 0.2f; dictionary["sgd_virtual_loss_weight"] = 0.12f; dictionary["sgd_hp_virtual_error_contribution"] = SgdDecisionRuntimeState.LastVirtualPowerContributionHp; dictionary["sgd_ms_virtual_error_contribution"] = SgdDecisionRuntimeState.LastVirtualPowerContributionMs; dictionary["sgd_as_virtual_error_contribution"] = SgdDecisionRuntimeState.LastVirtualPowerContributionAs; dictionary["sgd_dmg_virtual_error_contribution"] = SgdDecisionRuntimeState.LastVirtualPowerContributionDmg; AddPlayerBuildProperties(dictionary, FindAnyPlayerBody()); session.RecordSample(Mathf.Abs(num9), Mathf.Abs(num10), Mathf.Abs(num11), Mathf.Abs(num12), num, num2, num3, num4, num5, num6, num7, num8, num18, snapshot, in s, dt); session.SetPreviousVirtuals(in h3AxisDecisionSnapshot.VirtualPower, in h3AxisDecisionSnapshot.VirtualChallenge); dictionary["degradation_signal"] = num20; dictionary["is_degraded"] = session.IsDegraded; dictionary["is_degraded_050"] = num20 >= 0.5f; dictionary["is_degraded_060"] = num20 >= 0.6f; dictionary["is_degraded_070"] = num20 >= 0.7f; dictionary["degradation_signal_above_050_seconds"] = session.DegradationSignalAbove050Seconds; dictionary["degradation_signal_above_060_seconds"] = session.DegradationSignalAbove060Seconds; dictionary["degradation_signal_above_070_seconds"] = session.DegradationSignalAbove070Seconds; dictionary["degradation_signal_below_recovery_seconds"] = session.DegradationSignalBelowRecoverySeconds; dictionary["recovery_elapsed_seconds"] = session.RecoveryElapsedSeconds; dictionary["current_degradation_trigger"] = session.CurrentDegradationTrigger; dictionary["current_degradation_trigger_value"] = session.CurrentDegradationTriggerValue; return new TelemetryEvent("dda_sample", dictionary); } public static TelemetryEvent BuildRecovery(TelemetrySessionState session, float recoverySeconds) { Dictionary dictionary = BuildCommonProperties(session); dictionary["event_kind"] = "recovery"; dictionary["recovery_elapsed_seconds"] = recoverySeconds; dictionary["recovery_events_count"] = session.RecoveryEventsCount; return new TelemetryEvent("dda_recovery", dictionary); } public static TelemetryEvent BuildDegradationTransition(TelemetrySessionState session, TelemetryDegradationTransition transition) { Dictionary dictionary = BuildCommonProperties(session); dictionary["event_kind"] = transition.EventKind; dictionary["transition_run_elapsed_seconds"] = transition.RunElapsedSeconds; dictionary["recovery_elapsed_seconds"] = transition.RecoveryElapsedSeconds; dictionary["degradation_trigger"] = transition.Trigger; dictionary["degradation_trigger_value"] = transition.TriggerValue; dictionary["degradation_signal"] = transition.DegradationSignal; dictionary["incoming_damage_norm01"] = transition.IncomingDamageNorm01; dictionary["deaths_per_window_norm01"] = transition.DeathsPerWindowNorm01; dictionary["low_health_uptime"] = transition.LowHealthUptime; dictionary["mean_abs_error_all_axes"] = transition.MeanAbsError; dictionary["degradation_threshold"] = ConfigManager.telemetryDegradationThreshold.Value; dictionary["recovery_threshold"] = ConfigManager.telemetryRecoveryThreshold.Value; dictionary["degradation_signal_above_050_seconds"] = session.DegradationSignalAbove050Seconds; dictionary["degradation_signal_above_060_seconds"] = session.DegradationSignalAbove060Seconds; dictionary["degradation_signal_above_070_seconds"] = session.DegradationSignalAbove070Seconds; dictionary["degradation_signal_below_recovery_seconds"] = session.DegradationSignalBelowRecoverySeconds; return new TelemetryEvent((transition.EventKind == "degradation_start") ? "dda_degradation_start" : "dda_degradation_end", dictionary); } public static TelemetryEvent BuildPlayerDeath(TelemetrySessionState session, CharacterBody body, DamageInfo damageInfo) { Dictionary dictionary = BuildCommonProperties(session); dictionary["event_kind"] = "player_death"; dictionary["player_deaths_count"] = session.PlayerDeathsCount; dictionary["death_body_name"] = (((Object)(object)body != (Object)null) ? body.GetDisplayName() : ""); dictionary["death_damage"] = damageInfo?.damage ?? 0f; dictionary["death_damage_type"] = ((damageInfo != null) ? ((object)(DamageTypeCombo)(ref damageInfo.damageType)).ToString() : ""); dictionary["death_attacker_body"] = GetAttackerBodyName(damageInfo); AddPlayerBuildProperties(dictionary, body); return new TelemetryEvent("dda_player_death", dictionary); } public static TelemetryEvent BuildPostSessionSurvey(TelemetrySessionState session, int fairnessLikert, int continuityLikert, string comment) { Dictionary dictionary = BuildCommonProperties(session); dictionary["event_kind"] = "post_session_survey"; dictionary["fairness_likert_1_7"] = fairnessLikert; dictionary["continuity_likert_1_7"] = continuityLikert; dictionary["survey_comment"] = comment ?? ""; return new TelemetryEvent("dda_post_session_survey", dictionary); } public static TelemetryEvent BuildPostSessionSurveySkipped(TelemetrySessionState session, string comment) { Dictionary dictionary = BuildCommonProperties(session); dictionary["event_kind"] = "post_session_survey_skipped"; dictionary["survey_comment"] = comment ?? ""; return new TelemetryEvent("dda_post_session_survey_skipped", dictionary); } public static TelemetryEvent BuildSessionEnd(TelemetrySessionState session, string endReason) { Dictionary dictionary = BuildCommonProperties(session); dictionary["event_kind"] = "session_end"; dictionary["end_reason"] = endReason ?? "run_destroyed"; dictionary["duration_seconds"] = session.ElapsedSeconds; dictionary["samples_count"] = session.SamplesCount; dictionary["mean_abs_error_max_health"] = session.MeanAbsErrorMaxHealth; dictionary["mean_abs_error_move_speed"] = session.MeanAbsErrorMoveSpeed; dictionary["mean_abs_error_attack_speed"] = session.MeanAbsErrorAttackSpeed; dictionary["mean_abs_error_attack_damage"] = session.MeanAbsErrorAttackDamage; dictionary["jump_rate_all_axes"] = session.JumpRateAllAxes; dictionary["smoothness_observations"] = session.SmoothnessObservations; dictionary["mean_abs_delta_multiplier"] = session.MeanAbsDeltaMultiplier; dictionary["mean_abs_delta_theta"] = session.MeanAbsDeltaTheta; dictionary["mean_abs_relative_delta_multiplier"] = session.MeanAbsRelativeDeltaMultiplier; dictionary["max_abs_delta_multiplier"] = session.MaxAbsDeltaMultiplier; dictionary["mean_virtual_gap_abs"] = session.MeanVirtualGapAbs; dictionary["h3_axis_mean_abs_error"] = (session.MeanAbsErrorMaxHealth + session.MeanAbsErrorMoveSpeed + session.MeanAbsErrorAttackSpeed + session.MeanAbsErrorAttackDamage) * 0.25f; dictionary["recovery_events_count"] = session.RecoveryEventsCount; dictionary["degradation_events_count"] = session.DegradationEventsCount; dictionary["mean_recovery_seconds"] = session.MeanRecoverySeconds; dictionary["degradation_signal_above_050_seconds"] = session.DegradationSignalAbove050Seconds; dictionary["degradation_signal_above_060_seconds"] = session.DegradationSignalAbove060Seconds; dictionary["degradation_signal_above_070_seconds"] = session.DegradationSignalAbove070Seconds; dictionary["degradation_signal_below_recovery_seconds"] = session.DegradationSignalBelowRecoverySeconds; dictionary["player_deaths_count"] = session.PlayerDeathsCount; dictionary["missed_sample_intervals"] = session.MissedSampleIntervals; dictionary["minimum_session_seconds"] = ConfigManager.telemetryMinimumSessionSeconds.Value; dictionary["is_quality_excluded_short_session"] = session.ElapsedSeconds < ConfigManager.telemetryMinimumSessionSeconds.Value; dictionary["fairness_likert_1_7"] = session.SurveyFairnessLikert; dictionary["continuity_likert_1_7"] = session.SurveyContinuityLikert; dictionary["survey_comment"] = session.SurveyComment; return new TelemetryEvent("dda_session_end", dictionary); } private static Dictionary BuildCommonProperties(TelemetrySessionState session) { TelemetryDifficultySnapshot telemetryDifficultySnapshot = TelemetryDifficultySnapshot.Capture(); string value = (string.IsNullOrWhiteSpace(session.SessionMode) ? telemetryDifficultySnapshot.Mode : session.SessionMode); Dictionary obj = new Dictionary { ["distinct_id"] = ConfigManager.telemetryAnonymousUserId.Value, ["$process_person_profile"] = false, ["session_id"] = session.SessionId, ["participant_id"] = GetParticipantId(), ["mod_version"] = "4.5.12", ["telemetry_schema_version"] = 7, ["experiment_id"] = ConfigManager.telemetryExperimentId.Value, ["condition_order"] = ConfigManager.telemetryConditionOrder.Value, ["run_attempt_index"] = ConfigManager.telemetryRunAttemptIndex.Value, ["configured_run_seed"] = ConfigManager.telemetryConfiguredRunSeed.Value, ["research_seed_cycle"] = ConfigManager.researchRunSeedCycle.Value, ["research_seed_index"] = ConfigManager.researchCurrentRunSeedIndex.Value, ["research_cycle_seed"] = ConfigManager.researchCurrentRunSeed.Value, ["research_seed_rotation_enabled"] = ConfigManager.researchAutoRotateRunSeeds.Value, ["runtime_run_seed"] = GetRuntimeRunSeed(), ["run_elapsed_seconds"] = session.ElapsedSeconds }; Stage instance = Stage.instance; object obj2; if (instance == null) { obj2 = null; } else { SceneDef sceneDef = instance.sceneDef; obj2 = ((sceneDef != null) ? sceneDef.baseSceneName : null); } if (obj2 == null) { obj2 = ""; } obj["stage_name"] = obj2; obj["stage_index"] = (((Object)(object)Run.instance != (Object)null) ? (Run.instance.stageClearCount + 1) : 0); obj["player_body"] = SgdSensorsRuntimeState.PlayerBodyName; obj["dda_mode"] = value; obj["dda_mode_current"] = telemetryDifficultySnapshot.Mode; obj["artifact_enabled"] = IsArtifactEnabled(); obj["is_network_server"] = NetworkServer.active; obj["queue_count"] = TelemetryEventQueue.Count; obj["missed_sample_intervals"] = session.MissedSampleIntervals; obj["sgd_total_steps_done"] = SgdDecisionRuntimeState.TotalStepsDone; obj["sgd_applied_monsters_last"] = SgdDecisionRuntimeState.AppliedMonstersLast; AddExperimentConfigProperties(obj); return obj; } private static void AddSensorProperties(Dictionary props, in SgdSensorsSample s) { props["incoming_damage_rate"] = s.IncomingDamageRate; props["incoming_damage_norm01"] = s.IncomingDamageNorm01; props["outgoing_damage_rate"] = s.OutgoingDamageRate; props["outgoing_damage_norm01"] = s.OutgoingDamageNorm01; props["hit_rate_on_player"] = s.HitRateOnPlayer; props["hit_rate_on_player_norm01"] = s.HitRateOnPlayerNorm01; props["combat_uptime"] = s.CombatUptime; props["low_health_uptime"] = s.LowHealthUptime; props["deaths_per_window"] = s.DeathsPerWindow; props["deaths_per_window_norm01"] = s.DeathsPerWindowNorm01; props["avg_ttk_seconds"] = s.AvgTtkSeconds; props["avg_ttk_seconds_norm01"] = s.AvgTtkSecondsNorm01; } private static void AddAxisProperties(Dictionary props, string axis, string plane, float skill01, float challenge01, float error, float multiplier, float previousMultiplier, float previousSkill01, float previousChallenge01, bool hasPrevious, bool isJump) { string text = "axis_" + axis + "_"; float num = Mathf.Max(0.0001f, multiplier); float num2 = Mathf.Max(0.0001f, previousMultiplier); float num3 = (hasPrevious ? (multiplier - previousMultiplier) : 0f); float num4 = (hasPrevious ? (Mathf.Log(num) - Mathf.Log(num2)) : 0f); float num5 = (hasPrevious ? (num3 / num2) : 0f); props[text + "plane"] = plane; props[text + "skill01"] = skill01; props[text + "challenge01"] = challenge01; props[text + "error"] = error; props[text + "abs_error"] = Mathf.Abs(error); props[text + "multiplier"] = multiplier; props[text + "previous_multiplier"] = previousMultiplier; props[text + "delta_multiplier"] = num3; props[text + "abs_delta_multiplier"] = Mathf.Abs(num3); props[text + "delta_theta"] = num4; props[text + "abs_delta_theta"] = Mathf.Abs(num4); props[text + "relative_delta_multiplier"] = num5; props[text + "abs_relative_delta_multiplier"] = Mathf.Abs(num5); props[text + "delta_skill01"] = (hasPrevious ? (skill01 - previousSkill01) : 0f); props[text + "delta_challenge01"] = (hasPrevious ? (challenge01 - previousChallenge01) : 0f); props[text + "is_jump"] = isJump; } private static void AddExperimentConfigProperties(Dictionary props) { props["tau_jump"] = ConfigManager.telemetryJumpThreshold.Value; props["epsilon_v"] = ConfigManager.telemetryVirtualGapEpsilon.Value; props["epsilon_stable"] = ConfigManager.telemetryStableErrorEpsilon.Value; props["degradation_threshold"] = ConfigManager.telemetryDegradationThreshold.Value; props["recovery_threshold"] = ConfigManager.telemetryRecoveryThreshold.Value; props["sample_interval_seconds"] = ConfigManager.telemetrySampleIntervalSeconds.Value; props["minimum_session_seconds"] = ConfigManager.telemetryMinimumSessionSeconds.Value; props["sgd_step_seconds"] = SgdDecisionRuntimeState.StepSeconds; props["sgd_momentum"] = 0.65f; props["sgd_gradient_clip"] = 0.5f; props["sgd_velocity_clip"] = 1f; props["sgd_error_dead_zone"] = 0.03f; props["sgd_virtual_power_scale"] = 0.2f; props["sgd_virtual_loss_weight"] = 0.12f; props["sgd_hp_virtual_challenge_weight"] = 0.35f; props["sgd_ms_virtual_challenge_weight"] = 0.15f; props["sgd_as_virtual_challenge_weight"] = 0.2f; props["sgd_dmg_virtual_challenge_weight"] = 0.3f; props["sgd_hp_learning_rate"] = 0.22f; props["sgd_ms_learning_rate"] = 0.2f; props["sgd_as_learning_rate"] = 0.2f; props["sgd_dmg_learning_rate"] = 0.18f; props["sgd_hp_max_delta_theta"] = 0.06f; props["sgd_ms_max_delta_theta"] = 0.05f; props["sgd_as_max_delta_theta"] = 0.045f; props["sgd_dmg_max_delta_theta"] = 0.05f; props["sgd_hp_floor"] = ConfigManager.sgdHpFloor.Value; props["sgd_hp_cap"] = ConfigManager.sgdHpCap.Value; props["sgd_ms_floor"] = ConfigManager.sgdMsFloor.Value; props["sgd_ms_cap"] = ConfigManager.sgdMsCap.Value; props["sgd_as_floor"] = ConfigManager.sgdAsFloor.Value; props["sgd_as_cap"] = ConfigManager.sgdAsCap.Value; props["sgd_dmg_floor"] = ConfigManager.sgdDmgFloor.Value; props["sgd_dmg_cap"] = ConfigManager.sgdDmgCap.Value; AddAppliedSgdAxisLimitProperties(props); props["ga_governor_type"] = ConfigManager.governorType.Value; props["ga_time_limit_seconds"] = ConfigManager.timeLimit.Value; props["ga_death_limit"] = ConfigManager.deathLimit.Value; props["ga_gene_variance_limit"] = ConfigManager.geneVarianceLimit.Value; props["ga_gene_cap"] = ConfigManager.geneCap.Value; props["ga_gene_floor"] = ConfigManager.geneFloor.Value; props["ga_gene_product_limit"] = ConfigManager.geneProductLimit.Value; } private static void AddAppliedSgdAxisLimitProperties(Dictionary props) { AddAppliedSgdAxisLimitProperties(props, "hp", GeneStat.MaxHealth); AddAppliedSgdAxisLimitProperties(props, "ms", GeneStat.MoveSpeed); AddAppliedSgdAxisLimitProperties(props, "as", GeneStat.AttackSpeed); AddAppliedSgdAxisLimitProperties(props, "dmg", GeneStat.AttackDamage); } private static void AddAppliedSgdAxisLimitProperties(Dictionary props, string prefix, GeneStat stat) { SgdAxisLimitProvider.GetLimits(stat, out var floor, out var cap); float num = Mathf.Log(floor); float num2 = Mathf.Log(cap); float num3 = Mathf.Max(0.0001f, num2 - num); float num4 = Mathf.Clamp01((0f - num) / num3); props["sgd_" + prefix + "_floor_applied"] = floor; props["sgd_" + prefix + "_cap_applied"] = cap; props["sgd_" + prefix + "_theta_min_applied"] = num; props["sgd_" + prefix + "_theta_max_applied"] = num2; props["sgd_" + prefix + "_theta_range_applied"] = num3; props["sgd_" + prefix + "_neutral_challenge01"] = num4; } private static void AddPlayerBuildProperties(Dictionary props, CharacterBody body) { if ((Object)(object)body == (Object)null) { props["player_build_available"] = false; return; } props["player_build_available"] = true; props["player_body_name"] = body.GetDisplayName(); props["player_level"] = body.level; props["player_damage"] = body.damage; props["player_attack_speed"] = body.attackSpeed; props["player_crit"] = body.crit; props["player_max_health"] = body.maxHealth; props["player_max_shield"] = body.maxShield; props["player_regen"] = body.regen; props["player_armor"] = body.armor; props["player_move_speed"] = body.moveSpeed; SgdVirtualPowerSample sgdVirtualPowerSample = SgdVirtualPowerEstimator.ComputeRaw(body); SgdBuildPowerAxisWeights sgdBuildPowerAxisWeights = SgdBuildPowerItemModel.EstimateInventoryBonus(body.inventory); props["virtual_power_raw_hp"] = sgdVirtualPowerSample.Hp; props["virtual_power_raw_move_speed"] = sgdVirtualPowerSample.MoveSpeed; props["virtual_power_raw_attack_speed"] = sgdVirtualPowerSample.AttackSpeed; props["virtual_power_raw_attack_damage"] = sgdVirtualPowerSample.AttackDamage; props["virtual_power_raw_offense"] = sgdVirtualPowerSample.AttackDamage; props["virtual_power_raw_defense"] = sgdVirtualPowerSample.Hp; props["virtual_power_raw_mobility"] = sgdVirtualPowerSample.MoveSpeed; props["virtual_power_item_bonus_hp"] = sgdBuildPowerAxisWeights.Hp; props["virtual_power_item_bonus_move_speed"] = sgdBuildPowerAxisWeights.MoveSpeed; props["virtual_power_item_bonus_attack_speed"] = sgdBuildPowerAxisWeights.AttackSpeed; props["virtual_power_item_bonus_attack_damage"] = sgdBuildPowerAxisWeights.AttackDamage; props["virtual_power_weight_hp"] = 0.25f; props["virtual_power_weight_move_speed"] = 0.25f; props["virtual_power_weight_attack_speed"] = 0.25f; props["virtual_power_weight_attack_damage"] = 0.25f; props["virtual_power_weight_offense"] = 0.25f; props["virtual_power_weight_defense"] = 0.25f; props["virtual_power_weight_mobility"] = 0.25f; props["virtual_power_regen_weight"] = 25f; props["player_unique_items"] = CountUniqueItems(body.inventory); props["player_item_stacks_total"] = CountItemStacks(body.inventory); props["player_items_compact"] = BuildItemSummary(body.inventory); } private static CharacterBody FindAnyPlayerBody() { //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Invalid comparison between Unknown and I4 foreach (CharacterBody readOnlyInstances in CharacterBody.readOnlyInstancesList) { if ((Object)(object)readOnlyInstances != (Object)null && readOnlyInstances.isPlayerControlled) { return readOnlyInstances; } } foreach (CharacterBody readOnlyInstances2 in CharacterBody.readOnlyInstancesList) { if ((Object)(object)readOnlyInstances2 != (Object)null && (Object)(object)readOnlyInstances2.teamComponent != (Object)null && (int)readOnlyInstances2.teamComponent.teamIndex == 1) { return readOnlyInstances2; } } return null; } private static string GetParticipantId() { string text = ConfigManager.telemetryParticipantId?.Value; if (!string.IsNullOrWhiteSpace(text)) { return text.Trim(); } return ConfigManager.telemetryAnonymousUserId.Value; } private static string GetRuntimeRunSeed() { Run instance = Run.instance; if ((Object)(object)instance == (Object)null) { return ""; } Type type = ((object)instance).GetType(); FieldInfo fieldInfo = type.GetField("seed", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? type.GetField("runSeed", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (fieldInfo != null) { object value = fieldInfo.GetValue(instance); if (value == null) { return ""; } return value.ToString(); } PropertyInfo propertyInfo = type.GetProperty("seed", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? type.GetProperty("runSeed", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (propertyInfo != null) { object value2 = propertyInfo.GetValue(instance, null); if (value2 == null) { return ""; } return value2.ToString(); } return ""; } private static string GetAttackerBodyName(DamageInfo damageInfo) { if ((Object)(object)damageInfo?.attacker == (Object)null) { return ""; } CharacterBody component = damageInfo.attacker.GetComponent(); if (!((Object)(object)component != (Object)null)) { return ((Object)damageInfo.attacker).name; } return component.GetDisplayName(); } private static int CountUniqueItems(Inventory inventory) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) int num = 0; foreach (ItemIndex item in EnumerateAcquiredItems(inventory)) { if (inventory.GetItemCount(item) > 0) { num++; } } return num; } private static int CountItemStacks(Inventory inventory) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: 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) int num = 0; foreach (ItemIndex item in EnumerateAcquiredItems(inventory)) { num += Mathf.Max(0, inventory.GetItemCount(item)); } return num; } private static string BuildItemSummary(Inventory inventory) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)inventory == (Object)null) { return ""; } StringBuilder stringBuilder = new StringBuilder(256); foreach (ItemIndex item in EnumerateAcquiredItems(inventory)) { ItemIndex current = item; int itemCount = inventory.GetItemCount(current); if (itemCount > 0) { if (stringBuilder.Length > 0) { stringBuilder.Append("|"); } ItemDef itemDef = ItemCatalog.GetItemDef(current); string text = (((Object)(object)itemDef != (Object)null) ? ((Object)itemDef).name : ((object)(ItemIndex)(ref current)).ToString()); stringBuilder.Append(text.Replace("|", "_").Replace(":", "_")); stringBuilder.Append(":"); stringBuilder.Append(itemCount); } } return stringBuilder.ToString(); } [IteratorStateMachine(typeof(d__22))] private static IEnumerable EnumerateAcquiredItems(Inventory inventory) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__22(-2) { <>3__inventory = inventory }; } private static float EstimateAttackSpeedSkill01(in SgdSensorsSample s) { float num = 1f - Mathf.Clamp01(s.HitRateOnPlayerNorm01); float num2 = 1f - Mathf.Clamp01(s.IncomingDamageNorm01); float num3 = 1f - Mathf.Clamp01(s.LowHealthUptime); float num4 = 1f - Mathf.Clamp01(s.DeathsPerWindowNorm01); return ClampSkill(0.4f * num + 0.35f * num2 + 0.2f * num3 + 0.05f * num4); } private static float EstimateMaxHealthSkill01(in SgdSensorsSample s) { float num = Mathf.Clamp01(s.OutgoingDamageNorm01); float num2 = ((s.AvgTtkSeconds > 0.01f) ? (1f - Mathf.Clamp01(s.AvgTtkSecondsNorm01)) : 0.5f); float num3 = 1f - Mathf.Clamp01(s.LowHealthUptime); return ClampSkill(0.45f * num + 0.45f * num2 + 0.1f * num3); } private static float EstimateMoveSpeedSkill01(in SgdSensorsSample s) { float num = 1f - Mathf.Clamp01(s.HitRateOnPlayerNorm01); float num2 = 1f - Mathf.Clamp01(s.IncomingDamageNorm01); float num3 = Mathf.Clamp01(s.OutgoingDamageNorm01); float num4 = 1f - Mathf.Clamp01(s.LowHealthUptime); return ClampSkill(0.45f * num + 0.25f * num2 + 0.2f * num3 + 0.1f * num4); } private static float EstimateAttackDamageSkill01(in SgdSensorsSample s) { float num = 1f - Mathf.Clamp01(s.IncomingDamageNorm01); float num2 = 1f - Mathf.Clamp01(s.LowHealthUptime); float num3 = 1f - Mathf.Clamp01(s.DeathsPerWindowNorm01); float num4 = 1f - Mathf.Clamp01(s.HitRateOnPlayerNorm01); return ClampSkill(0.45f * num + 0.3f * num2 + 0.2f * num3 + 0.05f * num4); } private static float Challenge01(GeneStat stat, float multiplier) { SgdAxisLimitProvider.GetLimits(stat, out var floor, out var cap); float num = Mathf.Log(floor); float num2 = Mathf.Log(cap); float num3 = Mathf.Max(0.0001f, num2 - num); return Mathf.Clamp01((Mathf.Clamp(Mathf.Log(Mathf.Max(0.0001f, multiplier)), num, num2) - num) / num3); } private static float ComputeVirtualChallenge(TelemetryDifficultySnapshot snapshot) { SgdVirtualPowerSample sgdVirtualPowerSample = ComputeVirtualChallengeAxes(snapshot); return 0.35f * sgdVirtualPowerSample.Hp + 0.15f * sgdVirtualPowerSample.MoveSpeed + 0.2f * sgdVirtualPowerSample.AttackSpeed + 0.3f * sgdVirtualPowerSample.AttackDamage; } private static SgdVirtualPowerSample ComputeVirtualChallengeAxes(TelemetryDifficultySnapshot snapshot) { return new SgdVirtualPowerSample(SafeLog(snapshot.MaxHealth), SafeLog(snapshot.MoveSpeed), SafeLog(snapshot.AttackSpeed), SafeLog(snapshot.AttackDamage)); } private static SgdVirtualPowerSample Subtract(in SgdVirtualPowerSample a, in SgdVirtualPowerSample b) { return new SgdVirtualPowerSample(a.Hp - b.Hp, a.MoveSpeed - b.MoveSpeed, a.AttackSpeed - b.AttackSpeed, a.AttackDamage - b.AttackDamage); } private static bool IsArtifactEnabled() { if ((Object)(object)RunArtifactManager.instance != (Object)null && (Object)(object)ArtifactOfGenetics.artifactDef != (Object)null) { return RunArtifactManager.instance.IsArtifactEnabled(ArtifactOfGenetics.artifactDef); } return false; } private static float ClampSkill(float value) { if (!float.IsNaN(value) && !float.IsInfinity(value)) { return Mathf.Clamp01(value); } return 0f; } private static float SafeLog(float value) { if (float.IsNaN(value) || float.IsInfinity(value) || value <= 0f) { return 0f; } return Mathf.Log(value); } } internal sealed class TelemetryDegradationTransition { public string EventKind { get; } public float RunElapsedSeconds { get; } public float RecoveryElapsedSeconds { get; } public string Trigger { get; } public float TriggerValue { get; } public float DegradationSignal { get; } public float IncomingDamageNorm01 { get; } public float DeathsPerWindowNorm01 { get; } public float LowHealthUptime { get; } public float MeanAbsError { get; } public TelemetryDegradationTransition(string eventKind, float runElapsedSeconds, float recoveryElapsedSeconds, string trigger, float triggerValue, float degradationSignal, in SgdSensorsSample sensors, float meanAbsError) { EventKind = eventKind; RunElapsedSeconds = Sanitize(runElapsedSeconds); RecoveryElapsedSeconds = Sanitize(recoveryElapsedSeconds); Trigger = trigger ?? ""; TriggerValue = Sanitize(triggerValue); DegradationSignal = Sanitize(degradationSignal); IncomingDamageNorm01 = Sanitize(sensors.IncomingDamageNorm01); DeathsPerWindowNorm01 = Sanitize(sensors.DeathsPerWindowNorm01); LowHealthUptime = Sanitize(sensors.LowHealthUptime); MeanAbsError = Sanitize(meanAbsError); } private static float Sanitize(float value) { if (!float.IsNaN(value) && !float.IsInfinity(value)) { return Mathf.Max(0f, value); } return 0f; } } internal sealed class TelemetrySessionState { private bool _hasPreviousSnapshot; private float _pendingRecoverySeconds = -1f; private readonly Queue _pendingDegradationTransitions = new Queue(); public string SessionId { get; private set; } = ""; public string SessionMode { get; private set; } = ""; public float StartedAtUnityTime { get; private set; } public int SamplesCount { get; private set; } public int RecoveryEventsCount { get; private set; } public int DegradationEventsCount { get; private set; } public int PlayerDeathsCount { get; private set; } public int MissedSampleIntervals { get; private set; } public int SurveyFairnessLikert { get; private set; } public int SurveyContinuityLikert { get; private set; } public string SurveyComment { get; private set; } = ""; public bool HasSurveyCompleted { get; private set; } public bool HasSessionEndQueued { get; private set; } public bool HasSurvey { get { if (SurveyFairnessLikert > 0) { return SurveyContinuityLikert > 0; } return false; } } public float PreviousMaxHealthMultiplier { get; private set; } = 1f; public float PreviousMoveSpeedMultiplier { get; private set; } = 1f; public float PreviousAttackSpeedMultiplier { get; private set; } = 1f; public float PreviousAttackDamageMultiplier { get; private set; } = 1f; public float PreviousMaxHealthSkill01 { get; private set; } public float PreviousMoveSpeedSkill01 { get; private set; } public float PreviousAttackSpeedSkill01 { get; private set; } public float PreviousAttackDamageSkill01 { get; private set; } public float PreviousMaxHealthChallenge01 { get; private set; } public float PreviousMoveSpeedChallenge01 { get; private set; } public float PreviousAttackSpeedChallenge01 { get; private set; } public float PreviousAttackDamageChallenge01 { get; private set; } public float PreviousVirtualPower { get; private set; } public float PreviousVirtualChallenge { get; private set; } public SgdVirtualPowerSample PreviousVirtualPowerAxes { get; private set; } public SgdVirtualPowerSample PreviousVirtualChallengeAxes { get; private set; } public float SumAbsErrorMaxHealth { get; private set; } public float SumAbsErrorMoveSpeed { get; private set; } public float SumAbsErrorAttackSpeed { get; private set; } public float SumAbsErrorAttackDamage { get; private set; } public int JumpCount { get; private set; } public int JumpObservations { get; private set; } public int SmoothnessObservations { get; private set; } public float SumAbsDeltaMultiplier { get; private set; } public float SumAbsDeltaTheta { get; private set; } public float SumAbsRelativeDeltaMultiplier { get; private set; } public float MaxAbsDeltaMultiplier { get; private set; } public float SumVirtualGapAbs { get; private set; } public float SumRecoverySeconds { get; private set; } public bool IsDegraded { get; private set; } public float RecoveryElapsedSeconds { get; private set; } public string CurrentDegradationTrigger { get; private set; } = ""; public float CurrentDegradationTriggerValue { get; private set; } public float DegradationSignalAbove050Seconds { get; private set; } public float DegradationSignalAbove060Seconds { get; private set; } public float DegradationSignalAbove070Seconds { get; private set; } public float DegradationSignalBelowRecoverySeconds { get; private set; } public float ElapsedSeconds => Mathf.Max(0f, Time.time - StartedAtUnityTime); public float MeanAbsErrorMaxHealth => Mean(SumAbsErrorMaxHealth, SamplesCount); public float MeanAbsErrorMoveSpeed => Mean(SumAbsErrorMoveSpeed, SamplesCount); public float MeanAbsErrorAttackSpeed => Mean(SumAbsErrorAttackSpeed, SamplesCount); public float MeanAbsErrorAttackDamage => Mean(SumAbsErrorAttackDamage, SamplesCount); public float JumpRateAllAxes { get { if (JumpObservations <= 0) { return 0f; } return (float)JumpCount / (float)JumpObservations; } } public float MeanAbsDeltaMultiplier => Mean(SumAbsDeltaMultiplier, SmoothnessObservations); public float MeanAbsDeltaTheta => Mean(SumAbsDeltaTheta, SmoothnessObservations); public float MeanAbsRelativeDeltaMultiplier => Mean(SumAbsRelativeDeltaMultiplier, SmoothnessObservations); public float MeanVirtualGapAbs => Mean(SumVirtualGapAbs, SamplesCount); public float MeanRecoverySeconds => Mean(SumRecoverySeconds, RecoveryEventsCount); public bool HasPreviousSample => _hasPreviousSnapshot; public void StartNewRun() { H3AxisDecisionState.Reset(); H3GaDecisionObserver.Reset(); SessionId = "run-" + DateTime.UtcNow.ToString("yyyyMMdd-HHmmss") + "-" + Guid.NewGuid().ToString("N").Substring(0, 8); SessionMode = DdaAlgorithmState.GetTelemetryMode(); StartedAtUnityTime = Time.time; SamplesCount = 0; RecoveryEventsCount = 0; DegradationEventsCount = 0; PlayerDeathsCount = 0; MissedSampleIntervals = 0; SurveyFairnessLikert = 0; SurveyContinuityLikert = 0; SurveyComment = ""; HasSurveyCompleted = false; HasSessionEndQueued = false; PreviousMaxHealthMultiplier = 1f; PreviousMoveSpeedMultiplier = 1f; PreviousAttackSpeedMultiplier = 1f; PreviousAttackDamageMultiplier = 1f; PreviousMaxHealthSkill01 = 0f; PreviousMoveSpeedSkill01 = 0f; PreviousAttackSpeedSkill01 = 0f; PreviousAttackDamageSkill01 = 0f; PreviousMaxHealthChallenge01 = 0f; PreviousMoveSpeedChallenge01 = 0f; PreviousAttackSpeedChallenge01 = 0f; PreviousAttackDamageChallenge01 = 0f; PreviousVirtualPower = 0f; PreviousVirtualChallenge = 0f; PreviousVirtualPowerAxes = default(SgdVirtualPowerSample); PreviousVirtualChallengeAxes = default(SgdVirtualPowerSample); SumAbsErrorMaxHealth = 0f; SumAbsErrorMoveSpeed = 0f; SumAbsErrorAttackSpeed = 0f; SumAbsErrorAttackDamage = 0f; JumpCount = 0; JumpObservations = 0; SmoothnessObservations = 0; SumAbsDeltaMultiplier = 0f; SumAbsDeltaTheta = 0f; SumAbsRelativeDeltaMultiplier = 0f; MaxAbsDeltaMultiplier = 0f; SumVirtualGapAbs = 0f; SumRecoverySeconds = 0f; IsDegraded = false; RecoveryElapsedSeconds = 0f; CurrentDegradationTrigger = ""; CurrentDegradationTriggerValue = 0f; DegradationSignalAbove050Seconds = 0f; DegradationSignalAbove060Seconds = 0f; DegradationSignalAbove070Seconds = 0f; DegradationSignalBelowRecoverySeconds = 0f; _hasPreviousSnapshot = false; _pendingRecoverySeconds = -1f; _pendingDegradationTransitions.Clear(); } public void RecordMissedSampleIntervals(int missedIntervals) { if (missedIntervals > 0) { MissedSampleIntervals += missedIntervals; } } public void RecordPlayerDeath() { PlayerDeathsCount++; } public void RecordSurvey(int fairnessLikert, int continuityLikert, string comment) { SurveyFairnessLikert = Mathf.Clamp(fairnessLikert, 1, 7); SurveyContinuityLikert = Mathf.Clamp(continuityLikert, 1, 7); SurveyComment = comment ?? ""; HasSurveyCompleted = true; } public void RecordSurveySkipped(string comment) { SurveyFairnessLikert = 0; SurveyContinuityLikert = 0; SurveyComment = comment ?? ""; HasSurveyCompleted = true; } public void MarkSessionEndQueued() { HasSessionEndQueued = true; } public void RecordSample(float absErrorMaxHealth, float absErrorMoveSpeed, float absErrorAttackSpeed, float absErrorAttackDamage, float maxHealthSkill01, float moveSpeedSkill01, float attackSpeedSkill01, float attackDamageSkill01, float maxHealthChallenge01, float moveSpeedChallenge01, float attackSpeedChallenge01, float attackDamageChallenge01, float virtualGapAbs, TelemetryDifficultySnapshot snapshot, in SgdSensorsSample sensors, float dt) { SamplesCount++; SumAbsErrorMaxHealth += Sanitize(absErrorMaxHealth); SumAbsErrorMoveSpeed += Sanitize(absErrorMoveSpeed); SumAbsErrorAttackSpeed += Sanitize(absErrorAttackSpeed); SumAbsErrorAttackDamage += Sanitize(absErrorAttackDamage); SumVirtualGapAbs += Sanitize(virtualGapAbs); RecordJump(snapshot.MaxHealth, PreviousMaxHealthMultiplier); RecordJump(snapshot.MoveSpeed, PreviousMoveSpeedMultiplier); RecordJump(snapshot.AttackSpeed, PreviousAttackSpeedMultiplier); RecordJump(snapshot.AttackDamage, PreviousAttackDamageMultiplier); float meanAbsError = (absErrorMaxHealth + absErrorMoveSpeed + absErrorAttackSpeed + absErrorAttackDamage) * 0.25f; UpdateRecovery(in sensors, meanAbsError, ComputeDegradationSignal(in sensors, meanAbsError), dt); PreviousMaxHealthSkill01 = maxHealthSkill01; PreviousMoveSpeedSkill01 = moveSpeedSkill01; PreviousAttackSpeedSkill01 = attackSpeedSkill01; PreviousAttackDamageSkill01 = attackDamageSkill01; PreviousMaxHealthChallenge01 = maxHealthChallenge01; PreviousMoveSpeedChallenge01 = moveSpeedChallenge01; PreviousAttackSpeedChallenge01 = attackSpeedChallenge01; PreviousAttackDamageChallenge01 = attackDamageChallenge01; PreviousMaxHealthMultiplier = snapshot.MaxHealth; PreviousMoveSpeedMultiplier = snapshot.MoveSpeed; PreviousAttackSpeedMultiplier = snapshot.AttackSpeed; PreviousAttackDamageMultiplier = snapshot.AttackDamage; _hasPreviousSnapshot = true; } public bool IsJump(float currentMultiplier, float previousMultiplier) { if (!_hasPreviousSnapshot) { return false; } float num = ConfigManager.telemetryJumpThreshold?.Value ?? 0.1f; return Mathf.Abs(currentMultiplier - previousMultiplier) > Mathf.Max(0.001f, num); } public float ComputeDegradationSignal(in SgdSensorsSample sensors, float meanAbsError) { return Mathf.Max(new float[4] { Mathf.Clamp01(sensors.IncomingDamageNorm01), Mathf.Clamp01(sensors.DeathsPerWindowNorm01), Mathf.Clamp01(sensors.LowHealthUptime), Mathf.Clamp01(meanAbsError) }); } public bool TryConsumeRecoveryEvent(out float recoverySeconds) { if (_pendingRecoverySeconds >= 0f) { recoverySeconds = _pendingRecoverySeconds; _pendingRecoverySeconds = -1f; return true; } recoverySeconds = 0f; return false; } public bool TryConsumeDegradationTransition(out TelemetryDegradationTransition transition) { if (_pendingDegradationTransitions.Count > 0) { transition = _pendingDegradationTransitions.Dequeue(); return true; } transition = null; return false; } public void SetPreviousVirtuals(float virtualPower, float virtualChallenge) { PreviousVirtualPower = virtualPower; PreviousVirtualChallenge = virtualChallenge; } public void SetPreviousVirtuals(in SgdVirtualPowerSample virtualPower, in SgdVirtualPowerSample virtualChallenge) { PreviousVirtualPowerAxes = virtualPower; PreviousVirtualChallengeAxes = virtualChallenge; PreviousVirtualPower = virtualPower.Total; PreviousVirtualChallenge = virtualChallenge.Total; } private void RecordJump(float current, float previous) { JumpObservations++; RecordSmoothness(current, previous); if (IsJump(current, previous)) { JumpCount++; } } private void RecordSmoothness(float current, float previous) { if (_hasPreviousSnapshot) { float num = Mathf.Max(0.0001f, current); float num2 = Mathf.Max(0.0001f, previous); float num3 = Mathf.Abs(num - num2); float num4 = Mathf.Abs(Mathf.Log(num) - Mathf.Log(num2)); float num5 = num3 / num2; SmoothnessObservations++; SumAbsDeltaMultiplier += num3; SumAbsDeltaTheta += num4; SumAbsRelativeDeltaMultiplier += num5; MaxAbsDeltaMultiplier = Mathf.Max(MaxAbsDeltaMultiplier, num3); } } private void UpdateRecovery(in SgdSensorsSample sensors, float meanAbsError, float degradationSignal, float dt) { float num = ConfigManager.telemetryDegradationThreshold?.Value ?? 0.3f; float num2 = ConfigManager.telemetryRecoveryThreshold?.Value ?? 0.25f; UpdateDegradationDiagnosticTimers(degradationSignal, num2, dt); if (!IsDegraded && degradationSignal >= num) { DetermineDegradationTrigger(in sensors, meanAbsError, out var trigger, out var triggerValue); IsDegraded = true; RecoveryElapsedSeconds = 0f; CurrentDegradationTrigger = trigger; CurrentDegradationTriggerValue = triggerValue; DegradationEventsCount++; _pendingDegradationTransitions.Enqueue(new TelemetryDegradationTransition("degradation_start", ElapsedSeconds, 0f, trigger, triggerValue, degradationSignal, in sensors, meanAbsError)); return; } if (!IsDegraded) { RecoveryElapsedSeconds = 0f; return; } RecoveryElapsedSeconds += Mathf.Max(0f, dt); if (degradationSignal <= num2) { IsDegraded = false; RecoveryEventsCount++; SumRecoverySeconds += RecoveryElapsedSeconds; _pendingRecoverySeconds = RecoveryElapsedSeconds; _pendingDegradationTransitions.Enqueue(new TelemetryDegradationTransition("degradation_end", ElapsedSeconds, RecoveryElapsedSeconds, CurrentDegradationTrigger, CurrentDegradationTriggerValue, degradationSignal, in sensors, meanAbsError)); CurrentDegradationTrigger = ""; CurrentDegradationTriggerValue = 0f; } } private void UpdateDegradationDiagnosticTimers(float degradationSignal, float recoveryThreshold, float dt) { float num = Mathf.Max(0f, dt); DegradationSignalAbove050Seconds = ((degradationSignal >= 0.5f) ? (DegradationSignalAbove050Seconds + num) : 0f); DegradationSignalAbove060Seconds = ((degradationSignal >= 0.6f) ? (DegradationSignalAbove060Seconds + num) : 0f); DegradationSignalAbove070Seconds = ((degradationSignal >= 0.7f) ? (DegradationSignalAbove070Seconds + num) : 0f); DegradationSignalBelowRecoverySeconds = ((degradationSignal <= recoveryThreshold) ? (DegradationSignalBelowRecoverySeconds + num) : 0f); } private static void DetermineDegradationTrigger(in SgdSensorsSample sensors, float meanAbsError, out string trigger, out float triggerValue) { trigger = "mean_abs_error"; triggerValue = Mathf.Clamp01(meanAbsError); Consider("incoming_damage_norm01", sensors.IncomingDamageNorm01, ref trigger, ref triggerValue); Consider("deaths_per_window_norm01", sensors.DeathsPerWindowNorm01, ref trigger, ref triggerValue); Consider("low_health_uptime", sensors.LowHealthUptime, ref trigger, ref triggerValue); } private static void Consider(string name, float value, ref string trigger, ref float triggerValue) { value = Mathf.Clamp01(value); if (value > triggerValue) { trigger = name; triggerValue = value; } } private static float Mean(float sum, int count) { if (count <= 0) { return 0f; } return sum / (float)count; } private static float Sanitize(float value) { if (!float.IsNaN(value) && !float.IsInfinity(value)) { return Mathf.Max(0f, value); } return 0f; } } internal sealed class TelemetrySurveyWidget : MonoBehaviour { private sealed class SurveyText { public readonly string WindowTitle; public readonly string Intro; public readonly string FairnessQuestion; public readonly string ContinuityQuestion; public readonly string CommentLabel; public readonly string SubmitButton; public readonly string CloseButton; public readonly string SkipAndQuitButton; public readonly string MissingAnswers; public readonly string[] FairnessOptions; public readonly string[] ContinuityOptions; public SurveyText(string windowTitle, string intro, string fairnessQuestion, string continuityQuestion, string commentLabel, string submitButton, string closeButton, string skipAndQuitButton, string missingAnswers, string[] fairnessOptions, string[] continuityOptions) { WindowTitle = windowTitle; Intro = intro; FairnessQuestion = fairnessQuestion; ContinuityQuestion = continuityQuestion; CommentLabel = commentLabel; SubmitButton = submitButton; CloseButton = closeButton; SkipAndQuitButton = skipAndQuitButton; MissingAnswers = missingAnswers; FairnessOptions = fairnessOptions; ContinuityOptions = continuityOptions; } } [CompilerGenerated] private sealed class d__41 : IEnumerator, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__41(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = PostHogBatchClient.FlushAllQueuedEvents(10f, 128); <>1__state = 1; return true; case 1: <>1__state = -1; _allowQuit = true; Application.Quit(); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private const int WindowId = 453216; private const float OverlayOpacity = 0.86f; private static readonly SurveyText RuText = new SurveyText("Опрос после забега DDA", "Пожалуйста, оцените последний забег. Выберите один вариант в каждом вопросе.", "H5. Насколько справедливой ощущалась сложность?", "H6. Насколько плавной и непрерывной ощущалась динамика сложности?", "Комментарий, необязательно:", "Отправить ответы", "Закрыть без отправки", "Пропустить и выйти", "Для отправки нужно выбрать ответ на оба вопроса.", new string[7] { "1 - совсем несправедливо: сложность казалась случайной или наказующей", "2 - скорее несправедливо: часто было ощущение, что игра давит без причины", "3 - немного несправедливо: были заметные спорные моменты сложности", "4 - нейтрально: сложность не казалась ни честной, ни нечестной", "5 - немного справедливо: в основном вызов соответствовал моим действиям", "6 - скорее справедливо: сложность почти всегда ощущалась заслуженной", "7 - полностью справедливо: вызов стабильно соответствовал моей игре" }, new string[7] { "1 - очень рвано: сложность менялась скачками и выбивала из темпа", "2 - рвано: резкие изменения были частыми и заметными", "3 - скорее рвано: иногда динамика сложности ощущалась неестественно", "4 - нейтрально: плавность изменений трудно оценить", "5 - скорее плавно: изменения в основном были постепенными", "6 - плавно: кривая сложности почти не нарушала темп игры", "7 - очень плавно: сложность ощущалась как единая непрерывная кривая" }); private static readonly SurveyText EnText = new SurveyText("DDA Post-Run Survey", "Please rate the last run. Select exactly one answer for each question.", "H5. How fair did the difficulty feel?", "H6. How smooth and continuous did the difficulty curve feel?", "Comment, optional:", "Submit answers", "Close without submitting", "Skip and quit", "Please select an answer for both questions before submitting.", new string[7] { "1 - completely unfair: difficulty felt random or punitive", "2 - mostly unfair: the game often felt harsh without a clear reason", "3 - slightly unfair: there were noticeable questionable difficulty moments", "4 - neutral: difficulty felt neither fair nor unfair", "5 - slightly fair: challenge mostly matched my actions", "6 - mostly fair: difficulty almost always felt earned", "7 - completely fair: challenge consistently matched my play" }, new string[7] { "1 - very abrupt: difficulty changed in jumps and broke the flow", "2 - abrupt: sharp changes were frequent and noticeable", "3 - slightly abrupt: difficulty dynamics sometimes felt unnatural", "4 - neutral: smoothness was hard to judge", "5 - slightly smooth: changes were mostly gradual", "6 - smooth: the difficulty curve almost never disrupted pacing", "7 - very smooth: difficulty felt like one continuous curve" }); private static TelemetrySurveyWidget _instance; private static bool _visible; private static bool _quitAfterClose; private static bool _allowQuit; private static string _triggerReason = ""; private int _fairnessLikert; private int _continuityLikert; private string _comment = ""; private Rect _windowRect; private Vector2 _scroll; private Texture2D _overlayTexture; private GUIStyle _windowStyle; private GUIStyle _introStyle; private GUIStyle _questionStyle; private GUIStyle _optionStyle; private GUIStyle _buttonStyle; private GUIStyle _textAreaStyle; private GUIStyle _missingStyle; private bool _savedCursorState; private bool _previousCursorVisible; private CursorLockMode _previousCursorLockMode; private bool _savedEventSystemState; private bool _previousEventSystemEnabled; private EventSystem _previousEventSystem; private bool _isWaitingForQuitFlush; public static void EnsureAttached() { if (!((Object)(object)_instance != (Object)null) && !((Object)(object)GeneticsArtifactPlugin.Instance == (Object)null)) { _instance = ((Component)GeneticsArtifactPlugin.Instance).gameObject.GetComponent(); if ((Object)(object)_instance == (Object)null) { _instance = ((Component)GeneticsArtifactPlugin.Instance).gameObject.AddComponent(); } } } public static void Show(string triggerReason, bool quitAfterClose = false) { //IL_004f: Unknown result type (might be due to invalid IL or missing references) EnsureAttached(); if (!((Object)(object)_instance == (Object)null) && !TelemetryRuntimeDriver.HasSubmittedSurvey) { if ((Object)(object)EventSystem.current != (Object)null && !(EventSystem.current is MPEventSystem)) { _instance._savedCursorState = true; _instance._previousCursorVisible = true; _instance._previousCursorLockMode = (CursorLockMode)0; } _triggerReason = (string.IsNullOrWhiteSpace(triggerReason) ? "manual" : triggerReason); _quitAfterClose = quitAfterClose; _visible = true; _instance.ResetAnswers(); _instance.RememberCursorState(); _instance.DisableBackgroundEventSystem(); Cursor.visible = true; Cursor.lockState = (CursorLockMode)0; } } private void Awake() { //IL_001b: 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) _instance = this; _windowRect = new Rect(0f, 0f, 760f, 620f); Application.wantsToQuit += WantsToQuit; } private void OnDestroy() { if ((Object)(object)_instance == (Object)(object)this) { _instance = null; } RestoreBackgroundEventSystem(); Application.wantsToQuit -= WantsToQuit; } private static bool WantsToQuit() { if (_allowQuit || !TelemetryRuntimeDriver.HasActiveSession || TelemetryRuntimeDriver.HasSubmittedSurvey) { return true; } Show("exit_attempt", quitAfterClose: true); return false; } private void OnGUI() { //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Expected O, but got Unknown //IL_00c1: Unknown result type (might be due to invalid IL or missing references) if (_visible) { Cursor.visible = true; Cursor.lockState = (CursorLockMode)0; EnsureStyles(); DrawDimmedOverlay(); float num = Mathf.Min(980f, (float)Screen.width - 56f); float num2 = Mathf.Min(780f, (float)Screen.height - 56f); ((Rect)(ref _windowRect)).width = num; ((Rect)(ref _windowRect)).height = num2; ((Rect)(ref _windowRect)).x = ((float)Screen.width - num) * 0.5f; ((Rect)(ref _windowRect)).y = ((float)Screen.height - num2) * 0.5f; SurveyText text = GetText(); GUI.ModalWindow(453216, _windowRect, new WindowFunction(DrawWindow), text.WindowTitle, _windowStyle); } } private void DrawWindow(int id) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0274: Unknown result type (might be due to invalid IL or missing references) //IL_0235: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Invalid comparison between Unknown and I4 SurveyText text = GetText(); GUILayout.BeginVertical(Array.Empty()); GUILayout.Space(18f); GUILayout.Label(text.Intro, _introStyle, Array.Empty()); GUILayout.Space(14f); _scroll = GUILayout.BeginScrollView(_scroll, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandHeight(true) }); GUILayout.Label(text.FairnessQuestion, _questionStyle, Array.Empty()); _fairnessLikert = DrawLikertOptions(text.FairnessOptions, _fairnessLikert); GUILayout.Space(22f); GUILayout.Label(text.ContinuityQuestion, _questionStyle, Array.Empty()); _continuityLikert = DrawLikertOptions(text.ContinuityOptions, _continuityLikert); GUILayout.Space(22f); GUILayout.Label(text.CommentLabel, _questionStyle, Array.Empty()); _comment = GUILayout.TextArea(_comment ?? "", _textAreaStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.MinHeight(76f) }); GUILayout.EndScrollView(); GUILayout.Space(14f); GUILayout.BeginHorizontal(Array.Empty()); GUI.enabled = !_isWaitingForQuitFlush && _fairnessLikert > 0 && _continuityLikert > 0; if (GUILayout.Button(text.SubmitButton, _buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(48f) })) { SubmitSurvey(); } GUI.enabled = !_isWaitingForQuitFlush; if (GUILayout.Button(_quitAfterClose ? text.SkipAndQuitButton : text.CloseButton, _buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(48f) })) { string comment = "ui_trigger=" + _triggerReason; CloseWidget(); TelemetryRuntimeDriver.SkipPendingSurvey(comment); if (_quitAfterClose) { BeginQuitAfterFlush(); } } GUI.enabled = true; GUILayout.EndHorizontal(); if (_fairnessLikert <= 0 || _continuityLikert <= 0) { GUILayout.Space(6f); GUILayout.Label(text.MissingAnswers, _missingStyle, Array.Empty()); } else if (_isWaitingForQuitFlush) { GUILayout.Space(6f); GUILayout.Label(((int)Application.systemLanguage == 30) ? "Отправка телеметрии перед выходом..." : "Sending telemetry before quitting...", _missingStyle, Array.Empty()); } GUI.DragWindow(new Rect(0f, 0f, ((Rect)(ref _windowRect)).width, 24f)); GUILayout.EndVertical(); } private int DrawLikertOptions(string[] options, int selected) { for (int i = 0; i < options.Length; i++) { bool flag = selected == i + 1; if (GUILayout.Toggle(flag, options[i], _optionStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.MinHeight(34f) }) && !flag) { selected = i + 1; } } return selected; } private static SurveyText GetText() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 if ((int)Application.systemLanguage != 30) { return EnText; } return RuText; } private void SubmitSurvey() { string comment = (string.IsNullOrWhiteSpace(_comment) ? ("ui_trigger=" + _triggerReason) : (_comment.Trim() + " | ui_trigger=" + _triggerReason)); if (TelemetryRuntimeDriver.RecordPostSessionSurvey(_fairnessLikert, _continuityLikert, comment)) { if (_quitAfterClose) { CloseWidget(); BeginQuitAfterFlush(); } else { CloseWidget(); } } } private void BeginQuitAfterFlush() { if (!_isWaitingForQuitFlush) { _isWaitingForQuitFlush = true; ((MonoBehaviour)this).StartCoroutine(QuitAfterFlushRoutine()); } } [IteratorStateMachine(typeof(d__41))] private IEnumerator QuitAfterFlushRoutine() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__41(0); } private void CloseWidget() { _visible = false; RestoreCursorState(); RestoreBackgroundEventSystem(); } private void ResetAnswers() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) _fairnessLikert = 0; _continuityLikert = 0; _comment = ""; _scroll = Vector2.zero; } private void RememberCursorState() { //IL_0015: 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) if (!_savedCursorState) { _previousCursorVisible = Cursor.visible; _previousCursorLockMode = Cursor.lockState; _savedCursorState = true; } } private void RestoreCursorState() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) if (_savedCursorState) { Cursor.visible = _previousCursorVisible; Cursor.lockState = _previousCursorLockMode; _savedCursorState = false; } } private void DisableBackgroundEventSystem() { if (!_savedEventSystemState) { _previousEventSystem = EventSystem.current; if ((Object)(object)_previousEventSystem != (Object)null) { _previousEventSystemEnabled = ((Behaviour)_previousEventSystem).enabled; ((Behaviour)_previousEventSystem).enabled = false; } _savedEventSystemState = true; } } private void RestoreBackgroundEventSystem() { if (_savedEventSystemState) { if ((Object)(object)_previousEventSystem != (Object)null && ((Object)(object)EventSystem.current == (Object)null || (Object)(object)EventSystem.current == (Object)(object)_previousEventSystem)) { ((Behaviour)_previousEventSystem).enabled = _previousEventSystemEnabled; } _previousEventSystem = null; _savedEventSystemState = false; } } private void DrawDimmedOverlay() { //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown //IL_0039: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_overlayTexture == (Object)null) { _overlayTexture = new Texture2D(1, 1, (TextureFormat)4, false); _overlayTexture.SetPixel(0, 0, new Color(0f, 0f, 0f, 0.86f)); _overlayTexture.Apply(); } GUI.DrawTexture(new Rect(0f, 0f, (float)Screen.width, (float)Screen.height), (Texture)(object)_overlayTexture, (ScaleMode)0); } private void EnsureStyles() { //IL_0014: 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_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown //IL_0039: Expected O, but got Unknown //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Expected O, but got Unknown //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Expected O, but got Unknown //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Expected O, but got Unknown //IL_0102: Expected O, but got Unknown //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Expected O, but got Unknown //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Expected O, but got Unknown //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Expected O, but got Unknown //IL_01e8: Unknown result type (might be due to invalid IL or missing references) if (_windowStyle == null) { _windowStyle = new GUIStyle(GUI.skin.window) { fontSize = 24, padding = new RectOffset(26, 26, 30, 24) }; _windowStyle.normal.textColor = Color.white; _introStyle = new GUIStyle(GUI.skin.label) { fontSize = 20, wordWrap = true, richText = false }; _introStyle.normal.textColor = Color.white; _questionStyle = new GUIStyle(GUI.skin.label) { fontSize = 21, fontStyle = (FontStyle)1, wordWrap = true }; _questionStyle.normal.textColor = Color.white; _optionStyle = new GUIStyle(GUI.skin.toggle) { fontSize = 18, wordWrap = true, padding = new RectOffset(28, 8, 7, 7) }; _optionStyle.normal.textColor = Color.white; _optionStyle.onNormal.textColor = Color.white; _optionStyle.hover.textColor = Color.white; _optionStyle.onHover.textColor = Color.white; _buttonStyle = new GUIStyle(GUI.skin.button) { fontSize = 19, fontStyle = (FontStyle)1 }; _textAreaStyle = new GUIStyle(GUI.skin.textArea) { fontSize = 18, wordWrap = true }; _missingStyle = new GUIStyle(GUI.skin.label) { fontSize = 17, fontStyle = (FontStyle)1, wordWrap = true }; _missingStyle.normal.textColor = new Color(1f, 0.78f, 0.35f, 1f); } } } internal static class TelemetryBuildSecrets { internal const string PostHogHost = "https://us.i.posthog.com"; internal const string PostHogProjectToken = "phc_oHSq642PWWQmaTGWDzmrvyHUm5BuuSkQaKgbStJBD9Sw"; } } namespace GeneticsArtifact.SgdEngine { public sealed class SgdSensorsEstimator { public const float DefaultTauSeconds = 7.5f; public const float DefaultWindowSeconds = 60f; public const float DefaultDamageRateWindowSeconds = 10f; public const float DefaultLowHealthThreshold = 0.3f; private readonly float _tauSeconds; private readonly float _windowSeconds; private readonly float _lowHealthThreshold; private float _incomingDamageRateEma; private float _outgoingDamageRateEma; private float _hitRateOnPlayerEma; private float _combatUptimeEma; private float _lowHealthUptimeEma; private float _avgTtkSecondsEma; private float _incomingDamageWindowSum; private float _outgoingDamageWindowSum; private int _incomingHitCountWindow; private float _damageRateWindowElapsed; private readonly List _playerDeathTimes = new List(8); private readonly Dictionary _victimFirstHitTime = new Dictionary(128); private readonly List _ttkSamples = new List(64); public SgdSensorsEstimator(float tauSeconds = 7.5f, float windowSeconds = 60f, float lowHealthThreshold = 0.3f) { _tauSeconds = Mathf.Max(0.1f, tauSeconds); _windowSeconds = Mathf.Max(5f, windowSeconds); _lowHealthThreshold = Mathf.Clamp01(lowHealthThreshold); } public void Reset() { _incomingDamageRateEma = 0f; _outgoingDamageRateEma = 0f; _hitRateOnPlayerEma = 0f; _combatUptimeEma = 0f; _lowHealthUptimeEma = 0f; _avgTtkSecondsEma = 0f; _incomingDamageWindowSum = 0f; _outgoingDamageWindowSum = 0f; _incomingHitCountWindow = 0; _damageRateWindowElapsed = 0f; _playerDeathTimes.Clear(); _victimFirstHitTime.Clear(); _ttkSamples.Clear(); } public void TickPlayerBody(CharacterBody playerBody, float dt) { if (!((Object)(object)playerBody == (Object)null) && !(dt <= 0f) && !float.IsNaN(dt) && !float.IsInfinity(dt)) { float alpha = ComputeEmaAlpha(dt, _tauSeconds); UpdateDamageRateWindows(dt); float x = (playerBody.outOfCombat ? 0f : 1f); _combatUptimeEma = Ema(_combatUptimeEma, x, alpha); HealthComponent healthComponent = playerBody.healthComponent; float a = (((Object)(object)healthComponent != (Object)null) ? healthComponent.combinedHealth : 0f); float b = (((Object)(object)healthComponent != (Object)null) ? healthComponent.fullCombinedHealth : 0f); float num = SafeDiv(a, b); float x2 = ((num > 0f && num < _lowHealthThreshold) ? 1f : 0f); _lowHealthUptimeEma = Ema(_lowHealthUptimeEma, x2, alpha); PruneOldTtkSamples(); float x3 = ((_ttkSamples.Count > 0) ? Average(_ttkSamples) : 0f); _avgTtkSecondsEma = Ema(_avgTtkSecondsEma, x3, alpha); } } public void ObserveIncomingDamage(CharacterBody victimPlayerBody, float damage, float dt) { if (!((Object)(object)victimPlayerBody == (Object)null) && !(damage <= 0f) && !float.IsNaN(damage) && !float.IsInfinity(damage)) { _incomingDamageWindowSum += damage; _incomingHitCountWindow++; } } public void ObserveOutgoingDamage(CharacterBody attackerPlayerBody, CharacterBody victimMonsterBody, float damage, float dt) { if (!((Object)(object)attackerPlayerBody == (Object)null) && !((Object)(object)victimMonsterBody == (Object)null) && !(damage <= 0f) && !float.IsNaN(damage) && !float.IsInfinity(damage)) { _outgoingDamageWindowSum += damage; int num = (((Object)(object)((Component)victimMonsterBody).gameObject != (Object)null) ? ((Object)((Component)victimMonsterBody).gameObject).GetInstanceID() : 0); if (num != 0 && !_victimFirstHitTime.ContainsKey(num)) { _victimFirstHitTime[num] = Time.time; } } } private void UpdateDamageRateWindows(float dt) { if (!(dt <= 0f) && !float.IsNaN(dt) && !float.IsInfinity(dt)) { _damageRateWindowElapsed += dt; if (!(_damageRateWindowElapsed < 10f)) { float num = Mathf.Max(0.001f, _damageRateWindowElapsed); float alpha = ComputeEmaAlpha(num, _tauSeconds); float x = _incomingDamageWindowSum / num; float x2 = _outgoingDamageWindowSum / num; float x3 = (float)_incomingHitCountWindow / num; _incomingDamageRateEma = Ema(_incomingDamageRateEma, x, alpha); _outgoingDamageRateEma = Ema(_outgoingDamageRateEma, x2, alpha); _hitRateOnPlayerEma = Ema(_hitRateOnPlayerEma, x3, alpha); _incomingDamageWindowSum = 0f; _outgoingDamageWindowSum = 0f; _incomingHitCountWindow = 0; _damageRateWindowElapsed = 0f; } } } public void ObserveMonsterDeath(CharacterBody deadMonsterBody) { if (!((Object)(object)deadMonsterBody == (Object)null)) { int num = (((Object)(object)((Component)deadMonsterBody).gameObject != (Object)null) ? ((Object)((Component)deadMonsterBody).gameObject).GetInstanceID() : 0); if (num != 0 && _victimFirstHitTime.TryGetValue(num, out var value)) { _victimFirstHitTime.Remove(num); float ttkSeconds = Mathf.Max(0f, Time.time - value); AddTtkSample(ttkSeconds); } } } public void ObservePlayerDeath() { float time = Time.time; _playerDeathTimes.Add(time); PruneOldDeathTimes(time); } public SgdSensorsSample GetCurrentSample(in SgdVirtualPowerSample vp) { float time = Time.time; PruneOldDeathTimes(time); float num = _playerDeathTimes.Count; float num2 = Sanitize(_incomingDamageRateEma); float num3 = Sanitize(_outgoingDamageRateEma); float num4 = Sanitize(_hitRateOnPlayerEma); float combatUptime = Mathf.Clamp01(Sanitize(_combatUptimeEma)); float lowHealthUptime = Mathf.Clamp01(Sanitize(_lowHealthUptimeEma)); float num5 = Sanitize(_avgTtkSecondsEma); float num6 = Mathf.Max(1f, SafeExpm1(vp.AttackDamage)) * Mathf.Max(1f, SafeExpm1(vp.AttackSpeed)); float num7 = Mathf.Max(1f, SafeExpm1(vp.Hp)); float configOrDefault = GetConfigOrDefault(ConfigManager.sgdNormTargetTimeToDieSeconds, 10f); float configOrDefault2 = GetConfigOrDefault(ConfigManager.sgdNormTargetTtkSeconds, 8f); float configOrDefault3 = GetConfigOrDefault(ConfigManager.sgdNormHitRateScalePerSecond, 1.5f); float incomingDamageNorm = Normalize01(num2 * configOrDefault / num7); float outgoingDamageNorm = Normalize01(num3 / num6); float hitRateOnPlayerNorm = Normalize01(num4 / Mathf.Max(0.001f, configOrDefault3)); float deathsPerWindowNorm = Normalize01(num); float avgTtkSecondsNorm = Normalize01(num5 / Mathf.Max(0.001f, configOrDefault2)); return new SgdSensorsSample(num2, incomingDamageNorm, num3, outgoingDamageNorm, num4, hitRateOnPlayerNorm, combatUptime, lowHealthUptime, num, deathsPerWindowNorm, num5, avgTtkSecondsNorm); } private void AddTtkSample(float ttkSeconds) { if (!float.IsNaN(ttkSeconds) && !float.IsInfinity(ttkSeconds)) { ttkSeconds = Mathf.Clamp(ttkSeconds, 0f, 600f); _ttkSamples.Add(ttkSeconds); PruneOldTtkSamples(); } } private void PruneOldDeathTimes(float now) { float num = now - _windowSeconds; for (int num2 = _playerDeathTimes.Count - 1; num2 >= 0; num2--) { if (_playerDeathTimes[num2] < num) { _playerDeathTimes.RemoveAt(num2); } } } private void PruneOldTtkSamples() { int num = _ttkSamples.Count - 64; if (num > 0) { _ttkSamples.RemoveRange(0, num); } } private static float Ema(float prev, float x, float alpha) { if (float.IsNaN(x) || float.IsInfinity(x)) { return prev; } if (float.IsNaN(prev) || float.IsInfinity(prev)) { prev = 0f; } return Mathf.Lerp(prev, x, alpha); } private static float ComputeEmaAlpha(float dt, float tauSeconds) { tauSeconds = Mathf.Max(0.01f, tauSeconds); float num = 1f - Mathf.Exp((0f - dt) / tauSeconds); if (float.IsNaN(num) || float.IsInfinity(num)) { return 1f; } return Mathf.Clamp01(num); } private static float SafeDiv(float a, float b) { if (b <= 0f || float.IsNaN(b) || float.IsInfinity(b)) { return 0f; } float num = a / b; if (float.IsNaN(num) || float.IsInfinity(num)) { return 0f; } return num; } private static float Average(List values) { if (values == null || values.Count == 0) { return 0f; } double num = 0.0; for (int i = 0; i < values.Count; i++) { num += (double)values[i]; } return (float)(num / (double)values.Count); } private static float Sanitize(float x) { if (float.IsNaN(x) || float.IsInfinity(x)) { return 0f; } return Mathf.Max(0f, x); } private static float SafeExpm1(float log1pX) { if (float.IsNaN(log1pX) || float.IsInfinity(log1pX) || log1pX <= 0f) { return 0f; } log1pX = Mathf.Clamp(log1pX, 0f, 25f); float num = Mathf.Exp(log1pX) - 1f; if (float.IsNaN(num) || float.IsInfinity(num)) { return 0f; } return Mathf.Max(0f, num); } private static float Normalize01(float x) { if (float.IsNaN(x) || float.IsInfinity(x) || x <= 0f) { return 0f; } x = Mathf.Clamp(x, 0f, 100f); float num = 1f - Mathf.Exp(0f - x); if (float.IsNaN(num) || float.IsInfinity(num)) { return 0f; } return Mathf.Clamp01(num); } private static float GetConfigOrDefault(ConfigEntry entry, float fallback) { if (entry == null) { return fallback; } float value = entry.Value; if (float.IsNaN(value) || float.IsInfinity(value) || value <= 0f) { return fallback; } return value; } } public static class SgdSensorsHooks { private static SgdSensorsEstimator _estimator = new SgdSensorsEstimator(); private static CharacterBody _trackedPlayerBody; public static void RegisterHooks() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown HealthComponent.TakeDamage += new hook_TakeDamage(HealthComponent_TakeDamage); CharacterBody.OnDestroy += new hook_OnDestroy(CharacterBody_OnDestroy); } public static void Reset(CharacterBody newPlayerBody) { _trackedPlayerBody = newPlayerBody; _estimator.Reset(); SgdSensorsRuntimeState.Clear(); } public static void Tick(CharacterBody playerBody, float dt, in SgdVirtualPowerSample vp) { if ((Object)(object)playerBody == (Object)null) { Reset(null); return; } if ((Object)(object)_trackedPlayerBody != (Object)(object)playerBody) { Reset(playerBody); } _estimator.TickPlayerBody(playerBody, dt); SgdSensorsRuntimeState.Set(_estimator.GetCurrentSample(in vp), playerBody); } private static void HealthComponent_TakeDamage(orig_TakeDamage orig, HealthComponent self, DamageInfo damageInfo) { //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Invalid comparison between Unknown and I4 orig.Invoke(self, damageInfo); if ((Object)(object)self == (Object)null || damageInfo.damage <= 0f) { return; } CharacterBody body = self.body; if ((Object)(object)body == (Object)null) { return; } if ((Object)(object)_trackedPlayerBody != (Object)null && (Object)(object)body == (Object)(object)_trackedPlayerBody) { _estimator.ObserveIncomingDamage(_trackedPlayerBody, damageInfo.damage, Time.deltaTime); } else { if (!((Object)(object)_trackedPlayerBody != (Object)null)) { return; } GameObject attacker = damageInfo.attacker; if (attacker != null) { CharacterBody component = attacker.GetComponent(); if ((Object)(object)component != (Object)null && (Object)(object)component == (Object)(object)_trackedPlayerBody && (Object)(object)body.teamComponent != (Object)null && (int)body.teamComponent.teamIndex == 2) { _estimator.ObserveOutgoingDamage(_trackedPlayerBody, body, damageInfo.damage, Time.deltaTime); } } } } private static void CharacterBody_OnDestroy(orig_OnDestroy orig, CharacterBody self) { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Invalid comparison between Unknown and I4 try { if ((Object)(object)self != (Object)null) { if ((Object)(object)_trackedPlayerBody != (Object)null && (Object)(object)self == (Object)(object)_trackedPlayerBody) { _estimator.ObservePlayerDeath(); TelemetryRuntimeDriver.NotifyPlayerBodyDestroyed(self); } else if ((Object)(object)self.teamComponent != (Object)null && (int)self.teamComponent.teamIndex == 2) { _estimator.ObserveMonsterDeath(self); } } } finally { orig.Invoke(self); } } } public static class SgdSensorsRuntimeState { public static bool HasSample { get; private set; } public static SgdSensorsSample Sample { get; private set; } public static string PlayerBodyName { get; private set; } = ""; public static void Clear() { HasSample = false; Sample = default(SgdSensorsSample); PlayerBodyName = ""; } public static void Set(SgdSensorsSample sample, CharacterBody body) { HasSample = true; Sample = sample; PlayerBodyName = (((Object)(object)body != (Object)null) ? body.GetDisplayName() : ""); } } public readonly struct SgdSensorsSample { public readonly float IncomingDamageRate; public readonly float IncomingDamageNorm01; public readonly float OutgoingDamageRate; public readonly float OutgoingDamageNorm01; public readonly float HitRateOnPlayer; public readonly float HitRateOnPlayerNorm01; public readonly float CombatUptime; public readonly float LowHealthUptime; public readonly float DeathsPerWindow; public readonly float DeathsPerWindowNorm01; public readonly float AvgTtkSeconds; public readonly float AvgTtkSecondsNorm01; public SgdSensorsSample(float incomingDamageRate, float incomingDamageNorm01, float outgoingDamageRate, float outgoingDamageNorm01, float hitRateOnPlayer, float hitRateOnPlayerNorm01, float combatUptime, float lowHealthUptime, float deathsPerWindow, float deathsPerWindowNorm01, float avgTtkSeconds, float avgTtkSecondsNorm01) { IncomingDamageRate = incomingDamageRate; IncomingDamageNorm01 = incomingDamageNorm01; OutgoingDamageRate = outgoingDamageRate; OutgoingDamageNorm01 = outgoingDamageNorm01; HitRateOnPlayer = hitRateOnPlayer; HitRateOnPlayerNorm01 = hitRateOnPlayerNorm01; CombatUptime = combatUptime; LowHealthUptime = lowHealthUptime; DeathsPerWindow = deathsPerWindow; DeathsPerWindowNorm01 = deathsPerWindowNorm01; AvgTtkSeconds = avgTtkSeconds; AvgTtkSecondsNorm01 = avgTtkSecondsNorm01; } } internal static class SgdAxisLimitProvider { private const float FallbackHpFloor = 0.5f; private const float FallbackHpCap = 2f; private const float FallbackMoveSpeedFloor = 0.8f; private const float FallbackMoveSpeedCap = 1.25f; private const float FallbackAttackSpeedFloor = 0.6f; private const float FallbackAttackSpeedCap = 1.6667f; private const float FallbackAttackDamageFloor = 0.6f; private const float FallbackAttackDamageCap = 1.6667f; private const float AbsoluteMinFloor = 0.0001f; public static void GetMaxHealthLimits(out float floor, out float cap) { NormalizeLimits(ConfigManager.sgdHpFloor?.Value ?? 0.5f, ConfigManager.sgdHpCap?.Value ?? 2f, out floor, out cap); } public static void GetMoveSpeedLimits(out float floor, out float cap) { NormalizeLimits(ConfigManager.sgdMsFloor?.Value ?? 0.8f, ConfigManager.sgdMsCap?.Value ?? 1.25f, out floor, out cap); } public static void GetAttackSpeedLimits(out float floor, out float cap) { NormalizeLimits(ConfigManager.sgdAsFloor?.Value ?? 0.6f, ConfigManager.sgdAsCap?.Value ?? 1.6667f, out floor, out cap); } public static void GetAttackDamageLimits(out float floor, out float cap) { NormalizeLimits(ConfigManager.sgdDmgFloor?.Value ?? 0.6f, ConfigManager.sgdDmgCap?.Value ?? 1.6667f, out floor, out cap); } public static void GetLimits(GeneStat stat, out float floor, out float cap) { switch (stat) { case GeneStat.MaxHealth: GetMaxHealthLimits(out floor, out cap); break; case GeneStat.MoveSpeed: GetMoveSpeedLimits(out floor, out cap); break; case GeneStat.AttackSpeed: GetAttackSpeedLimits(out floor, out cap); break; case GeneStat.AttackDamage: GetAttackDamageLimits(out floor, out cap); break; default: NormalizeLimits(0.5f, 2f, out floor, out cap); break; } } public static float Clamp(GeneStat stat, float value) { GetLimits(stat, out var floor, out var cap); return Mathf.Clamp(value, floor, cap); } private static void NormalizeLimits(float rawFloor, float rawCap, out float floor, out float cap) { floor = rawFloor; cap = rawCap; if (cap < floor) { float num = cap; float num2 = floor; floor = num; cap = num2; } floor = Mathf.Max(0.0001f, floor); cap = Mathf.Max(floor, cap); } } internal readonly struct SgdBuildPowerAxisWeights { public readonly float Hp; public readonly float MoveSpeed; public readonly float AttackSpeed; public readonly float AttackDamage; public SgdBuildPowerAxisWeights(float hp, float moveSpeed, float attackSpeed, float attackDamage) { Hp = hp; MoveSpeed = moveSpeed; AttackSpeed = attackSpeed; AttackDamage = attackDamage; } public static SgdBuildPowerAxisWeights operator +(SgdBuildPowerAxisWeights a, SgdBuildPowerAxisWeights b) { return new SgdBuildPowerAxisWeights(a.Hp + b.Hp, a.MoveSpeed + b.MoveSpeed, a.AttackSpeed + b.AttackSpeed, a.AttackDamage + b.AttackDamage); } } internal static class SgdBuildPowerItemModel { [CompilerGenerated] private sealed class d__4 : IEnumerable, IEnumerable, IEnumerator, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; private int <>l__initialThreadId; private Inventory inventory; public Inventory <>3__inventory; private IEnumerator <>7__wrap1; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__4(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } <>7__wrap1 = null; <>1__state = -2; } private bool MoveNext() { //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; if (!(typeof(Inventory).GetField("itemAcquisitionOrder", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(inventory) is IEnumerable enumerable)) { return false; } <>7__wrap1 = enumerable.GetEnumerator(); <>1__state = -3; break; case 1: <>1__state = -3; break; } while (<>7__wrap1.MoveNext()) { if (<>7__wrap1.Current is ItemIndex val) { <>2__current = val; <>1__state = 1; return true; } } <>m__Finally1(); <>7__wrap1 = null; return false; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (<>7__wrap1 is IDisposable disposable) { disposable.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__4 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__4(0); } d__.inventory = <>3__inventory; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } public static SgdBuildPowerAxisWeights EstimateInventoryBonus(Inventory inventory) { //IL_002f: 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) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)inventory == (Object)null) { return default(SgdBuildPowerAxisWeights); } SgdBuildPowerAxisWeights result = default(SgdBuildPowerAxisWeights); foreach (ItemIndex item in EnumerateAcquiredItems(inventory)) { int itemCount = inventory.GetItemCount(item); if (itemCount > 0) { result += EstimateItem(ItemCatalog.GetItemDef(item), itemCount); } } return result; } private static SgdBuildPowerAxisWeights EstimateItem(ItemDef def, int count) { if ((Object)(object)def == (Object)null || count <= 0) { return default(SgdBuildPowerAxisWeights); } float num = Mathf.Log(1f + (float)count); float hp = 0f; float moveSpeed = 0f; float attackSpeed = 0f; float attackDamage = 0f; if (HasTag(def, "Healing")) { hp += 0.08f * num; } if (HasTag(def, "Utility")) { hp += 0.03f * num; } if (HasTag(def, "MobilityRelated") || HasTag(def, "SprintRelated")) { moveSpeed += 0.1f * num; } if (HasTag(def, "Damage")) { attackDamage += 0.08f * num; } if (HasTag(def, "OnKillEffect")) { attackDamage += 0.03f * num; } if (HasTag(def, "EquipmentRelated")) { attackSpeed += 0.02f * num; attackDamage += 0.02f * num; } ApplyKnownItemWeights(((Object)def).name, num, ref hp, ref moveSpeed, ref attackSpeed, ref attackDamage); return new SgdBuildPowerAxisWeights(hp, moveSpeed, attackSpeed, attackDamage); } private static void ApplyKnownItemWeights(string itemName, float stack, ref float hp, ref float moveSpeed, ref float attackSpeed, ref float attackDamage) { string text = itemName ?? ""; if (text == null) { return; } switch (text.Length) { default: return; case 10: switch (text[0]) { case 'F': break; case 'A': goto IL_022f; case 'C': goto IL_0240; case 'B': goto IL_0251; case 'S': goto IL_0262; default: return; } if (!(text == "FlatHealth")) { return; } goto IL_04a9; case 7: { char c = text[0]; if ((uint)c <= 67u) { if (c != 'B') { if (c != 'C' || !(text == "Crowbar")) { return; } goto IL_04fa; } if (!(text == "BoostHp")) { return; } goto IL_04a9; } if (c != 'I') { if (c != 'M') { if (c != 'S' || !(text == "Syringe")) { return; } goto IL_04eb; } if (!(text == "Missile")) { return; } break; } if (!(text == "IceRing")) { return; } break; } case 8: { char c = text[2]; if ((uint)c <= 102u) { if (c != 'a') { if (c != 'f' || !(text == "Infusion")) { return; } goto IL_04a9; } if (!(text == "BearVoid")) { return; } goto IL_04b6; } switch (c) { default: return; case 'r': if (!(text == "FireRing")) { return; } break; case 'h': if (!(text == "Behemoth")) { return; } break; } break; } case 14: { char c = text[0]; if (c != 'B') { if (c != 'C') { if (c != 'P' || !(text == "PersonalShield")) { return; } goto IL_04a9; } if (!(text == "ChainLightning")) { return; } break; } if (!(text == "BleedOnHitVoid")) { return; } break; } case 4: { char c = text[0]; if (c != 'B') { if (c != 'H' || !(text == "Hoof")) { return; } goto IL_04c3; } if (!(text == "Bear")) { return; } goto IL_04b6; } case 16: { char c = text[0]; if (c != 'B') { if (c != 'O') { if (c != 'S' || !(text == "SpeedBoostPickup")) { return; } goto IL_04c3; } if (!(text == "OutOfCombatArmor")) { return; } goto IL_04b6; } if (!(text == "BoostAttackSpeed")) { return; } goto IL_04eb; } case 11: switch (text[7]) { case 'r': break; case 'o': goto IL_03b6; case 's': goto IL_03c7; case 'm': goto IL_03d8; case 'V': goto IL_03e9; default: return; } if (!(text == "SprintArmor")) { return; } goto IL_04b6; case 15: { char c = text[0]; if (c != 'B') { if (c != 'M' || !(text == "MoveSpeedOnKill")) { return; } goto IL_04c3; } if (!(text == "BossDamageBonus")) { return; } goto IL_04fa; } case 23: switch (text[0]) { default: return; case 'A': if (text == "AttackSpeedAndMoveSpeed") { moveSpeed += 0.08f * stack; attackSpeed += 0.08f * stack; } return; case 'E': break; } if (!(text == "EnergizedOnEquipmentUse")) { return; } goto IL_04eb; case 17: { char c = text[0]; if (c != 'A') { if (c != 'N' || !(text == "NearbyDamageBonus")) { return; } goto IL_04fa; } if (!(text == "AttackSpeedOnCrit")) { return; } goto IL_04eb; } case 18: { char c = text[0]; if (c != 'C') { if (c != 'F' || !(text == "FragileDamageBonus")) { return; } goto IL_04fa; } if (!(text == "ChainLightningVoid")) { return; } break; } case 5: if (!(text == "Knurl")) { return; } goto IL_04a9; case 13: if (!(text == "SpeedOnPickup")) { return; } goto IL_04c3; case 31: if (!(text == "AttackSpeedPerNearbyAllyOrEnemy")) { return; } goto IL_04eb; case 6: if (!(text == "Dagger")) { return; } break; case 9: case 12: case 19: case 20: case 21: case 22: case 24: case 25: case 26: case 27: case 28: case 29: case 30: return; IL_04fa: attackDamage += 0.12f * stack; return; IL_04b6: hp += 0.08f * stack; return; IL_04eb: attackSpeed += 0.15f * stack; return; IL_04c3: moveSpeed += 0.14f * stack; return; IL_0240: if (!(text == "CritDamage")) { return; } goto IL_04fa; IL_04a9: hp += 0.1f * stack; return; IL_03e9: if (!(text == "MissileVoid")) { return; } break; IL_03d8: if (!(text == "BoostDamage")) { return; } goto IL_04fa; IL_03c7: if (!(text == "CritGlasses")) { return; } goto IL_04fa; IL_03b6: if (!(text == "SprintBonus")) { return; } goto IL_04c3; IL_0262: if (!(text == "StickyBomb")) { return; } break; IL_0251: if (!(text == "BleedOnHit")) { return; } break; IL_022f: if (!(text == "ArmorPlate")) { return; } goto IL_04b6; } attackDamage += 0.1f * stack; } private static bool HasTag(ItemDef def, string tagName) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) if (def?.tags == null) { return false; } ItemTag[] tags = def.tags; for (int i = 0; i < tags.Length; i++) { ItemTag val = tags[i]; if (((object)(ItemTag)(ref val)).ToString() == tagName) { return true; } } return false; } [IteratorStateMachine(typeof(d__4))] private static IEnumerable EnumerateAcquiredItems(Inventory inventory) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__4(-2) { <>3__inventory = inventory }; } } public sealed class SgdRuntimeDriver : MonoBehaviour { private static SgdRuntimeDriver _instance; private readonly SgdVirtualPowerEstimator _vpEstimator = new SgdVirtualPowerEstimator(); private CharacterBody _trackedBody; private bool _wasSgdActiveLastFrame; public static void RegisterHooks() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown Run.Start += new hook_Start(Run_Start); Run.BeginGameOver += new hook_BeginGameOver(Run_BeginGameOver); SgdSensorsHooks.RegisterHooks(); } private static void Run_Start(orig_Start orig, Run self) { orig.Invoke(self); SgdDecisionRuntimeState.Reset(); SgdActuatorsRuntimeState.Reset(); SgdActuatorsApplier.ApplyToAllLivingMonsters(); if ((Object)(object)self != (Object)null && (Object)(object)((Component)self).gameObject != (Object)null && (Object)(object)((Component)self).gameObject.GetComponent() == (Object)null) { ((Component)self).gameObject.AddComponent(); } if (ConfigManager.diagnosticsEnableTelemetryHooks != null && ConfigManager.diagnosticsEnableTelemetryHooks.Value && ConfigManager.telemetryEnabled.Value && (Object)(object)self != (Object)null && (Object)(object)((Component)self).gameObject != (Object)null && (Object)(object)((Component)self).gameObject.GetComponent() == (Object)null) { ((Component)self).gameObject.AddComponent(); } } private static void Run_BeginGameOver(orig_BeginGameOver orig, Run self, GameEndingDef gameEndingDef) { if (ConfigManager.diagnosticsEnableTelemetryHooks != null && ConfigManager.diagnosticsEnableTelemetryHooks.Value && ConfigManager.telemetryEnabled.Value) { TelemetryRuntimeDriver.NotifyRunBeginGameOver(gameEndingDef); } orig.Invoke(self, gameEndingDef); } private void Awake() { if ((Object)(object)_instance != (Object)null && (Object)(object)_instance != (Object)(object)this) { Object.Destroy((Object)(object)this); return; } _instance = this; SgdRuntimeState.Clear(); SgdDecisionRuntimeState.Reset(); } private void OnDestroy() { if ((Object)(object)_instance == (Object)(object)this) { _instance = null; } } private void Update() { bool flag = DdaAlgorithmState.ActiveAlgorithm == DdaAlgorithmType.Sgd; if (flag && !_wasSgdActiveLastFrame) { SgdDecisionRuntimeState.Reset(); } _wasSgdActiveLastFrame = flag; CharacterBody val = FindAnyPlayerBody(); if ((Object)(object)val == (Object)null) { SgdRuntimeState.Clear(); SgdSensorsRuntimeState.Clear(); _trackedBody = null; _vpEstimator.Reset(); return; } if ((Object)(object)_trackedBody != (Object)(object)val) { _trackedBody = val; _vpEstimator.Reset(); } SgdVirtualPowerSample vp = _vpEstimator.ComputeSmoothed(val, Time.deltaTime); SgdRuntimeState.SetVirtualPower(vp, val); SgdSensorsHooks.Tick(val, Time.deltaTime, in vp); if (flag && NetworkServer.active) { SgdDecisionDriver.Tick(val, Time.deltaTime); } } private static CharacterBody FindAnyPlayerBody() { //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Invalid comparison between Unknown and I4 foreach (CharacterBody readOnlyInstances in CharacterBody.readOnlyInstancesList) { if ((Object)(object)readOnlyInstances != (Object)null && readOnlyInstances.isPlayerControlled) { return readOnlyInstances; } } foreach (CharacterBody readOnlyInstances2 in CharacterBody.readOnlyInstancesList) { if ((Object)(object)readOnlyInstances2 != (Object)null && (Object)(object)readOnlyInstances2.teamComponent != (Object)null && (int)readOnlyInstances2.teamComponent.teamIndex == 1) { return readOnlyInstances2; } } return null; } } public static class SgdRuntimeState { public static bool HasVirtualPower { get; private set; } public static SgdVirtualPowerSample VirtualPower { get; private set; } public static string VirtualPowerBodyName { get; private set; } = ""; public static void Clear() { HasVirtualPower = false; VirtualPower = default(SgdVirtualPowerSample); VirtualPowerBodyName = ""; } public static void SetVirtualPower(SgdVirtualPowerSample sample, CharacterBody body) { HasVirtualPower = true; VirtualPower = sample; VirtualPowerBodyName = (((Object)(object)body != (Object)null) ? body.GetDisplayName() : ""); } } public sealed class SgdVirtualPowerEstimator { public const float WeightHp = 0.25f; public const float WeightMoveSpeed = 0.25f; public const float WeightAttackSpeed = 0.25f; public const float WeightAttackDamage = 0.25f; public const float WeightOffense = 0.25f; public const float WeightDefense = 0.25f; public const float WeightMobility = 0.25f; public const float RegenWeight = 25f; public const float DefaultTauSeconds = 7.5f; private float _tauSeconds; private bool _hasEma; private SgdVirtualPowerSample _ema; public SgdVirtualPowerEstimator(float tauSeconds = 7.5f) { _tauSeconds = Mathf.Max(0.1f, tauSeconds); } public void Reset() { _hasEma = false; _ema = default(SgdVirtualPowerSample); } public static SgdVirtualPowerSample ComputeRaw(CharacterBody body) { if ((Object)(object)body == (Object)null) { return default(SgdVirtualPowerSample); } float num = Mathf.Max(0f, body.maxHealth); float num2 = Mathf.Max(0f, body.maxShield); float num3 = num + num2; float num4 = Mathf.Clamp((100f + body.armor) / 100f, 0.05f, 10f); float num5 = num3 * num4; float num6 = Mathf.Max(0f, body.regen); float hp = num5 + 25f * num6; float moveSpeed = Mathf.Max(0f, body.moveSpeed); float attackSpeed = Mathf.Max(0f, body.attackSpeed); float num7 = Mathf.Max(0f, body.damage); float num8 = Mathf.Clamp(body.crit, 0f, 100f) / 100f; float attackDamage = num7 * (1f + num8); return new SgdVirtualPowerSample(hp, moveSpeed, attackSpeed, attackDamage); } public SgdVirtualPowerSample ComputeSmoothed(CharacterBody body, float dt) { SgdVirtualPowerSample sgdVirtualPowerSample = ComputeRaw(body); SgdBuildPowerAxisWeights sgdBuildPowerAxisWeights = SgdBuildPowerItemModel.EstimateInventoryBonus((body != null) ? body.inventory : null); float hp = SafeLog1p(sgdVirtualPowerSample.Hp) + sgdBuildPowerAxisWeights.Hp; float moveSpeed = SafeLog1p(sgdVirtualPowerSample.MoveSpeed) + sgdBuildPowerAxisWeights.MoveSpeed; float attackSpeed = SafeLog1p(sgdVirtualPowerSample.AttackSpeed) + sgdBuildPowerAxisWeights.AttackSpeed; float attackDamage = SafeLog1p(sgdVirtualPowerSample.AttackDamage) + sgdBuildPowerAxisWeights.AttackDamage; SgdVirtualPowerSample ema = new SgdVirtualPowerSample(hp, moveSpeed, attackSpeed, attackDamage); float num = ComputeEmaAlpha(dt, _tauSeconds); if (!_hasEma) { _ema = ema; _hasEma = true; return _ema; } _ema = new SgdVirtualPowerSample(Mathf.Lerp(_ema.Hp, ema.Hp, num), Mathf.Lerp(_ema.MoveSpeed, ema.MoveSpeed, num), Mathf.Lerp(_ema.AttackSpeed, ema.AttackSpeed, num), Mathf.Lerp(_ema.AttackDamage, ema.AttackDamage, num)); return _ema; } private static float SafeLog1p(float x) { if (float.IsNaN(x) || float.IsInfinity(x) || x <= 0f) { return 0f; } return Mathf.Log(x + 1f); } private static float ComputeEmaAlpha(float dt, float tauSeconds) { if (dt <= 0f || float.IsNaN(dt) || float.IsInfinity(dt)) { return 1f; } tauSeconds = Mathf.Max(0.01f, tauSeconds); float num = 1f - Mathf.Exp((0f - dt) / tauSeconds); if (float.IsNaN(num) || float.IsInfinity(num)) { return 1f; } return Mathf.Clamp01(num); } } public readonly struct SgdVirtualPowerSample { public readonly float Hp; public readonly float MoveSpeed; public readonly float AttackSpeed; public readonly float AttackDamage; public readonly float Total; public float Offense => AttackDamage; public float Defense => Hp; public float Mobility => MoveSpeed; public SgdVirtualPowerSample(float hp, float moveSpeed, float attackSpeed, float attackDamage) { Hp = hp; MoveSpeed = moveSpeed; AttackSpeed = attackSpeed; AttackDamage = attackDamage; Total = (hp + moveSpeed + attackSpeed + attackDamage) * 0.25f; } } } namespace GeneticsArtifact.SgdEngine.Decision { public static class SgdDecisionDriver { private struct VirtualPowerCompensation { public float HpContribution; public float MsContribution; public float AsContribution; public float DmgContribution; } internal const float DefaultMomentum = 0.65f; internal const float DefaultGradientClip = 0.5f; internal const float DefaultVelocityClip = 1f; internal const float DefaultErrorDeadZone = 0.03f; internal const float VirtualPowerLossWeight = 0.12f; internal const float VirtualPowerScale = 0.2f; internal const float HpVirtualChallengeWeight = 0.35f; internal const float MsVirtualChallengeWeight = 0.15f; internal const float AsVirtualChallengeWeight = 0.2f; internal const float DmgVirtualChallengeWeight = 0.3f; private const float ExternalSyncEpsilon = 0.001f; internal const float HpLearningRate = 0.22f; internal const float HpMaxDeltaTheta = 0.06f; internal const float MsLearningRate = 0.2f; internal const float MsMaxDeltaTheta = 0.05f; internal const float AsLearningRate = 0.2f; internal const float AsMaxDeltaTheta = 0.045f; internal const float DmgLearningRate = 0.18f; internal const float DmgMaxDeltaTheta = 0.05f; private const float AxisApplyEpsilon = 0.0005f; public static void Tick(CharacterBody playerBody, float dt) { if (!NetworkServer.active || DdaAlgorithmState.ActiveAlgorithm != DdaAlgorithmType.Sgd || (Object)(object)playerBody == (Object)null || dt <= 0f || float.IsNaN(dt) || float.IsInfinity(dt)) { return; } EnsureAxisStatesSynced(); if ((!SgdDecisionRuntimeState.IsMaxHealthAdaptationEnabled && !SgdDecisionRuntimeState.IsMoveSpeedAdaptationEnabled && !SgdDecisionRuntimeState.IsAttackSpeedAdaptationEnabled && !SgdDecisionRuntimeState.IsAttackDamageAdaptationEnabled) || playerBody.outOfCombat || !SgdSensorsRuntimeState.HasSample) { return; } SgdDecisionRuntimeState.AddCombatSeconds(dt); int num = SgdDecisionRuntimeState.ConsumeDueSteps(); if (num > 0) { for (int i = 0; i < num; i++) { SgdSensorsSample sensors = SgdSensorsRuntimeState.Sample; StepAllAxes(in sensors); } } } private static void EnsureAxisStatesSynced() { EnsureMaxHealthStateSynced(); EnsureMoveSpeedStateSynced(); EnsureAttackSpeedStateSynced(); EnsureAttackDamageStateSynced(); } private static void EnsureMaxHealthStateSynced() { SgdAxisLimitProvider.GetMaxHealthLimits(out var floor, out var cap); float num = Mathf.Log(floor); float num2 = Mathf.Log(cap); float num3 = Mathf.Max(0.0001f, SgdActuatorsRuntimeState.MaxHealthMultiplier); if (!SgdDecisionRuntimeState.HasMaxHealthState) { float num4 = Mathf.Clamp(Mathf.Log(num3), num, num2); float multiplier = Mathf.Exp(num4); SgdDecisionRuntimeState.SyncMaxHealthTheta(num4, 0f, multiplier); } else if (Mathf.Abs(Mathf.Exp(SgdDecisionRuntimeState.MaxHealthTheta) - num3) > 0.001f) { float num5 = Mathf.Clamp(Mathf.Log(num3), num, num2); float multiplier2 = Mathf.Exp(num5); SgdDecisionRuntimeState.SyncMaxHealthTheta(num5, 0f, multiplier2); } } private static void EnsureMoveSpeedStateSynced() { SgdAxisLimitProvider.GetMoveSpeedLimits(out var floor, out var cap); float num = Mathf.Log(floor); float num2 = Mathf.Log(cap); float num3 = Mathf.Max(0.0001f, SgdActuatorsRuntimeState.MoveSpeedMultiplier); if (!SgdDecisionRuntimeState.HasMoveSpeedState) { float num4 = Mathf.Clamp(Mathf.Log(num3), num, num2); float multiplier = Mathf.Exp(num4); SgdDecisionRuntimeState.SyncMoveSpeedTheta(num4, 0f, multiplier); } else if (Mathf.Abs(Mathf.Exp(SgdDecisionRuntimeState.MoveSpeedTheta) - num3) > 0.001f) { float num5 = Mathf.Clamp(Mathf.Log(num3), num, num2); float multiplier2 = Mathf.Exp(num5); SgdDecisionRuntimeState.SyncMoveSpeedTheta(num5, 0f, multiplier2); } } private static void EnsureAttackSpeedStateSynced() { SgdAxisLimitProvider.GetAttackSpeedLimits(out var floor, out var cap); float num = Mathf.Log(floor); float num2 = Mathf.Log(cap); float num3 = Mathf.Max(0.0001f, SgdActuatorsRuntimeState.AttackSpeedMultiplier); if (!SgdDecisionRuntimeState.HasAttackSpeedState) { float num4 = Mathf.Clamp(Mathf.Log(num3), num, num2); float multiplier = Mathf.Exp(num4); SgdDecisionRuntimeState.SyncAttackSpeedTheta(num4, 0f, multiplier); } else if (Mathf.Abs(Mathf.Exp(SgdDecisionRuntimeState.AttackSpeedTheta) - num3) > 0.001f) { float num5 = Mathf.Clamp(Mathf.Log(num3), num, num2); float multiplier2 = Mathf.Exp(num5); SgdDecisionRuntimeState.SyncAttackSpeedTheta(num5, 0f, multiplier2); } } private static void EnsureAttackDamageStateSynced() { SgdAxisLimitProvider.GetAttackDamageLimits(out var floor, out var cap); float num = Mathf.Log(floor); float num2 = Mathf.Log(cap); float num3 = Mathf.Max(0.0001f, SgdActuatorsRuntimeState.AttackDamageMultiplier); if (!SgdDecisionRuntimeState.HasAttackDamageState) { float num4 = Mathf.Clamp(Mathf.Log(num3), num, num2); float multiplier = Mathf.Exp(num4); SgdDecisionRuntimeState.SyncAttackDamageTheta(num4, 0f, multiplier); } else if (Mathf.Abs(Mathf.Exp(SgdDecisionRuntimeState.AttackDamageTheta) - num3) > 0.001f) { float num5 = Mathf.Clamp(Mathf.Log(num3), num, num2); float multiplier2 = Mathf.Exp(num5); SgdDecisionRuntimeState.SyncAttackDamageTheta(num5, 0f, multiplier2); } } private static void StepAllAxes(in SgdSensorsSample sensors) { bool flag = false; VirtualPowerCompensation virtualPowerCompensation = PrepareAxisVirtualPowerCompensation(); if (SgdDecisionRuntimeState.IsMaxHealthAdaptationEnabled) { flag |= StepMaxHealth(in sensors, virtualPowerCompensation.HpContribution); } if (SgdDecisionRuntimeState.IsMoveSpeedAdaptationEnabled) { flag |= StepMoveSpeed(in sensors, virtualPowerCompensation.MsContribution); } if (SgdDecisionRuntimeState.IsAttackSpeedAdaptationEnabled) { flag |= StepAttackSpeed(in sensors, virtualPowerCompensation.AsContribution); } if (SgdDecisionRuntimeState.IsAttackDamageAdaptationEnabled) { flag |= StepAttackDamage(in sensors, virtualPowerCompensation.DmgContribution); } SgdDecisionRuntimeState.RecordGlobalStep(flag ? SgdActuatorsApplier.ApplyToAllLivingMonsters() : 0); } private static VirtualPowerCompensation PrepareAxisVirtualPowerCompensation() { SgdVirtualPowerSample virtualChallenge = ComputeCurrentVirtualChallengeAxes(); SgdVirtualPowerSample virtualPowerDelta = default(SgdVirtualPowerSample); SgdVirtualPowerSample virtualError = default(SgdVirtualPowerSample); VirtualPowerCompensation result = default(VirtualPowerCompensation); if (SgdRuntimeState.HasVirtualPower) { SgdVirtualPowerSample sample = SgdRuntimeState.VirtualPower; if (IsFinite(in sample)) { if (!SgdDecisionRuntimeState.HasBaselineVirtualPower) { SgdDecisionRuntimeState.CaptureBaselineVirtualPower(in sample); } if (SgdDecisionRuntimeState.HasBaselineVirtualPower) { SgdVirtualPowerSample b = SgdDecisionRuntimeState.BaselineVirtualPower; virtualPowerDelta = Subtract(in sample, in b); virtualError = new SgdVirtualPowerSample(virtualChallenge.Hp - virtualPowerDelta.Hp * 0.2f, virtualChallenge.MoveSpeed - virtualPowerDelta.MoveSpeed * 0.2f, virtualChallenge.AttackSpeed - virtualPowerDelta.AttackSpeed * 0.2f, virtualChallenge.AttackDamage - virtualPowerDelta.AttackDamage * 0.2f); result.HpContribution = 0.12f * virtualError.Hp; result.MsContribution = 0.12f * virtualError.MoveSpeed; result.AsContribution = 0.12f * virtualError.AttackSpeed; result.DmgContribution = 0.12f * virtualError.AttackDamage; } } } SgdDecisionRuntimeState.RecordVirtualPowerCompensation(in virtualPowerDelta, in virtualChallenge, in virtualError, result.HpContribution, result.MsContribution, result.AsContribution, result.DmgContribution); return result; } internal static SgdVirtualPowerSample ComputeCurrentVirtualChallengeAxes() { return new SgdVirtualPowerSample(SafeTheta(SgdDecisionRuntimeState.MaxHealthTheta), SafeTheta(SgdDecisionRuntimeState.MoveSpeedTheta), SafeTheta(SgdDecisionRuntimeState.AttackSpeedTheta), SafeTheta(SgdDecisionRuntimeState.AttackDamageTheta)); } private static float ComputeCurrentVirtualChallenge() { SgdVirtualPowerSample sgdVirtualPowerSample = ComputeCurrentVirtualChallengeAxes(); return 0.35f * sgdVirtualPowerSample.Hp + 0.15f * sgdVirtualPowerSample.MoveSpeed + 0.2f * sgdVirtualPowerSample.AttackSpeed + 0.3f * sgdVirtualPowerSample.AttackDamage; } private static float SafeTheta(float theta) { if (!float.IsNaN(theta) && !float.IsInfinity(theta)) { return theta; } return 0f; } private static bool IsFinite(in SgdVirtualPowerSample sample) { if (IsFinite(sample.Hp) && IsFinite(sample.MoveSpeed) && IsFinite(sample.AttackSpeed)) { return IsFinite(sample.AttackDamage); } return false; } private static bool IsFinite(float value) { if (!float.IsNaN(value)) { return !float.IsInfinity(value); } return false; } private static SgdVirtualPowerSample Subtract(in SgdVirtualPowerSample a, in SgdVirtualPowerSample b) { return new SgdVirtualPowerSample(a.Hp - b.Hp, a.MoveSpeed - b.MoveSpeed, a.AttackSpeed - b.AttackSpeed, a.AttackDamage - b.AttackDamage); } private static float EstimateAttackSpeedSkill01(in SgdSensorsSample s) { float num = 1f - Mathf.Clamp01(s.HitRateOnPlayerNorm01); float num2 = 1f - Mathf.Clamp01(s.IncomingDamageNorm01); float num3 = 1f - Mathf.Clamp01(s.LowHealthUptime); float num4 = 1f - Mathf.Clamp01(s.DeathsPerWindowNorm01); float num5 = 0.4f * num + 0.35f * num2 + 0.2f * num3 + 0.05f * num4; if (float.IsNaN(num5) || float.IsInfinity(num5)) { return 0f; } return Mathf.Clamp01(num5); } private static float EstimateMaxHealthSkill01(in SgdSensorsSample s) { float num = Mathf.Clamp01(s.OutgoingDamageNorm01); float num2 = ((s.AvgTtkSeconds > 0.01f) ? (1f - Mathf.Clamp01(s.AvgTtkSecondsNorm01)) : 0.5f); float num3 = 1f - Mathf.Clamp01(s.LowHealthUptime); float num4 = 0.45f * num + 0.45f * num2 + 0.1f * num3; if (float.IsNaN(num4) || float.IsInfinity(num4)) { return 0f; } return Mathf.Clamp01(num4); } private static float EstimateMoveSpeedSkill01(in SgdSensorsSample s) { float num = 1f - Mathf.Clamp01(s.HitRateOnPlayerNorm01); float num2 = 1f - Mathf.Clamp01(s.IncomingDamageNorm01); float num3 = Mathf.Clamp01(s.OutgoingDamageNorm01); float num4 = 1f - Mathf.Clamp01(s.LowHealthUptime); float num5 = 0.45f * num + 0.25f * num2 + 0.2f * num3 + 0.1f * num4; if (float.IsNaN(num5) || float.IsInfinity(num5)) { return 0f; } return Mathf.Clamp01(num5); } private static float EstimateAttackDamageSkill01(in SgdSensorsSample s) { float num = 1f - Mathf.Clamp01(s.IncomingDamageNorm01); float num2 = 1f - Mathf.Clamp01(s.LowHealthUptime); float num3 = 1f - Mathf.Clamp01(s.DeathsPerWindowNorm01); float num4 = 1f - Mathf.Clamp01(s.HitRateOnPlayerNorm01); float num5 = 0.45f * num + 0.3f * num2 + 0.2f * num3 + 0.05f * num4; if (float.IsNaN(num5) || float.IsInfinity(num5)) { return 0f; } return Mathf.Clamp01(num5); } private static bool StepMaxHealth(in SgdSensorsSample sensors, float virtualErrorContribution) { SgdAxisLimitProvider.GetMaxHealthLimits(out var floor, out var cap); float num = Mathf.Log(floor); float num2 = Mathf.Log(cap); float num3 = Mathf.Max(0.0001f, num2 - num); float num4 = Mathf.Clamp(SgdDecisionRuntimeState.MaxHealthTheta, num, num2); float maxHealthVelocity = SgdDecisionRuntimeState.MaxHealthVelocity; float num5 = Mathf.Clamp01((num4 - num) / num3); float num6 = EstimateMaxHealthSkill01(in sensors); float num7 = num5 - num6; if (Mathf.Abs(num7) < 0.03f) { num7 = 0f; } float num8 = num7 + virtualErrorContribution; float num9 = 2f * num8 * (1f / num3); num9 = Mathf.Clamp(num9, -0.5f, 0.5f); maxHealthVelocity = 0.65f * maxHealthVelocity + num9; maxHealthVelocity = Mathf.Clamp(maxHealthVelocity, -1f, 1f); float num10 = 0.22f * maxHealthVelocity; num10 = Mathf.Clamp(num10, -0.06f, 0.06f); float num11 = Mathf.Clamp(num4 - num10, num, num2); float maxHealthMultiplier = Mathf.Exp(num11); float maxHealthMultiplier2 = SgdActuatorsRuntimeState.MaxHealthMultiplier; SgdActuatorsRuntimeState.SetMaxHealthMultiplier(maxHealthMultiplier); float maxHealthMultiplier3 = SgdActuatorsRuntimeState.MaxHealthMultiplier; SgdDecisionRuntimeState.SyncMaxHealthTheta(num11, maxHealthVelocity, maxHealthMultiplier3); SgdDecisionRuntimeState.RecordMaxHealthStep(num6, num5, num8, num9, 0.22f, num10, maxHealthMultiplier3); return Mathf.Abs(maxHealthMultiplier3 - maxHealthMultiplier2) > 0.0005f; } private static bool StepMoveSpeed(in SgdSensorsSample sensors, float virtualErrorContribution) { SgdAxisLimitProvider.GetMoveSpeedLimits(out var floor, out var cap); float num = Mathf.Log(floor); float num2 = Mathf.Log(cap); float num3 = Mathf.Max(0.0001f, num2 - num); float num4 = Mathf.Clamp(SgdDecisionRuntimeState.MoveSpeedTheta, num, num2); float moveSpeedVelocity = SgdDecisionRuntimeState.MoveSpeedVelocity; float num5 = Mathf.Clamp01((num4 - num) / num3); float num6 = EstimateMoveSpeedSkill01(in sensors); float num7 = num5 - num6; if (Mathf.Abs(num7) < 0.03f) { num7 = 0f; } float num8 = num7 + virtualErrorContribution; float num9 = 2f * num8 * (1f / num3); num9 = Mathf.Clamp(num9, -0.5f, 0.5f); moveSpeedVelocity = 0.65f * moveSpeedVelocity + num9; moveSpeedVelocity = Mathf.Clamp(moveSpeedVelocity, -1f, 1f); float num10 = 0.2f * moveSpeedVelocity; num10 = Mathf.Clamp(num10, -0.05f, 0.05f); float num11 = Mathf.Clamp(num4 - num10, num, num2); float moveSpeedMultiplier = Mathf.Exp(num11); float moveSpeedMultiplier2 = SgdActuatorsRuntimeState.MoveSpeedMultiplier; SgdActuatorsRuntimeState.SetMoveSpeedMultiplier(moveSpeedMultiplier); float moveSpeedMultiplier3 = SgdActuatorsRuntimeState.MoveSpeedMultiplier; SgdDecisionRuntimeState.SyncMoveSpeedTheta(num11, moveSpeedVelocity, moveSpeedMultiplier3); SgdDecisionRuntimeState.RecordMoveSpeedStep(num6, num5, num8, num9, 0.2f, num10, moveSpeedMultiplier3); return Mathf.Abs(moveSpeedMultiplier3 - moveSpeedMultiplier2) > 0.0005f; } private static bool StepAttackSpeed(in SgdSensorsSample sensors, float virtualErrorContribution) { SgdAxisLimitProvider.GetAttackSpeedLimits(out var floor, out var cap); float num = Mathf.Log(floor); float num2 = Mathf.Log(cap); float num3 = Mathf.Max(0.0001f, num2 - num); float num4 = Mathf.Clamp(SgdDecisionRuntimeState.AttackSpeedTheta, num, num2); float attackSpeedVelocity = SgdDecisionRuntimeState.AttackSpeedVelocity; float num5 = Mathf.Clamp01((num4 - num) / num3); float num6 = EstimateAttackSpeedSkill01(in sensors); float num7 = num5 - num6; if (Mathf.Abs(num7) < 0.03f) { num7 = 0f; } float num8 = num7 + virtualErrorContribution; float num9 = 2f * num8 * (1f / num3); num9 = Mathf.Clamp(num9, -0.5f, 0.5f); attackSpeedVelocity = 0.65f * attackSpeedVelocity + num9; attackSpeedVelocity = Mathf.Clamp(attackSpeedVelocity, -1f, 1f); float num10 = 0.2f * attackSpeedVelocity; num10 = Mathf.Clamp(num10, -0.045f, 0.045f); float num11 = Mathf.Clamp(num4 - num10, num, num2); float attackSpeedMultiplier = Mathf.Exp(num11); float attackSpeedMultiplier2 = SgdActuatorsRuntimeState.AttackSpeedMultiplier; SgdActuatorsRuntimeState.SetAttackSpeedMultiplier(attackSpeedMultiplier); float attackSpeedMultiplier3 = SgdActuatorsRuntimeState.AttackSpeedMultiplier; SgdDecisionRuntimeState.SyncAttackSpeedTheta(num11, attackSpeedVelocity, attackSpeedMultiplier3); SgdDecisionRuntimeState.RecordAttackSpeedStep(num6, num5, num8, num9, 0.2f, num10, attackSpeedMultiplier3); return Mathf.Abs(attackSpeedMultiplier3 - attackSpeedMultiplier2) > 0.0005f; } private static bool StepAttackDamage(in SgdSensorsSample sensors, float virtualErrorContribution) { SgdAxisLimitProvider.GetAttackDamageLimits(out var floor, out var cap); float num = Mathf.Log(floor); float num2 = Mathf.Log(cap); float num3 = Mathf.Max(0.0001f, num2 - num); float num4 = Mathf.Clamp(SgdDecisionRuntimeState.AttackDamageTheta, num, num2); float attackDamageVelocity = SgdDecisionRuntimeState.AttackDamageVelocity; float num5 = Mathf.Clamp01((num4 - num) / num3); float num6 = EstimateAttackDamageSkill01(in sensors); float num7 = num5 - num6; if (Mathf.Abs(num7) < 0.03f) { num7 = 0f; } float num8 = num7 + virtualErrorContribution; float num9 = 2f * num8 * (1f / num3); num9 = Mathf.Clamp(num9, -0.5f, 0.5f); attackDamageVelocity = 0.65f * attackDamageVelocity + num9; attackDamageVelocity = Mathf.Clamp(attackDamageVelocity, -1f, 1f); float num10 = 0.18f * attackDamageVelocity; num10 = Mathf.Clamp(num10, -0.05f, 0.05f); float num11 = Mathf.Clamp(num4 - num10, num, num2); float attackDamageMultiplier = Mathf.Exp(num11); float attackDamageMultiplier2 = SgdActuatorsRuntimeState.AttackDamageMultiplier; SgdActuatorsRuntimeState.SetAttackDamageMultiplier(attackDamageMultiplier); float attackDamageMultiplier3 = SgdActuatorsRuntimeState.AttackDamageMultiplier; SgdDecisionRuntimeState.SyncAttackDamageTheta(num11, attackDamageVelocity, attackDamageMultiplier3); SgdDecisionRuntimeState.RecordAttackDamageStep(num6, num5, num8, num9, 0.18f, num10, attackDamageMultiplier3); return Mathf.Abs(attackDamageMultiplier3 - attackDamageMultiplier2) > 0.0005f; } } public static class SgdDecisionRuntimeState { public const float DefaultStepSeconds = 10f; public static float StepSeconds { get; private set; } = 10f; public static float CombatSecondsSinceLastStep { get; private set; } public static int TotalStepsDone { get; private set; } public static int AppliedMonstersLast { get; private set; } public static bool HasBaselineVirtualPower { get; private set; } public static SgdVirtualPowerSample BaselineVirtualPower { get; private set; } public static SgdVirtualPowerSample LastVirtualPowerDelta { get; private set; } public static SgdVirtualPowerSample LastVirtualChallenge { get; private set; } public static SgdVirtualPowerSample LastVirtualError { get; private set; } public static float BaselineVirtualPowerTotal => BaselineVirtualPower.Total; public static float LastVirtualPowerDeltaTotal => LastVirtualPowerDelta.Total; public static float LastVirtualChallengeTotal => LastVirtualChallenge.Total; public static float LastVirtualErrorTotal => LastVirtualError.Total; public static float LastVirtualPowerContributionHp { get; private set; } public static float LastVirtualPowerContributionMs { get; private set; } public static float LastVirtualPowerContributionAs { get; private set; } public static float LastVirtualPowerContributionDmg { get; private set; } public static bool IsMaxHealthAdaptationEnabled { get; private set; } = true; public static bool HasMaxHealthState { get; private set; } public static float MaxHealthTheta { get; private set; } public static float MaxHealthVelocity { get; private set; } public static int MaxHealthStepsDone { get; private set; } public static float MaxHealthSkill01Last { get; private set; } public static float MaxHealthChallenge01Last { get; private set; } public static float MaxHealthErrorLast { get; private set; } public static float MaxHealthGradientLast { get; private set; } public static float MaxHealthLearningRateLast { get; private set; } public static float MaxHealthDeltaThetaLast { get; private set; } public static float MaxHealthMultiplierLast { get; private set; } = 1f; public static bool IsMoveSpeedAdaptationEnabled { get; private set; } = true; public static bool HasMoveSpeedState { get; private set; } public static float MoveSpeedTheta { get; private set; } public static float MoveSpeedVelocity { get; private set; } public static int MoveSpeedStepsDone { get; private set; } public static float MoveSpeedSkill01Last { get; private set; } public static float MoveSpeedChallenge01Last { get; private set; } public static float MoveSpeedErrorLast { get; private set; } public static float MoveSpeedGradientLast { get; private set; } public static float MoveSpeedLearningRateLast { get; private set; } public static float MoveSpeedDeltaThetaLast { get; private set; } public static float MoveSpeedMultiplierLast { get; private set; } = 1f; public static bool IsAttackSpeedAdaptationEnabled { get; private set; } = true; public static bool HasAttackSpeedState { get; private set; } public static float AttackSpeedTheta { get; private set; } public static float AttackSpeedVelocity { get; private set; } public static float AttackSpeedSkill01Last { get; private set; } public static float AttackSpeedChallenge01Last { get; private set; } public static float AttackSpeedErrorLast { get; private set; } public static float AttackSpeedGradientLast { get; private set; } public static float AttackSpeedLearningRateLast { get; private set; } public static float AttackSpeedDeltaThetaLast { get; private set; } public static float AttackSpeedMultiplierLast { get; private set; } = 1f; public static int AttackSpeedStepsDone { get; private set; } public static bool IsAttackDamageAdaptationEnabled { get; private set; } = true; public static bool HasAttackDamageState { get; private set; } public static float AttackDamageTheta { get; private set; } public static float AttackDamageVelocity { get; private set; } public static int AttackDamageStepsDone { get; private set; } public static float AttackDamageSkill01Last { get; private set; } public static float AttackDamageChallenge01Last { get; private set; } public static float AttackDamageErrorLast { get; private set; } public static float AttackDamageGradientLast { get; private set; } public static float AttackDamageLearningRateLast { get; private set; } public static float AttackDamageDeltaThetaLast { get; private set; } public static float AttackDamageMultiplierLast { get; private set; } = 1f; public static float CombatSecondsUntilNextStep => Mathf.Max(0f, StepSeconds - CombatSecondsSinceLastStep); public static void Reset() { CombatSecondsSinceLastStep = 0f; TotalStepsDone = 0; AppliedMonstersLast = 0; HasBaselineVirtualPower = false; BaselineVirtualPower = default(SgdVirtualPowerSample); LastVirtualPowerDelta = default(SgdVirtualPowerSample); LastVirtualChallenge = default(SgdVirtualPowerSample); LastVirtualError = default(SgdVirtualPowerSample); LastVirtualPowerContributionHp = 0f; LastVirtualPowerContributionMs = 0f; LastVirtualPowerContributionAs = 0f; LastVirtualPowerContributionDmg = 0f; IsMaxHealthAdaptationEnabled = true; HasMaxHealthState = false; MaxHealthTheta = 0f; MaxHealthVelocity = 0f; MaxHealthStepsDone = 0; MaxHealthSkill01Last = 0f; MaxHealthChallenge01Last = 0f; MaxHealthErrorLast = 0f; MaxHealthGradientLast = 0f; MaxHealthLearningRateLast = 0f; MaxHealthDeltaThetaLast = 0f; MaxHealthMultiplierLast = 1f; IsMoveSpeedAdaptationEnabled = true; HasMoveSpeedState = false; MoveSpeedTheta = 0f; MoveSpeedVelocity = 0f; MoveSpeedStepsDone = 0; MoveSpeedSkill01Last = 0f; MoveSpeedChallenge01Last = 0f; MoveSpeedErrorLast = 0f; MoveSpeedGradientLast = 0f; MoveSpeedLearningRateLast = 0f; MoveSpeedDeltaThetaLast = 0f; MoveSpeedMultiplierLast = 1f; IsAttackSpeedAdaptationEnabled = true; HasAttackSpeedState = false; AttackSpeedTheta = 0f; AttackSpeedVelocity = 0f; AttackSpeedStepsDone = 0; AttackSpeedSkill01Last = 0f; AttackSpeedChallenge01Last = 0f; AttackSpeedErrorLast = 0f; AttackSpeedGradientLast = 0f; AttackSpeedLearningRateLast = 0f; AttackSpeedDeltaThetaLast = 0f; AttackSpeedMultiplierLast = 1f; IsAttackDamageAdaptationEnabled = true; HasAttackDamageState = false; AttackDamageTheta = 0f; AttackDamageVelocity = 0f; AttackDamageStepsDone = 0; AttackDamageSkill01Last = 0f; AttackDamageChallenge01Last = 0f; AttackDamageErrorLast = 0f; AttackDamageGradientLast = 0f; AttackDamageLearningRateLast = 0f; AttackDamageDeltaThetaLast = 0f; AttackDamageMultiplierLast = 1f; } public static void SetMaxHealthAdaptationEnabled(bool enabled) { IsMaxHealthAdaptationEnabled = enabled; MaxHealthVelocity = 0f; } public static void SetMoveSpeedAdaptationEnabled(bool enabled) { IsMoveSpeedAdaptationEnabled = enabled; MoveSpeedVelocity = 0f; } public static void SetAttackSpeedAdaptationEnabled(bool enabled) { IsAttackSpeedAdaptationEnabled = enabled; AttackSpeedVelocity = 0f; } public static void SetAttackDamageAdaptationEnabled(bool enabled) { IsAttackDamageAdaptationEnabled = enabled; AttackDamageVelocity = 0f; } public static void SetStepSeconds(float seconds) { if (!float.IsNaN(seconds) && !float.IsInfinity(seconds)) { StepSeconds = Mathf.Clamp(seconds, 1f, 300f); CombatSecondsSinceLastStep = Mathf.Clamp(CombatSecondsSinceLastStep, 0f, StepSeconds); } } internal static void RecordGlobalStep(int appliedMonsters) { TotalStepsDone++; AppliedMonstersLast = Mathf.Max(0, appliedMonsters); } internal static void CaptureBaselineVirtualPower(in SgdVirtualPowerSample virtualPower) { if (IsFinite(in virtualPower)) { HasBaselineVirtualPower = true; BaselineVirtualPower = virtualPower; } } internal static void RecordVirtualPowerCompensation(in SgdVirtualPowerSample virtualPowerDelta, in SgdVirtualPowerSample virtualChallenge, in SgdVirtualPowerSample virtualError, float hpContribution, float msContribution, float asContribution, float dmgContribution) { LastVirtualPowerDelta = virtualPowerDelta; LastVirtualChallenge = virtualChallenge; LastVirtualError = virtualError; LastVirtualPowerContributionHp = hpContribution; LastVirtualPowerContributionMs = msContribution; LastVirtualPowerContributionAs = asContribution; LastVirtualPowerContributionDmg = dmgContribution; } private static bool IsFinite(in SgdVirtualPowerSample sample) { if (IsFinite(sample.Hp) && IsFinite(sample.MoveSpeed) && IsFinite(sample.AttackSpeed)) { return IsFinite(sample.AttackDamage); } return false; } private static bool IsFinite(float value) { if (!float.IsNaN(value)) { return !float.IsInfinity(value); } return false; } internal static void AddCombatSeconds(float dt) { if (!(dt <= 0f) && !float.IsNaN(dt) && !float.IsInfinity(dt)) { CombatSecondsSinceLastStep += dt; CombatSecondsSinceLastStep = Mathf.Clamp(CombatSecondsSinceLastStep, 0f, 10000f); } } internal static int ConsumeDueSteps() { float num = StepSeconds; if (num <= 0f || float.IsNaN(num) || float.IsInfinity(num)) { num = (StepSeconds = 10f); } int num3 = (int)(CombatSecondsSinceLastStep / num); if (num3 <= 0) { return 0; } CombatSecondsSinceLastStep -= (float)num3 * num; CombatSecondsSinceLastStep = Mathf.Clamp(CombatSecondsSinceLastStep, 0f, num); return num3; } internal static void SyncMaxHealthTheta(float theta, float velocity, float multiplier) { HasMaxHealthState = true; MaxHealthTheta = theta; MaxHealthVelocity = velocity; MaxHealthMultiplierLast = multiplier; } internal static void RecordMaxHealthStep(float skill01, float challenge01, float error, float gradient, float learningRate, float deltaTheta, float newMultiplier) { MaxHealthStepsDone++; MaxHealthSkill01Last = skill01; MaxHealthChallenge01Last = challenge01; MaxHealthErrorLast = error; MaxHealthGradientLast = gradient; MaxHealthLearningRateLast = learningRate; MaxHealthDeltaThetaLast = deltaTheta; MaxHealthMultiplierLast = newMultiplier; } internal static void SyncMoveSpeedTheta(float theta, float velocity, float multiplier) { HasMoveSpeedState = true; MoveSpeedTheta = theta; MoveSpeedVelocity = velocity; MoveSpeedMultiplierLast = multiplier; } internal static void RecordMoveSpeedStep(float skill01, float challenge01, float error, float gradient, float learningRate, float deltaTheta, float newMultiplier) { MoveSpeedStepsDone++; MoveSpeedSkill01Last = skill01; MoveSpeedChallenge01Last = challenge01; MoveSpeedErrorLast = error; MoveSpeedGradientLast = gradient; MoveSpeedLearningRateLast = learningRate; MoveSpeedDeltaThetaLast = deltaTheta; MoveSpeedMultiplierLast = newMultiplier; } internal static void SyncAttackSpeedTheta(float theta, float velocity, float multiplier) { HasAttackSpeedState = true; AttackSpeedTheta = theta; AttackSpeedVelocity = velocity; AttackSpeedMultiplierLast = multiplier; } internal static void RecordAttackSpeedStep(float skill01, float challenge01, float error, float gradient, float learningRate, float deltaTheta, float newMultiplier) { AttackSpeedStepsDone++; AttackSpeedSkill01Last = skill01; AttackSpeedChallenge01Last = challenge01; AttackSpeedErrorLast = error; AttackSpeedGradientLast = gradient; AttackSpeedLearningRateLast = learningRate; AttackSpeedDeltaThetaLast = deltaTheta; AttackSpeedMultiplierLast = newMultiplier; } internal static void SyncAttackDamageTheta(float theta, float velocity, float multiplier) { HasAttackDamageState = true; AttackDamageTheta = theta; AttackDamageVelocity = velocity; AttackDamageMultiplierLast = multiplier; } internal static void RecordAttackDamageStep(float skill01, float challenge01, float error, float gradient, float learningRate, float deltaTheta, float newMultiplier) { AttackDamageStepsDone++; AttackDamageSkill01Last = skill01; AttackDamageChallenge01Last = challenge01; AttackDamageErrorLast = error; AttackDamageGradientLast = gradient; AttackDamageLearningRateLast = learningRate; AttackDamageDeltaThetaLast = deltaTheta; AttackDamageMultiplierLast = newMultiplier; } } } namespace GeneticsArtifact.SgdEngine.Actuators { public static class SgdActuatorsApplier { public static int ApplyToAllLivingMonsters() { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Invalid comparison between Unknown and I4 if (!NetworkServer.active) { return 0; } if (DdaAlgorithmState.ActiveAlgorithm != DdaAlgorithmType.Sgd) { return 0; } int num = 0; foreach (CharacterBody readOnlyInstances in CharacterBody.readOnlyInstancesList) { if (!((Object)(object)readOnlyInstances == (Object)null) && !((Object)(object)readOnlyInstances.teamComponent == (Object)null) && (int)readOnlyInstances.teamComponent.teamIndex == 2 && !((Object)(object)readOnlyInstances.inventory == (Object)null)) { SgdGeneStatTokenApplier.ApplyMultiplier(readOnlyInstances.inventory, GeneStat.MaxHealth, SgdActuatorsRuntimeState.MaxHealthMultiplier); SgdGeneStatTokenApplier.ApplyMultiplier(readOnlyInstances.inventory, GeneStat.MoveSpeed, SgdActuatorsRuntimeState.MoveSpeedMultiplier); SgdGeneStatTokenApplier.ApplyMultiplier(readOnlyInstances.inventory, GeneStat.AttackSpeed, SgdActuatorsRuntimeState.AttackSpeedMultiplier); SgdGeneStatTokenApplier.ApplyMultiplier(readOnlyInstances.inventory, GeneStat.AttackDamage, SgdActuatorsRuntimeState.AttackDamageMultiplier); readOnlyInstances.RecalculateStats(); num++; } } return num; } } public static class SgdActuatorsHooks { public static void RegisterHooks() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown CharacterBody.Start += new hook_Start(CharacterBody_Start); } private static void CharacterBody_Start(orig_Start orig, CharacterBody self) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Invalid comparison between Unknown and I4 orig.Invoke(self); if (NetworkServer.active && !((Object)(object)self == (Object)null) && DdaAlgorithmState.ActiveAlgorithm == DdaAlgorithmType.Sgd && !((Object)(object)self.teamComponent == (Object)null) && (int)self.teamComponent.teamIndex == 2 && !((Object)(object)self.inventory == (Object)null)) { SgdGeneStatTokenApplier.ApplyMultiplier(self.inventory, GeneStat.MaxHealth, SgdActuatorsRuntimeState.MaxHealthMultiplier); SgdGeneStatTokenApplier.ApplyMultiplier(self.inventory, GeneStat.MoveSpeed, SgdActuatorsRuntimeState.MoveSpeedMultiplier); SgdGeneStatTokenApplier.ApplyMultiplier(self.inventory, GeneStat.AttackSpeed, SgdActuatorsRuntimeState.AttackSpeedMultiplier); SgdGeneStatTokenApplier.ApplyMultiplier(self.inventory, GeneStat.AttackDamage, SgdActuatorsRuntimeState.AttackDamageMultiplier); self.RecalculateStats(); } } } public static class SgdActuatorsRuntimeState { public static float MaxHealthMultiplier { get; private set; } = 1f; public static float MoveSpeedMultiplier { get; private set; } = 1f; public static float AttackSpeedMultiplier { get; private set; } = 1f; public static float AttackDamageMultiplier { get; private set; } = 1f; public static void Reset() { MaxHealthMultiplier = 1f; MoveSpeedMultiplier = 1f; AttackSpeedMultiplier = 1f; AttackDamageMultiplier = 1f; } public static void SetMaxHealthMultiplier(float multiplier) { if (!float.IsNaN(multiplier) && !float.IsInfinity(multiplier)) { MaxHealthMultiplier = SgdAxisLimitProvider.Clamp(GeneStat.MaxHealth, multiplier); } } public static void SetMoveSpeedMultiplier(float multiplier) { if (!float.IsNaN(multiplier) && !float.IsInfinity(multiplier)) { MoveSpeedMultiplier = SgdAxisLimitProvider.Clamp(GeneStat.MoveSpeed, multiplier); } } public static void SetAttackSpeedMultiplier(float multiplier) { if (!float.IsNaN(multiplier) && !float.IsInfinity(multiplier)) { AttackSpeedMultiplier = SgdAxisLimitProvider.Clamp(GeneStat.AttackSpeed, multiplier); } } public static void SetAttackDamageMultiplier(float multiplier) { if (!float.IsNaN(multiplier) && !float.IsInfinity(multiplier)) { AttackDamageMultiplier = SgdAxisLimitProvider.Clamp(GeneStat.AttackDamage, multiplier); } } } public static class SgdGeneStatTokenApplier { public static void ApplyMultiplier(Inventory inventory, GeneStat stat, float multiplier) { if (!((Object)(object)inventory == (Object)null) && !float.IsNaN(multiplier) && !float.IsInfinity(multiplier) && !(multiplier <= 0f)) { multiplier = SgdAxisLimitProvider.Clamp(stat, multiplier); int num = Mathf.RoundToInt((multiplier - 1f) * 100f); int desiredCount = ((num > 0) ? num : 0); int desiredCount2 = ((num < 0) ? (-num) : 0); ItemDef itemDef = GeneTokens.tokenDict[stat][GeneMod.Plus1]; ItemDef itemDef2 = GeneTokens.tokenDict[stat][GeneMod.Minus1]; SetExactCount(inventory, itemDef, desiredCount); SetExactCount(inventory, itemDef2, desiredCount2); } } private static void SetExactCount(Inventory inventory, ItemDef itemDef, int desiredCount) { if ((Object)(object)inventory == (Object)null || (Object)(object)itemDef == (Object)null) { return; } desiredCount = Mathf.Max(0, desiredCount); int itemCount = inventory.GetItemCount(itemDef); if (itemCount != desiredCount) { if (itemCount > 0) { inventory.RemoveItem(itemDef, itemCount); } if (desiredCount > 0) { inventory.GiveItem(itemDef, desiredCount); } } } } } namespace GeneticsArtifact.CheatManager { public static class DdaAlgorithmState { public static bool IsGeneticAlgorithmEnabled { get; set; } public static DdaAlgorithmType ActiveAlgorithm { get; set; } = DdaAlgorithmType.Sgd; public static bool IsDebugOverlayEnabled { get; set; } public static bool IsTelemetryOverlayEnabled { get; set; } public static void Activate(DdaAlgorithmType algorithm) { ActiveAlgorithm = algorithm; IsGeneticAlgorithmEnabled = algorithm == DdaAlgorithmType.Genetic; } public static string GetTelemetryMode() { if (ActiveAlgorithm == DdaAlgorithmType.Fixed) { return "FLS"; } if (ActiveAlgorithm == DdaAlgorithmType.Sgd) { return "SGD"; } if (ActiveAlgorithm == DdaAlgorithmType.Genetic && IsGeneticAlgorithmEnabled) { return "GA"; } return "FLS"; } public static bool ShouldRunGeneticEngine() { if (ActiveAlgorithm == DdaAlgorithmType.Genetic) { return IsGeneticAlgorithmEnabled; } return false; } } public enum DdaAlgorithmType { Fixed, Genetic, Sgd } public static class DdaCheatManager { public static void Init() { CommandHelper.AddToConsoleWhenReady(); ManualLogSource geneticLogSource = GeneticsArtifactPlugin.geneticLogSource; if (geneticLogSource != null) { geneticLogSource.LogInfo((object)"DDA CheatManager: Console commands registered."); } } [ConCommand(commandName = "dda_genetics", helpText = "Toggle genetic algorithm. Usage: dda_genetics [0|1]")] private static void OnGeneticsToggle(ConCommandArgs args) { if (((ConCommandArgs)(ref args)).Count > 0) { if (int.TryParse(((ConCommandArgs)(ref args))[0], out var result)) { if (result != 0) { DdaAlgorithmState.Activate(DdaAlgorithmType.Genetic); } else { DdaAlgorithmState.Activate(DdaAlgorithmType.Fixed); } } } else { DdaAlgorithmState.Activate((!DdaAlgorithmState.ShouldRunGeneticEngine()) ? DdaAlgorithmType.Genetic : DdaAlgorithmType.Fixed); } Debug.Log((object)("[DDA] Genetic algorithm: " + (DdaAlgorithmState.IsGeneticAlgorithmEnabled ? "ENABLED" : "DISABLED"))); } [ConCommand(commandName = "dda_algorithm", helpText = "Switch DDA algorithm. Usage: dda_algorithm [fixed|genetic|sgd]")] private static void OnAlgorithmSwitch(ConCommandArgs args) { if (((ConCommandArgs)(ref args)).Count > 0) { switch (((ConCommandArgs)(ref args))[0].ToLowerInvariant()) { case "fixed": case "fls": DdaAlgorithmState.Activate(DdaAlgorithmType.Fixed); Debug.Log((object)"[DDA] Algorithm set to: Fixed difficulty"); break; case "genetic": case "ga": DdaAlgorithmState.Activate(DdaAlgorithmType.Genetic); Debug.Log((object)"[DDA] Algorithm set to: Genetic"); break; case "sgd": DdaAlgorithmState.Activate(DdaAlgorithmType.Sgd); Debug.Log((object)"[DDA] Algorithm set to: SGD"); break; default: Debug.Log((object)"[DDA] Unknown algorithm. Use: fixed, genetic, sgd"); break; } } else { Debug.Log((object)$"[DDA] Current algorithm: {DdaAlgorithmState.ActiveAlgorithm}"); } } [ConCommand(commandName = "dda_debug_overlay", helpText = "Toggle debug overlay. Usage: dda_debug_overlay [0|1]")] private static void OnDebugOverlayToggle(ConCommandArgs args) { if (((ConCommandArgs)(ref args)).Count > 0) { if (int.TryParse(((ConCommandArgs)(ref args))[0], out var result)) { DdaAlgorithmState.IsDebugOverlayEnabled = result != 0; } } else { DdaAlgorithmState.IsDebugOverlayEnabled = !DdaAlgorithmState.IsDebugOverlayEnabled; } DebugOverlayBehaviour.UpdateVisibility(); Debug.Log((object)("[DDA] Debug overlay: " + (DdaAlgorithmState.IsDebugOverlayEnabled ? "ENABLED" : "DISABLED"))); } [ConCommand(commandName = "dda_telemetry_overlay", helpText = "Toggle telemetry overlay (last enqueued dda_sample). Usage: dda_telemetry_overlay [0|1]")] private static void OnTelemetryOverlayToggle(ConCommandArgs args) { if (((ConCommandArgs)(ref args)).Count > 0) { if (int.TryParse(((ConCommandArgs)(ref args))[0], out var result)) { DdaAlgorithmState.IsTelemetryOverlayEnabled = result != 0; } } else { DdaAlgorithmState.IsTelemetryOverlayEnabled = !DdaAlgorithmState.IsTelemetryOverlayEnabled; } TelemetryDebugOverlayBehaviour.UpdateVisibility(); Debug.Log((object)("[DDA] Telemetry overlay: " + (DdaAlgorithmState.IsTelemetryOverlayEnabled ? "ENABLED" : "DISABLED"))); } [ConCommand(commandName = "dda_param", helpText = "Change DDA parameters (placeholder). Usage: dda_param [param_name] [value]")] private static void OnParamCommand(ConCommandArgs args) { Debug.Log((object)"[DDA] dda_param: Not yet implemented. Use config file for now."); } [ConCommand(commandName = "dda_survey", helpText = "Send post-session Likert survey for H5-H6. Usage: dda_survey [comment]")] private static void OnPostSessionSurveyCommand(ConCommandArgs args) { if (((ConCommandArgs)(ref args)).Count < 2 || !int.TryParse(((ConCommandArgs)(ref args))[0], out var result) || !int.TryParse(((ConCommandArgs)(ref args))[1], out var result2)) { Debug.Log((object)"[DDA] Usage: dda_survey [comment]"); return; } result = Mathf.Clamp(result, 1, 7); result2 = Mathf.Clamp(result2, 1, 7); string comment = ""; if (((ConCommandArgs)(ref args)).Count > 2) { string[] array = new string[((ConCommandArgs)(ref args)).Count - 2]; for (int i = 2; i < ((ConCommandArgs)(ref args)).Count; i++) { array[i - 2] = ((ConCommandArgs)(ref args))[i]; } comment = string.Join(" ", array); } if (!TelemetryRuntimeDriver.RecordPostSessionSurvey(result, result2, comment)) { Debug.Log((object)"[DDA] Survey was not sent: no active telemetry session."); } else { Debug.Log((object)$"[DDA] Survey sent: fairness={result}, continuity={result2}"); } } [ConCommand(commandName = "dda_sgd_step_time", helpText = "Set SGD gradient step time (seconds). Counts only combat time. Usage: dda_sgd_step_time [seconds]")] private static void OnSgdStepTimeCommand(ConCommandArgs args) { if (((ConCommandArgs)(ref args)).Count <= 0) { Debug.Log((object)$"[DDA] SGD step time: {SgdDecisionRuntimeState.StepSeconds:F1}s (combat time only)"); return; } if (!TryParseFloat(((ConCommandArgs)(ref args))[0], out var value)) { Debug.Log((object)"[DDA] Usage: dda_sgd_step_time [seconds]. Example: dda_sgd_step_time 10"); return; } DdaAlgorithmState.Activate(DdaAlgorithmType.Sgd); SgdDecisionRuntimeState.SetStepSeconds(value); Debug.Log((object)$"[DDA] SGD step time set to: {SgdDecisionRuntimeState.StepSeconds:F1}s (combat time only)"); } private static void HandleSgdAxisToggleCommand(ConCommandArgs args, string commandName, string axisDisplayName, Func getValue, Action setValue) { bool flag = getValue(); if (((ConCommandArgs)(ref args)).Count > 0) { if (!int.TryParse(((ConCommandArgs)(ref args))[0], out var result)) { Debug.Log((object)("[DDA] Usage: " + commandName + " [0|1]. Example: " + commandName + " 0")); return; } flag = result != 0; } else { flag = !flag; } DdaAlgorithmState.Activate(DdaAlgorithmType.Sgd); setValue(flag); Debug.Log((object)("[DDA] SGD axis " + axisDisplayName + " adaptation: " + (flag ? "ENABLED" : "DISABLED"))); } [ConCommand(commandName = "dda_sgd_axis_hp", helpText = "Toggle SGD adaptation axis: enemy MaxHealth (HP). Usage: dda_sgd_axis_hp [0|1]")] private static void OnSgdAxisMaxHealthCommand(ConCommandArgs args) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) HandleSgdAxisToggleCommand(args, "dda_sgd_axis_hp", "MaxHealth (HP)", () => SgdDecisionRuntimeState.IsMaxHealthAdaptationEnabled, SgdDecisionRuntimeState.SetMaxHealthAdaptationEnabled); } [ConCommand(commandName = "dda_sgd_axis_ms", helpText = "Toggle SGD adaptation axis: enemy MoveSpeed. Usage: dda_sgd_axis_ms [0|1]")] private static void OnSgdAxisMoveSpeedCommand(ConCommandArgs args) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) HandleSgdAxisToggleCommand(args, "dda_sgd_axis_ms", "MoveSpeed (MS)", () => SgdDecisionRuntimeState.IsMoveSpeedAdaptationEnabled, SgdDecisionRuntimeState.SetMoveSpeedAdaptationEnabled); } [ConCommand(commandName = "dda_sgd_axis_as", helpText = "Toggle SGD adaptation axis: enemy AttackSpeed. Usage: dda_sgd_axis_as [0|1]")] private static void OnSgdAxisAttackSpeedCommand(ConCommandArgs args) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) HandleSgdAxisToggleCommand(args, "dda_sgd_axis_as", "AttackSpeed (AS)", () => SgdDecisionRuntimeState.IsAttackSpeedAdaptationEnabled, SgdDecisionRuntimeState.SetAttackSpeedAdaptationEnabled); } [ConCommand(commandName = "dda_sgd_axis_dmg", helpText = "Toggle SGD adaptation axis: enemy AttackDamage (DMG). Usage: dda_sgd_axis_dmg [0|1]")] private static void OnSgdAxisAttackDamageCommand(ConCommandArgs args) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) HandleSgdAxisToggleCommand(args, "dda_sgd_axis_dmg", "AttackDamage (DMG)", () => SgdDecisionRuntimeState.IsAttackDamageAdaptationEnabled, SgdDecisionRuntimeState.SetAttackDamageAdaptationEnabled); } [ConCommand(commandName = "dda_actuator_hp", helpText = "Set SGD actuator: monster MaxHealth multiplier. Applies to existing monsters on level and future spawns. Usage: dda_actuator_hp ")] private static void OnSgdHpCommand(ConCommandArgs args) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) HandleSgdActuatorFloatCommand(args, "dda_actuator_hp", "HP (MaxHealth)", () => SgdActuatorsRuntimeState.MaxHealthMultiplier, SgdActuatorsRuntimeState.SetMaxHealthMultiplier); } [ConCommand(commandName = "dda_actuator_ms", helpText = "Set SGD actuator: monster MoveSpeed multiplier. Applies to existing monsters on level and future spawns. Usage: dda_actuator_ms ")] private static void OnSgdMoveSpeedCommand(ConCommandArgs args) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) HandleSgdActuatorFloatCommand(args, "dda_actuator_ms", "MS (MoveSpeed)", () => SgdActuatorsRuntimeState.MoveSpeedMultiplier, SgdActuatorsRuntimeState.SetMoveSpeedMultiplier); } [ConCommand(commandName = "dda_actuator_as", helpText = "Set SGD actuator: monster AttackSpeed multiplier. Applies to existing monsters on level and future spawns. Usage: dda_actuator_as ")] private static void OnSgdAttackSpeedCommand(ConCommandArgs args) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) HandleSgdActuatorFloatCommand(args, "dda_actuator_as", "AS (AttackSpeed)", () => SgdActuatorsRuntimeState.AttackSpeedMultiplier, SgdActuatorsRuntimeState.SetAttackSpeedMultiplier); } [ConCommand(commandName = "dda_actuator_dmg", helpText = "Set SGD actuator: monster AttackDamage multiplier. Applies to existing monsters on level and future spawns. Usage: dda_actuator_dmg ")] private static void OnSgdAttackDamageCommand(ConCommandArgs args) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) HandleSgdActuatorFloatCommand(args, "dda_actuator_dmg", "DMG (AttackDamage)", () => SgdActuatorsRuntimeState.AttackDamageMultiplier, SgdActuatorsRuntimeState.SetAttackDamageMultiplier); } private static bool TryParseFloat(string s, out float value) { if (float.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out value)) { return true; } s = s?.Replace(',', '.'); return float.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out value); } private static void HandleSgdActuatorFloatCommand(ConCommandArgs args, string commandName, string statDisplayName, Func getValue, Action setValue) { if (((ConCommandArgs)(ref args)).Count <= 0) { Debug.Log((object)$"[DDA] SGD {statDisplayName} multiplier: {getValue():F2}"); return; } if (!TryParseFloat(((ConCommandArgs)(ref args))[0], out var value)) { Debug.Log((object)("[DDA] Usage: " + commandName + " . Example: " + commandName + " 1.50")); return; } DdaAlgorithmState.Activate(DdaAlgorithmType.Sgd); setValue(value); float num = getValue(); if (!NetworkServer.active) { Debug.Log((object)$"[DDA] SGD actuator set: {statDisplayName} multiplier = {num:F2}. (Not applied now: NetworkServer is not active)"); return; } int num2 = SgdActuatorsApplier.ApplyToAllLivingMonsters(); Debug.Log((object)$"[DDA] SGD actuator set: {statDisplayName} multiplier = {num:F2}. Applied to {num2} existing monsters; will apply to future spawns. Tip: run 'dda_genetics 0' to avoid genetic engine interference."); } [ConCommand(commandName = "dda_show_monster_hp", helpText = "Toggle HP numbers above monsters (client-side). Usage: dda_show_monster_hp [0|1]")] private static void OnMonsterHpOverlay(ConCommandArgs args) { if (((ConCommandArgs)(ref args)).Count > 0) { if (!int.TryParse(((ConCommandArgs)(ref args))[0], out var result)) { Debug.Log((object)"[DDA] Usage: dda_show_monster_hp [0|1]"); return; } MonsterHpOverheadDriver.SetEnabled(result != 0); } else { MonsterHpOverheadDriver.SetEnabled(!MonsterHpOverheadDriver.IsEnabled); } Debug.Log((object)("[DDA] Monster HP overhead: " + (MonsterHpOverheadDriver.IsEnabled ? "ENABLED" : "DISABLED"))); } } public static class DdaRunModeRotator { private const string LogPrefix = "[DDA][Seed] "; private const string DefaultRunSeedCycle = "8459684015804115075,8821573197706646788,2559340200192868678,97399012779323199,1444060760769064427"; public static void RegisterHooks() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown PreGameController.StartRun += new hook_StartRun(PreGameController_StartRun); ManualLogSource geneticLogSource = GeneticsArtifactPlugin.geneticLogSource; if (geneticLogSource != null) { geneticLogSource.LogInfo((object)"[DDA] Research run mode rotator enabled (PreGameController.StartRun)."); } } private static void PreGameController_StartRun(orig_StartRun orig, PreGameController self) { try { if (NetworkServer.active && ConfigManager.researchAutoRotateDdaAlgorithms.Value) { string text = Normalize(ConfigManager.researchLastRunDdaAlgorithm.Value); DdaAlgorithmState.Activate(GetNextAlgorithm(text)); string telemetryMode = DdaAlgorithmState.GetTelemetryMode(); string text2 = SelectConfiguredSeed(text, telemetryMode); ConfigManager.researchLastRunDdaAlgorithm.Value = telemetryMode; ConfigManager.telemetryConfiguredRunSeed.Value = text2; ConfigManager.Save(); LogSeedSelection(text, telemetryMode, text2); if (!string.IsNullOrWhiteSpace(text2)) { ApplyConfiguredRunSeed(self, text2); } ManualLogSource geneticLogSource = GeneticsArtifactPlugin.geneticLogSource; if (geneticLogSource != null) { geneticLogSource.LogInfo((object)("[DDA] Research run mode selected (StartRun): " + telemetryMode + (string.IsNullOrWhiteSpace(text2) ? "" : (", planned_seed=" + text2)))); } } } catch (Exception ex) { ManualLogSource geneticLogSource2 = GeneticsArtifactPlugin.geneticLogSource; if (geneticLogSource2 != null) { geneticLogSource2.LogWarning((object)("[DDA] PreGameController.StartRun rotator hook failed; falling back to vanilla StartRun. Error: " + ex.GetType().Name + ": " + ex.Message)); } } orig.Invoke(self); } private static void Run_Start(orig_Start orig, Run self) { try { if (NetworkServer.active && ConfigManager.researchAutoRotateDdaAlgorithms.Value) { string text = Normalize(ConfigManager.researchLastRunDdaAlgorithm.Value); DdaAlgorithmState.Activate(GetNextAlgorithm(text)); string telemetryMode = DdaAlgorithmState.GetTelemetryMode(); string text2 = SelectConfiguredSeed(text, telemetryMode); ConfigManager.researchLastRunDdaAlgorithm.Value = telemetryMode; ConfigManager.telemetryConfiguredRunSeed.Value = text2; ConfigManager.Save(); LogSeedSelection(text, telemetryMode, text2); ManualLogSource geneticLogSource = GeneticsArtifactPlugin.geneticLogSource; if (geneticLogSource != null) { geneticLogSource.LogInfo((object)("[DDA] Research run mode selected (pre-run): " + telemetryMode + (string.IsNullOrWhiteSpace(text2) ? "" : (", planned_seed=" + text2)) + " (seed forcing disabled)")); } } } catch (Exception ex) { ManualLogSource geneticLogSource2 = GeneticsArtifactPlugin.geneticLogSource; if (geneticLogSource2 != null) { geneticLogSource2.LogWarning((object)("[DDA] Run.Start rotator hook failed; falling back to vanilla Run.Start. Error: " + ex.GetType().Name + ": " + ex.Message)); } } orig.Invoke(self); } private static DdaAlgorithmType GetNextAlgorithm(string normalizedLast) { return normalizedLast switch { "SGD" => DdaAlgorithmType.Genetic, "GA" => DdaAlgorithmType.Fixed, "FLS" => DdaAlgorithmType.Sgd, _ => DdaAlgorithmType.Sgd, }; } private static string Normalize(string value) { if (string.IsNullOrWhiteSpace(value)) { return "None"; } string text = value.Trim().ToUpperInvariant(); switch (text) { case "FIXED": case "FIXEDDISABLED": return "FLS"; case "GENETIC": return "GA"; default: return text; } } private static string SelectConfiguredSeed(string normalizedLastAlgorithm, string nextTelemetryMode) { if (!ConfigManager.researchAutoRotateRunSeeds.Value) { return ConfigManager.telemetryConfiguredRunSeed.Value ?? ""; } List list = ParseSeedCycle(GetSeedCycleRaw()); if (list.Count <= 0) { ConfigManager.researchCurrentRunSeed.Value = ""; return ""; } int num = ClampSeedIndex(ConfigManager.researchCurrentRunSeedIndex.Value, list.Count); if (normalizedLastAlgorithm == "FLS" && nextTelemetryMode == "SGD") { num = (num + 1) % list.Count; ConfigManager.researchCurrentRunSeedIndex.Value = num; } string text = list[num]; ConfigManager.researchCurrentRunSeed.Value = text; return text; } private static string GetSeedCycleRaw() { string value = ConfigManager.researchRunSeedCycle.Value; if (!string.IsNullOrWhiteSpace(value)) { return value; } return "8459684015804115075,8821573197706646788,2559340200192868678,97399012779323199,1444060760769064427"; } private static string GetTelemetryMode(DdaAlgorithmType algorithm) { return algorithm switch { DdaAlgorithmType.Fixed => "FLS", DdaAlgorithmType.Sgd => "SGD", _ => "GA", }; } private static List ParseSeedCycle(string raw) { List list = new List(); if (string.IsNullOrWhiteSpace(raw)) { return list; } string[] array = raw.Split(new char[7] { ',', ';', '|', '\n', '\r', '\t', ' ' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length > 0) { list.Add(text); } } return list; } private static int ClampSeedIndex(int index, int count) { if (count <= 0) { return 0; } if (index < 0) { return 0; } return index % count; } private static void ApplyConfiguredRunSeed(PreGameController preGame, string configuredSeed) { if ((Object)(object)preGame == (Object)null || string.IsNullOrWhiteSpace(configuredSeed)) { return; } if (!ulong.TryParse(configuredSeed.Trim(), out var result)) { ManualLogSource geneticLogSource = GeneticsArtifactPlugin.geneticLogSource; if (geneticLogSource != null) { geneticLogSource.LogWarning((object)("[DDA] Research run seed was not applied: seed is not an unsigned integer: " + configuredSeed)); } return; } string text = TryDescribeSeedMember(preGame, "runSeed"); string text2 = TryDescribeSeedMember(preGame, "seed"); bool flag = TrySetSeedMemberWithLog(preGame, "runSeed", result); bool flag2 = !flag && TrySetSeedMemberWithLog(preGame, "seed", result); string text3 = TryDescribeSeedMember(preGame, "runSeed"); string text4 = TryDescribeSeedMember(preGame, "seed"); ManualLogSource geneticLogSource2 = GeneticsArtifactPlugin.geneticLogSource; if (geneticLogSource2 != null) { geneticLogSource2.LogInfo((object)("[DDA][Seed] PreGameController seed members before: runSeed=" + text + ", seed=" + text2 + " | after: runSeed=" + text3 + ", seed=" + text4)); } if (flag || flag2) { ManualLogSource geneticLogSource3 = GeneticsArtifactPlugin.geneticLogSource; if (geneticLogSource3 != null) { geneticLogSource3.LogInfo((object)("[DDA][Seed] Applied configured seed=" + result + " to PreGameController (StartRun)")); } } else { ManualLogSource geneticLogSource4 = GeneticsArtifactPlugin.geneticLogSource; if (geneticLogSource4 != null) { geneticLogSource4.LogWarning((object)"[DDA] Research run seed could not be applied to PreGameController via reflection; it will still be sent as configured_run_seed."); } } } private static void ApplyConfiguredRunSeed(Run run, string configuredSeed) { if ((Object)(object)run == (Object)null || string.IsNullOrWhiteSpace(configuredSeed)) { return; } if (!ulong.TryParse(configuredSeed.Trim(), out var result)) { ManualLogSource geneticLogSource = GeneticsArtifactPlugin.geneticLogSource; if (geneticLogSource != null) { geneticLogSource.LogWarning((object)("[DDA] Research run seed was not applied: seed is not an unsigned integer: " + configuredSeed)); } } else if (TrySetSeedMember(run, "seed", result) || TrySetSeedMember(run, "runSeed", result)) { ManualLogSource geneticLogSource2 = GeneticsArtifactPlugin.geneticLogSource; if (geneticLogSource2 != null) { geneticLogSource2.LogInfo((object)("[DDA] Research run seed applied: " + result)); } } else { ManualLogSource geneticLogSource3 = GeneticsArtifactPlugin.geneticLogSource; if (geneticLogSource3 != null) { geneticLogSource3.LogWarning((object)"[DDA] Research run seed could not be applied to Run via reflection; it will still be sent as configured_run_seed."); } } } private static bool TrySetSeedMember(object instance, string memberName, ulong seed) { if (instance == null) { return false; } Type type = instance.GetType(); FieldInfo field = type.GetField(memberName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { return TrySetSeedValue(instance, field.FieldType, delegate(object value) { field.SetValue(instance, value); }, seed); } PropertyInfo property = type.GetProperty(memberName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null && property.CanWrite) { return TrySetSeedValue(instance, property.PropertyType, delegate(object value) { property.SetValue(instance, value, null); }, seed); } return false; } private static bool TrySetSeedMemberWithLog(object instance, string memberName, ulong seed) { if (instance == null) { return false; } Type type = instance.GetType(); FieldInfo field = type.GetField(memberName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { bool flag = TrySetSeedValue(instance, field.FieldType, delegate(object value) { field.SetValue(instance, value); }, seed); ManualLogSource geneticLogSource = GeneticsArtifactPlugin.geneticLogSource; if (geneticLogSource != null) { geneticLogSource.LogInfo((object)("[DDA][Seed] TrySet " + type.Name + "." + memberName + " (field:" + field.FieldType.Name + ") => " + (flag ? "OK" : "FAIL"))); } return flag; } PropertyInfo property = type.GetProperty(memberName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null) { if (!property.CanWrite) { ManualLogSource geneticLogSource2 = GeneticsArtifactPlugin.geneticLogSource; if (geneticLogSource2 != null) { geneticLogSource2.LogInfo((object)("[DDA][Seed] TrySet " + type.Name + "." + memberName + " (property:" + property.PropertyType.Name + ") => SKIP (no setter)")); } return false; } bool flag2 = TrySetSeedValue(instance, property.PropertyType, delegate(object value) { property.SetValue(instance, value, null); }, seed); ManualLogSource geneticLogSource3 = GeneticsArtifactPlugin.geneticLogSource; if (geneticLogSource3 != null) { geneticLogSource3.LogInfo((object)("[DDA][Seed] TrySet " + type.Name + "." + memberName + " (property:" + property.PropertyType.Name + ") => " + (flag2 ? "OK" : "FAIL"))); } return flag2; } ManualLogSource geneticLogSource4 = GeneticsArtifactPlugin.geneticLogSource; if (geneticLogSource4 != null) { geneticLogSource4.LogInfo((object)("[DDA][Seed] TrySet " + type.Name + "." + memberName + " => MISS (no field/property)")); } return false; } private static string TryDescribeSeedMember(object instance, string memberName) { if (instance == null) { return "null"; } Type type = instance.GetType(); try { FieldInfo field = type.GetField(memberName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { object value = field.GetValue(instance); return (value == null) ? "null" : (value?.ToString() + " (" + field.FieldType.Name + ")"); } PropertyInfo property = type.GetProperty(memberName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null && property.CanRead) { object value2 = property.GetValue(instance, null); return (value2 == null) ? "null" : (value2?.ToString() + " (" + property.PropertyType.Name + ")"); } return ""; } catch (Exception ex) { return ""; } } private static void LogSeedSelection(string normalizedLastAlgorithm, string nextTelemetryMode, string configuredSeed) { if (GeneticsArtifactPlugin.geneticLogSource != null) { bool value = ConfigManager.researchAutoRotateRunSeeds.Value; int value2 = ConfigManager.researchCurrentRunSeedIndex.Value; string seedCycleRaw = GetSeedCycleRaw(); string text = ConfigManager.researchCurrentRunSeed.Value ?? ""; GeneticsArtifactPlugin.geneticLogSource.LogInfo((object)("[DDA][Seed] Select seed: last=" + normalizedLastAlgorithm + ", next=" + nextTelemetryMode + ", rotate=" + value + ", idx=" + value2 + ", selected=" + (string.IsNullOrWhiteSpace(configuredSeed) ? "" : configuredSeed) + ", current=" + (string.IsNullOrWhiteSpace(text) ? "" : text) + ", cycle_raw_len=" + seedCycleRaw.Length)); } } private static bool TrySetSeedValue(object target, Type memberType, Action setValue, ulong seed) { try { if (memberType == typeof(ulong)) { setValue(seed); return true; } if (memberType == typeof(long)) { setValue((long)seed); return true; } if (memberType == typeof(uint)) { setValue((uint)seed); return true; } if (memberType == typeof(int)) { setValue((int)seed); return true; } if (memberType == typeof(string)) { setValue(seed.ToString()); return true; } } catch (Exception ex) { ManualLogSource geneticLogSource = GeneticsArtifactPlugin.geneticLogSource; if (geneticLogSource != null) { geneticLogSource.LogWarning((object)("[DDA] Research run seed assignment failed: " + ex.Message)); } } return false; } } public class DebugOverlayBehaviour : MonoBehaviour { private static DebugOverlayBehaviour _instance; private static GameObject _overlayRoot; private static Text _textComponent; private static float _updateTimer; public static void UpdateVisibility() { if (DdaAlgorithmState.IsDebugOverlayEnabled) { EnsureOverlayExists(); if ((Object)(object)_instance != (Object)null) { ((Component)_instance).gameObject.SetActive(true); } } else if ((Object)(object)_instance != (Object)null) { ((Component)_instance).gameObject.SetActive(false); } } private static Font GetFontForOverlay() { Font builtinResource = Resources.GetBuiltinResource("Arial.ttf"); if ((Object)(object)builtinResource != (Object)null) { return builtinResource; } builtinResource = Resources.GetBuiltinResource("LegacyRuntime.ttf"); if ((Object)(object)builtinResource != (Object)null) { return builtinResource; } return Font.CreateDynamicFontFromOSFont("Arial", 14); } private static void EnsureOverlayExists() { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Expected O, but got Unknown //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_overlayRoot != (Object)null) { MakeOverlayClickThrough(_overlayRoot); if ((Object)(object)_textComponent != (Object)null) { ApplyTextStyle(_textComponent); ((Graphic)_textComponent).raycastTarget = false; } return; } _overlayRoot = new GameObject("DdaDebugOverlay"); Object.DontDestroyOnLoad((Object)(object)_overlayRoot); Canvas obj = _overlayRoot.AddComponent(); obj.renderMode = (RenderMode)0; obj.sortingOrder = 1000; _overlayRoot.AddComponent().uiScaleMode = (ScaleMode)1; MakeOverlayClickThrough(_overlayRoot); GameObject val = new GameObject("DebugText"); val.transform.SetParent(_overlayRoot.transform, false); _textComponent = val.AddComponent(); _textComponent.font = GetFontForOverlay(); ApplyTextStyle(_textComponent); ((Graphic)_textComponent).raycastTarget = false; RectTransform rectTransform = ((Graphic)_textComponent).rectTransform; rectTransform.anchorMin = new Vector2(0.02f, 0.98f); rectTransform.anchorMax = new Vector2(0.98f, 0.98f); rectTransform.pivot = new Vector2(0.5f, 1f); rectTransform.sizeDelta = new Vector2(-40f, 520f); rectTransform.anchoredPosition = Vector2.zero; _instance = _overlayRoot.AddComponent(); } private static void ApplyTextStyle(Text text) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)text == (Object)null)) { text.fontSize = 9; ((Graphic)text).color = new Color(0.85f, 1f, 0.85f, 1f); text.alignment = (TextAnchor)0; text.horizontalOverflow = (HorizontalWrapMode)0; text.verticalOverflow = (VerticalWrapMode)1; Outline obj = ((Component)text).GetComponent() ?? ((Component)text).gameObject.AddComponent(); ((Shadow)obj).effectColor = new Color(0f, 0f, 0f, 0.75f); ((Shadow)obj).effectDistance = new Vector2(1f, -1f); ((Shadow)obj).useGraphicAlpha = true; } } private static void MakeOverlayClickThrough(GameObject overlayRoot) { if (!((Object)(object)overlayRoot == (Object)null)) { GraphicRaycaster component = overlayRoot.GetComponent(); if ((Object)(object)component != (Object)null) { ((Behaviour)component).enabled = false; } CanvasGroup obj = overlayRoot.GetComponent() ?? overlayRoot.AddComponent(); obj.interactable = false; obj.blocksRaycasts = false; obj.ignoreParentGroups = true; } } private void Update() { if (!DdaAlgorithmState.IsDebugOverlayEnabled || (Object)(object)_textComponent == (Object)null) { return; } _updateTimer += Time.deltaTime; if (_updateTimer >= 0.5f) { _updateTimer = 0f; string text = "Actuators:\n" + $"HP (MaxHealth): {SgdActuatorsRuntimeState.MaxHealthMultiplier:F2}\n" + $"MS (MoveSpeed): {SgdActuatorsRuntimeState.MoveSpeedMultiplier:F2}\n" + $"AS (AttackSpeed): {SgdActuatorsRuntimeState.AttackSpeedMultiplier:F2}\n" + $"DMG (AttackDamage): {SgdActuatorsRuntimeState.AttackDamageMultiplier:F2}\n\n"; string text2 = "Decision (SGD):\n" + $"Step: {SgdDecisionRuntimeState.StepSeconds:F1}s\n" + $"Combat timer: {SgdDecisionRuntimeState.CombatSecondsSinceLastStep:F1}s (next in {SgdDecisionRuntimeState.CombatSecondsUntilNextStep:F1}s)\n" + $"Applied to monsters (last step): {SgdDecisionRuntimeState.AppliedMonstersLast}\n" + "Axes enabled:\n HP: " + (SgdDecisionRuntimeState.IsMaxHealthAdaptationEnabled ? "ENABLED" : "DISABLED") + "\n MS: " + (SgdDecisionRuntimeState.IsMoveSpeedAdaptationEnabled ? "ENABLED" : "DISABLED") + "\n AS: " + (SgdDecisionRuntimeState.IsAttackSpeedAdaptationEnabled ? "ENABLED" : "DISABLED") + "\n DMG: " + (SgdDecisionRuntimeState.IsAttackDamageAdaptationEnabled ? "ENABLED" : "DISABLED") + "\n\n" + $"Steps done: total={SgdDecisionRuntimeState.TotalStepsDone}, HP={SgdDecisionRuntimeState.MaxHealthStepsDone}, MS={SgdDecisionRuntimeState.MoveSpeedStepsDone}, AS={SgdDecisionRuntimeState.AttackSpeedStepsDone}, DMG={SgdDecisionRuntimeState.AttackDamageStepsDone}\n\n" + "Axis telemetry (last step):\nHP (MaxHealth):\n" + $" Multiplier: {SgdDecisionRuntimeState.MaxHealthMultiplierLast:F2}\n" + $" Skill: {SgdDecisionRuntimeState.MaxHealthSkill01Last:F2}, Challenge: {SgdDecisionRuntimeState.MaxHealthChallenge01Last:F2}, Error: {SgdDecisionRuntimeState.MaxHealthErrorLast:F2}\n" + $" Gradient: {SgdDecisionRuntimeState.MaxHealthGradientLast:F3}, Δθ: {SgdDecisionRuntimeState.MaxHealthDeltaThetaLast:F4}\n\n" + "MS (MoveSpeed):\n" + $" Multiplier: {SgdDecisionRuntimeState.MoveSpeedMultiplierLast:F2}\n" + $" Skill: {SgdDecisionRuntimeState.MoveSpeedSkill01Last:F2}, Challenge: {SgdDecisionRuntimeState.MoveSpeedChallenge01Last:F2}, Error: {SgdDecisionRuntimeState.MoveSpeedErrorLast:F2}\n" + $" Gradient: {SgdDecisionRuntimeState.MoveSpeedGradientLast:F3}, Δθ: {SgdDecisionRuntimeState.MoveSpeedDeltaThetaLast:F4}\n\n" + "AS (AttackSpeed):\n" + $" Multiplier: {SgdDecisionRuntimeState.AttackSpeedMultiplierLast:F2}\n" + $" Skill: {SgdDecisionRuntimeState.AttackSpeedSkill01Last:F2}, Challenge: {SgdDecisionRuntimeState.AttackSpeedChallenge01Last:F2}, Error: {SgdDecisionRuntimeState.AttackSpeedErrorLast:F2}\n" + $" Gradient: {SgdDecisionRuntimeState.AttackSpeedGradientLast:F3}, Δθ: {SgdDecisionRuntimeState.AttackSpeedDeltaThetaLast:F4}\n\n" + "DMG (AttackDamage):\n" + $" Multiplier: {SgdDecisionRuntimeState.AttackDamageMultiplierLast:F2}\n" + $" Skill: {SgdDecisionRuntimeState.AttackDamageSkill01Last:F2}, Challenge: {SgdDecisionRuntimeState.AttackDamageChallenge01Last:F2}, Error: {SgdDecisionRuntimeState.AttackDamageErrorLast:F2}\n" + $" Gradient: {SgdDecisionRuntimeState.AttackDamageGradientLast:F3}, Δθ: {SgdDecisionRuntimeState.AttackDamageDeltaThetaLast:F4}\n\n"; string text3; if (SgdSensorsRuntimeState.HasSample) { SgdSensorsSample sample = SgdSensorsRuntimeState.Sample; text3 = "Sensors:\n" + $"IncomingDPS: {sample.IncomingDamageRate:F1} (n={sample.IncomingDamageNorm01:F2})\n" + $"OutgoingDPS: {sample.OutgoingDamageRate:F1} (n={sample.OutgoingDamageNorm01:F2})\n" + $"HitRate: {sample.HitRateOnPlayer:F2}/s (n={sample.HitRateOnPlayerNorm01:F2})\n" + $"CombatUptime: {sample.CombatUptime:P0}\n" + $"LowHPUptime: {sample.LowHealthUptime:P0}\n" + $"Deaths/W: {sample.DeathsPerWindow:F0} (n={sample.DeathsPerWindowNorm01:F2})\n" + $"AvgTTK: {sample.AvgTtkSeconds:F2}s (n={sample.AvgTtkSecondsNorm01:F2})\n\n"; } else { text3 = "Sensors: N/A\n"; } if (SgdRuntimeState.HasVirtualPower) { SgdVirtualPowerSample virtualPower = SgdRuntimeState.VirtualPower; _textComponent.text = "[DDA Debug]\n" + $"Time: {Time.time:F1}s\n" + $"Algorithm: {DdaAlgorithmState.ActiveAlgorithm}\n" + "Body: " + SgdRuntimeState.VirtualPowerBodyName + "\n" + $"V_p.hp: {virtualPower.Hp:F3}\n" + $"V_p.moveSpeed: {virtualPower.MoveSpeed:F3}\n" + $"V_p.attackSpeed: {virtualPower.AttackSpeed:F3}\n" + $"V_p.attackDamage: {virtualPower.AttackDamage:F3}\n" + $"V_p.total: {virtualPower.Total:F3}\n\n" + text + "\n" + text2 + "\n" + text3; } else { _textComponent.text = "[DDA Debug]\n" + $"Time: {Time.time:F1}s\n" + $"Algorithm: {DdaAlgorithmState.ActiveAlgorithm}\n" + "V_p: N/A (enable SGD or start a run)\n\n" + text + "\n" + text2 + "\n" + text3; } } } } public sealed class MonsterHpOverheadDriver : MonoBehaviour { private sealed class HpLabel : MonoBehaviour { private const float BaseHeightOffset = 0.8f; private const float CharacterSize = 0.08f; private TextMesh _text; public CharacterBody Body { get; set; } public void Initialize(CharacterBody body) { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) Body = body; _text = ((Component)this).gameObject.AddComponent(); _text.anchor = (TextAnchor)4; _text.alignment = (TextAlignment)1; _text.fontSize = 48; _text.characterSize = 0.08f; _text.color = Color32.op_Implicit(new Color32((byte)0, byte.MaxValue, (byte)0, byte.MaxValue)); _text.richText = false; RefreshText(); } public void RefreshText() { if ((Object)(object)_text == (Object)null) { return; } if ((Object)(object)Body == (Object)null || (Object)(object)Body.healthComponent == (Object)null) { _text.text = ""; return; } float num = Body.healthComponent.combinedHealth; float num2 = Body.healthComponent.fullCombinedHealth; if (float.IsNaN(num) || float.IsInfinity(num) || num < 0f) { num = 0f; } if (float.IsNaN(num2) || float.IsInfinity(num2) || num2 <= 0f) { num2 = 0f; } int num3 = Mathf.CeilToInt(num); int num4 = Mathf.CeilToInt(num2); _text.text = ((num4 > 0) ? $"{num3}/{num4}" : $"{num3}"); } public void RefreshTransform(Camera cam) { //IL_001c: 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_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Body == (Object)null) { return; } Transform transform = ((Component)this).transform; Vector3 corePosition = Body.corePosition; float num = 0.8f + Mathf.Max(0.2f, Body.radius); transform.position = corePosition + Vector3.up * num; if ((Object)(object)cam != (Object)null) { Vector3 val = ((Component)cam).transform.position - transform.position; if (((Vector3)(ref val)).sqrMagnitude > 0.0001f) { transform.rotation = Quaternion.LookRotation(-val); } } } } private const float ScanIntervalSeconds = 0.5f; private const float TextUpdateIntervalSeconds = 0.2f; private static MonsterHpOverheadDriver _instance; private readonly Dictionary _labelsByBodyId = new Dictionary(256); private float _nextScanTime; private float _nextTextUpdateTime; private Camera _camera; public static bool IsEnabled { get; private set; } public static void SetEnabled(bool enabled) { IsEnabled = enabled; if (enabled) { EnsureInstance(); if ((Object)(object)_instance != (Object)null) { ((Behaviour)_instance).enabled = true; } } else if ((Object)(object)_instance != (Object)null) { _instance.ClearAll(); ((Behaviour)_instance).enabled = false; } } private static void EnsureInstance() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown if (!((Object)(object)_instance != (Object)null)) { GameObject val = new GameObject("DdaMonsterHpOverhead"); Object.DontDestroyOnLoad((Object)val); _instance = val.AddComponent(); } } private void Awake() { if ((Object)(object)_instance != (Object)null && (Object)(object)_instance != (Object)(object)this) { Object.Destroy((Object)(object)((Component)this).gameObject); return; } _instance = this; Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject); } private void OnDestroy() { if ((Object)(object)_instance == (Object)(object)this) { _instance = null; } } private void Update() { if (IsEnabled) { if ((Object)(object)_camera == (Object)null) { _camera = Camera.main; } float time = Time.time; if (time >= _nextScanTime) { _nextScanTime = time + 0.5f; ResyncBodies(); } if (time >= _nextTextUpdateTime) { _nextTextUpdateTime = time + 0.2f; UpdateAllTexts(); } UpdateAllTransforms(); } } private void ResyncBodies() { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Invalid comparison between Unknown and I4 HashSet hashSet = new HashSet(); foreach (CharacterBody readOnlyInstances in CharacterBody.readOnlyInstancesList) { if ((Object)(object)readOnlyInstances == (Object)null || (Object)(object)readOnlyInstances.teamComponent == (Object)null || (int)readOnlyInstances.teamComponent.teamIndex != 2 || (Object)(object)readOnlyInstances.healthComponent == (Object)null) { continue; } int num = (((Object)(object)((Component)readOnlyInstances).gameObject != (Object)null) ? ((Object)((Component)readOnlyInstances).gameObject).GetInstanceID() : 0); if (num != 0) { hashSet.Add(num); if (!_labelsByBodyId.TryGetValue(num, out var value) || (Object)(object)value == (Object)null) { _labelsByBodyId[num] = CreateLabel(readOnlyInstances); } else { value.Body = readOnlyInstances; } } } if (_labelsByBodyId.Count == 0) { return; } List list = new List(); foreach (KeyValuePair item in _labelsByBodyId) { if (!hashSet.Contains(item.Key) || (Object)(object)item.Value == (Object)null || (Object)(object)item.Value.Body == (Object)null) { list.Add(item.Key); } } for (int i = 0; i < list.Count; i++) { RemoveLabel(list[i]); } } private void UpdateAllTexts() { foreach (KeyValuePair item in _labelsByBodyId) { HpLabel value = item.Value; if (!((Object)(object)value == (Object)null)) { value.RefreshText(); } } } private void UpdateAllTransforms() { foreach (KeyValuePair item in _labelsByBodyId) { HpLabel value = item.Value; if (!((Object)(object)value == (Object)null)) { value.RefreshTransform(_camera); } } } private HpLabel CreateLabel(CharacterBody body) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) HpLabel hpLabel = new GameObject("DdaMonsterHpLabel").AddComponent(); hpLabel.Initialize(body); return hpLabel; } private void RemoveLabel(int bodyId) { if (_labelsByBodyId.TryGetValue(bodyId, out var value) && (Object)(object)value != (Object)null) { Object.Destroy((Object)(object)((Component)value).gameObject); } _labelsByBodyId.Remove(bodyId); } private void ClearAll() { foreach (KeyValuePair item in _labelsByBodyId) { if ((Object)(object)item.Value != (Object)null) { Object.Destroy((Object)(object)((Component)item.Value).gameObject); } } _labelsByBodyId.Clear(); } } public sealed class TelemetryDebugOverlayBehaviour : MonoBehaviour { private static TelemetryDebugOverlayBehaviour _instance; private static GameObject _overlayRoot; private static Text _textComponent; private static float _updateTimer; public static void UpdateVisibility() { if (DdaAlgorithmState.IsTelemetryOverlayEnabled) { EnsureOverlayExists(); if ((Object)(object)_instance != (Object)null) { ((Component)_instance).gameObject.SetActive(true); } } else if ((Object)(object)_instance != (Object)null) { ((Component)_instance).gameObject.SetActive(false); } } private static Font GetFontForOverlay() { Font builtinResource = Resources.GetBuiltinResource("Arial.ttf"); if ((Object)(object)builtinResource != (Object)null) { return builtinResource; } return Font.CreateDynamicFontFromOSFont("Arial", 14); } private static void EnsureOverlayExists() { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Expected O, but got Unknown //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_overlayRoot != (Object)null) { MakeOverlayClickThrough(_overlayRoot); if ((Object)(object)_textComponent != (Object)null) { ApplyTextStyle(_textComponent); ((Graphic)_textComponent).raycastTarget = false; } return; } _overlayRoot = new GameObject("DdaTelemetryOverlay"); Object.DontDestroyOnLoad((Object)(object)_overlayRoot); Canvas obj = _overlayRoot.AddComponent(); obj.renderMode = (RenderMode)0; obj.sortingOrder = 1001; _overlayRoot.AddComponent().uiScaleMode = (ScaleMode)1; MakeOverlayClickThrough(_overlayRoot); GameObject val = new GameObject("TelemetryText"); val.transform.SetParent(_overlayRoot.transform, false); _textComponent = val.AddComponent(); _textComponent.font = GetFontForOverlay(); ApplyTextStyle(_textComponent); ((Graphic)_textComponent).raycastTarget = false; RectTransform rectTransform = ((Graphic)_textComponent).rectTransform; rectTransform.anchorMin = new Vector2(0.02f, 0.02f); rectTransform.anchorMax = new Vector2(0.98f, 0.02f); rectTransform.pivot = new Vector2(0.5f, 0f); rectTransform.sizeDelta = new Vector2(-40f, 560f); rectTransform.anchoredPosition = Vector2.zero; _instance = _overlayRoot.AddComponent(); } private static void ApplyTextStyle(Text text) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)text == (Object)null)) { text.fontSize = 9; ((Graphic)text).color = new Color(0.9f, 0.9f, 1f, 1f); text.alignment = (TextAnchor)6; text.horizontalOverflow = (HorizontalWrapMode)0; text.verticalOverflow = (VerticalWrapMode)1; Outline obj = ((Component)text).GetComponent() ?? ((Component)text).gameObject.AddComponent(); ((Shadow)obj).effectColor = new Color(0f, 0f, 0f, 0.75f); ((Shadow)obj).effectDistance = new Vector2(1f, -1f); ((Shadow)obj).useGraphicAlpha = true; } } private static void MakeOverlayClickThrough(GameObject overlayRoot) { if (!((Object)(object)overlayRoot == (Object)null)) { GraphicRaycaster component = overlayRoot.GetComponent(); if ((Object)(object)component != (Object)null) { ((Behaviour)component).enabled = false; } CanvasGroup obj = overlayRoot.GetComponent() ?? overlayRoot.AddComponent(); obj.interactable = false; obj.blocksRaycasts = false; obj.ignoreParentGroups = true; } } private void Update() { if (!DdaAlgorithmState.IsTelemetryOverlayEnabled || (Object)(object)_textComponent == (Object)null) { return; } _updateTimer += Time.deltaTime; if (!(_updateTimer < 0.5f)) { _updateTimer = 0f; TelemetryEvent telemetryEvent = TelemetryEventQueue.LastEnqueuedSample ?? TelemetryEventQueue.LastEnqueuedEvent; if (telemetryEvent == null) { _textComponent.text = "[Telemetry Debug]\n" + $"Time: {Time.time:F1}s\n" + $"Algorithm: {DdaAlgorithmState.ActiveAlgorithm}\n" + "Last event: N/A (no telemetry enqueued yet)\n"; return; } Dictionary p = telemetryEvent.Properties ?? new Dictionary(); string @string = GetString(p, "session_id"); string string2 = GetString(p, "dda_mode"); float @float = GetFloat(p, "run_elapsed_seconds"); int num = (int)GetFloat(p, "queue_count"); float float2 = GetFloat(p, "sample_interval_seconds"); StringBuilder stringBuilder = new StringBuilder(2048); stringBuilder.AppendLine("[Telemetry Debug]"); stringBuilder.AppendLine($"Time: {Time.time:F1}s"); stringBuilder.AppendLine($"Algorithm: {DdaAlgorithmState.ActiveAlgorithm} (telemetry dda_mode={string2})"); stringBuilder.AppendLine($"Last enqueued: {telemetryEvent.EventName} @ {telemetryEvent.TimestampUtc:O}"); stringBuilder.AppendLine("Session: " + @string); stringBuilder.AppendLine($"Run elapsed: {@float:F1}s SampleInterval: {float2:F1}s Queue: {num}"); stringBuilder.AppendLine(); AppendAxis(stringBuilder, p, "max_health", "HP (MaxHealth)"); AppendAxis(stringBuilder, p, "move_speed", "MS (MoveSpeed)"); AppendAxis(stringBuilder, p, "attack_speed", "AS (AttackSpeed)"); AppendAxis(stringBuilder, p, "attack_damage", "DMG (AttackDamage)"); stringBuilder.AppendLine(); stringBuilder.AppendLine(string.Format("Degradation: is_degraded={0} signal={1:F3}", GetBool(p, "is_degraded"), GetFloat(p, "degradation_signal"))); stringBuilder.AppendLine(string.Format("Virtual total: Vp={0:F3} Vc={1:F3} gap={2:F3}", GetFloat(p, "virtual_power_total"), GetFloat(p, "virtual_challenge_total"), GetFloat(p, "virtual_gap_abs"))); stringBuilder.AppendLine(string.Format("Virtual axes gap: hp={0:F3} ms={1:F3} as={2:F3} dmg={3:F3}", GetFloat(p, "virtual_gap_hp_abs"), GetFloat(p, "virtual_gap_move_speed_abs"), GetFloat(p, "virtual_gap_attack_speed_abs"), GetFloat(p, "virtual_gap_attack_damage_abs"))); _textComponent.text = stringBuilder.ToString(); } } private static void AppendAxis(StringBuilder sb, Dictionary p, string axis, string label) { string text = "axis_" + axis + "_"; float @float = GetFloat(p, text + "multiplier"); float float2 = GetFloat(p, text + "previous_multiplier"); float float3 = GetFloat(p, text + "delta_multiplier"); bool @bool = GetBool(p, text + "is_jump"); float float4 = GetFloat(p, text + "skill01"); float float5 = GetFloat(p, text + "challenge01"); float float6 = GetFloat(p, text + "error"); float float7 = GetFloat(p, text + "abs_error"); sb.AppendLine(label + ":"); sb.AppendLine($" Mult: {@float:F3} (prev {float2:F3}) Δmult: {float3:F3} jump={@bool}"); sb.AppendLine($" Skill: {float4:F3} Challenge: {float5:F3} Error: {float6:F3} |err|: {float7:F3}"); } private static string GetString(Dictionary p, string key) { if (p == null || string.IsNullOrEmpty(key)) { return ""; } if (!p.TryGetValue(key, out var value) || value == null) { return ""; } return Convert.ToString(value) ?? ""; } private static float GetFloat(Dictionary p, string key) { if (p == null || string.IsNullOrEmpty(key)) { return 0f; } if (!p.TryGetValue(key, out var value) || value == null) { return 0f; } try { return Convert.ToSingle(value); } catch { return 0f; } } private static bool GetBool(Dictionary p, string key) { if (p == null || string.IsNullOrEmpty(key)) { return false; } if (!p.TryGetValue(key, out var value) || value == null) { return false; } try { return Convert.ToBoolean(value); } catch { return false; } } } }