diff --git a/src/InfiniteTool/App.xaml.cs b/src/InfiniteTool/App.xaml.cs index 95da864..c85dd4d 100644 --- a/src/InfiniteTool/App.xaml.cs +++ b/src/InfiniteTool/App.xaml.cs @@ -9,6 +9,7 @@ using System.ComponentModel; using System.Diagnostics; using System.IO; +using System.Reflection; using System.Text; using System.Threading.Tasks; using System.Windows; @@ -22,10 +23,12 @@ public partial class App : Application { private IHost _host; + public static string LogLocation = Path.Combine(Environment.CurrentDirectory, "log.txt"); + public App() { var serilogLogger = new LoggerConfiguration() - .WriteTo.File("log.txt") + .WriteTo.File(LogLocation) .CreateLogger(); AppDomain.CurrentDomain.FirstChanceException += (s, e) => @@ -35,6 +38,9 @@ public App() Console.SetOut(new TextWriterLogger(serilogLogger)); + serilogLogger.Information("AppInfo: " + Assembly.GetExecutingAssembly().ToString()); + + _host = Host.CreateDefaultBuilder() .ConfigureServices(services => { diff --git a/src/InfiniteTool/Data/6.10021.10921.0/lightskip.infprog b/src/InfiniteTool/Data/6.10021.10921.0/lightskip.infprog new file mode 100644 index 0000000..bbd2ce9 --- /dev/null +++ b/src/InfiniteTool/Data/6.10021.10921.0/lightskip.infprog @@ -0,0 +1,939 @@ +InfiniteProgressV1 +ParticipantID:0xEC63 +KeyName,DataType,GlobalValue,ParticipantValue +schematic_evade,Boolean,0x0,0x0 +schematic_wall,Boolean,0x0,0x0 +schematic_sensor,Boolean,0x0,0x0 +Schematic-ShieldUpdgrade1,Boolean,0x0,0x0 +Schematic-ShieldUpdgrade2,Boolean,0x0,0x0 +Schematic-ShieldUpdgrade3,Boolean,0x0,0x0 +poi_base_intro_green,Byte,0x0,0x0 +poi_fob_ash,Byte,0x0,0x0 +poi_fob_aspen,Byte,0x0,0x0 +poi_fob_birch,Byte,0x0,0x0 +poi_fob_cedar,Byte,0x0,0x0 +poi_fob_cherry,Byte,0x0,0x0 +poi_fob_dogwood,Byte,0x0,0x0 +poi_fob_elm,Byte,0x0,0x0 +poi_fob_magnolia,Byte,0x0,0x0 +poi_fob_maple,Byte,0x0,0x0 +poi_fob_oak,Byte,0x0,0x0 +poi_fob_palm,Byte,0x0,0x0 +poi_fob_pecan,Byte,0x0,0x0 +poi_fob_pine,Byte,0x0,0x0 +poi_fob_redwood,Byte,0x0,0x0 +poi_fob_sequoia,Byte,0x0,0x0 +poi_fob_spruce,Byte,0x0,0x0 +poi_fob_willow,Byte,0x0,0x0 +poi_outpost_baboon,Byte,0x0,0x0 +poi_outpost_gibbon,Byte,0x0,0x0 +poi_outpost_howler,Byte,0x0,0x0 +poi_outpost_marmoset,Byte,0x0,0x0 +poi_outpost_silverback,Byte,0x0,0x0 +poi_outpost_mandrill,Byte,0x0,0x0 +poi_outpost_bonobo,Byte,0x0,0x0 +poi_unsc_alpha,Byte,0x0,0x0 +poi_unsc_bravo,Byte,0x0,0x0 +poi_unsc_charlie,Byte,0x0,0x0 +poi_unsc_delta,Byte,0x0,0x0 +poi_unsc_echo,Byte,0x0,0x0 +poi_unsc_foxtrot,Byte,0x0,0x0 +poi_unsc_golf,Byte,0x0,0x0 +poi_unsc_hotel,Byte,0x0,0x0 +poi_unsc_india,Byte,0x0,0x0 +poi_unsc_juliet,Byte,0x0,0x0 +poi_unsc_kilo,Byte,0x0,0x0 +poi_unsc_lima,Byte,0x0,0x0 +poi_unsc_mike,Byte,0x0,0x0 +poi_unsc_november,Byte,0x0,0x0 +poi_unsc_oscar,Byte,0x0,0x0 +poi_unsc_papa,Byte,0x0,0x0 +poi_unsc_quebec,Byte,0x0,0x0 +poi_unsc_romeo,Byte,0x0,0x0 +poi_unsc_sierra,Byte,0x0,0x0 +poi_unsc_tango,Byte,0x0,0x0 +poi_boss_aluminum,Byte,0x0,0x0 +poi_boss_beryllium,Byte,0x0,0x0 +poi_boss_cesium,Byte,0x0,0x0 +poi_boss_dubnium,Byte,0x0,0x0 +poi_boss_einsteinium,Byte,0x0,0x0 +poi_boss_fermium,Byte,0x0,0x0 +poi_boss_gallium,Byte,0x0,0x0 +poi_boss_helium,Byte,0x0,0x0 +poi_boss_iridium,Byte,0x0,0x0 +poi_boss_lithium,Byte,0x0,0x0 +poi_boss_magnesium,Byte,0x0,0x0 +poi_boss_nobelium,Byte,0x0,0x0 +poi_boss_osmium,Byte,0x0,0x0 +poi_boss_plutonium,Byte,0x0,0x0 +poi_boss_radium,Byte,0x0,0x0 +poi_bridge_nail,Byte,0x0,0x0 +poi_bridge_staple,Byte,0x0,0x0 +poi_bridge_screw,Byte,0x0,0x0 +poi_bridge_periwinkle,Byte,0x0,0x0 +poi_green_pilot_base,Byte,0x0,0x0 +poi_green_refinery,Byte,0x0,0x0 +poi_green_prison_island,Byte,0x0,0x0 +poi_green_prison,Byte,0x0,0x0 +poi_green_spire,Byte,0x0,0x0 +poi_yellow_spire,Byte,0x0,0x0 +poi_boss_hq_exterior,Byte,0x0,0x0 +poi_boss_hq_interior,Byte,0x0,0x0 +poi_forerunner_tower_main_mission,Byte,0x0,0x0 +poi_forerunner_north,Byte,0x0,0x0 +poi_forerunner_south,Byte,0x0,0x0 +poi_forerunner_east,Byte,0x0,0x0 +poi_forerunner_west,Byte,0x0,0x0 +poi_forerunner_dallas,Byte,0x0,0x0 +poi_forerunner_houston,Byte,0x0,0x0 +poi_forerunner_austin,Byte,0x0,0x0 +poi_cortana_palace,Byte,0x0,0x0 +poi_scanner_afador,Byte,0x0,0x0 +poi_scanner_akbash,Byte,0x0,0x0 +poi_scanner_akita,Byte,0x0,0x0 +poi_scanner_auggie,Byte,0x0,0x0 +poi_scanner_barbet,Byte,0x0,0x0 +poi_scanner_bassador,Byte,0x0,0x0 +poi_scanner_beagle,Byte,0x0,0x0 +poi_scanner_borador,Byte,0x0,0x0 +poi_scanner_boxer,Byte,0x0,0x0 +poi_scanner_bulldog,Byte,0x0,0x0 +poi_scanner_cavador,Byte,0x0,0x0 +poi_scanner_chihuahua,Byte,0x0,0x0 +poi_scanner_collie,Byte,0x0,0x0 +poi_scanner_corgi,Byte,0x0,0x0 +poi_scanner_dachshund,Byte,0x0,0x0 +poi_scanner_dalmatian,Byte,0x0,0x0 +poi_scanner_eurasier,Byte,0x0,0x0 +poi_scanner_frenchie,Byte,0x0,0x0 +poi_scanner_germanshepherd,Byte,0x0,0x0 +poi_scanner_goldenretriever,Byte,0x0,0x0 +poi_scanner_goldendoodle,Byte,0x0,0x0 +poi_scanner_greatdane,Byte,0x0,0x0 +poi_scanner_greyhound,Byte,0x0,0x0 +poi_scanner_harrier,Byte,0x0,0x0 +poi_scanner_havanese,Byte,0x0,0x0 +poi_scanner_horgi,Byte,0x0,0x0 +poi_scanner_husky,Byte,0x0,0x0 +poi_scanner_jackrussell,Byte,0x0,0x0 +poi_scanner_komondor,Byte,0x0,0x0 +poi_scanner_labrador,Byte,0x0,0x0 +poi_scanner_mastiff,Byte,0x0,0x0 +poi_scanner_newfoundland,Byte,0x0,0x0 +poi_scanner_otterhound,Byte,0x0,0x0 +poi_scanner_peekapoo,Byte,0x0,0x0 +poi_scanner_pitbull,Byte,0x0,0x0 +poi_scanner_poodle,Byte,0x0,0x0 +poi_scanner_pug,Byte,0x0,0x0 +poi_scanner_rottweiler,Byte,0x0,0x0 +poi_scanner_shihtzu,Byte,0x0,0x0 +poi_scanner_shibainu,Byte,0x0,0x0 +Dungeon-Underbelly,Byte,0x0,0x0 +Dungeon-BanishedShip,Byte,0x3,0x3 +dungeon_SeedLost,Byte,0x0,0x0 +marmoset_AmmoDump01,Byte,0x0,0x0 +marmoset_AmmoDump02,Byte,0x0,0x0 +marmoset_AmmoDump03,Byte,0x0,0x0 +exampleobjective_01,Byte,0x0,0x0 +exampleobjective_02,Byte,0x0,0x0 +exampleobjective_03,Byte,0x0,0x0 +exampleobjective_04,Byte,0x0,0x0 +exampleobjective_05,Byte,0x0,0x0 +howler_FreeMarines,Byte,0x0,0x0 +howler_FreeMarine01,Byte,0x0,0x0 +howler_FreeMarine02,Byte,0x0,0x0 +howler_FreeMarine03,Byte,0x0,0x0 +howler_FreeVIP,Byte,0x0,0x0 +silverback_Investigate,Byte,0x0,0x0 +silverback_DestroySilos,Byte,0x0,0x0 +silverback_DestroyRepairBays,Byte,0x0,0x0 +silverback_Silo01,Byte,0x0,0x0 +silverback_Silo02,Byte,0x0,0x0 +silverback_Silo03,Byte,0x0,0x0 +silverback_Silo04,Byte,0x0,0x0 +silverback_RepairBay01,Byte,0x0,0x0 +silverback_RepairBay02,Byte,0x0,0x0 +green_spire_enter,Byte,0x0,0x0 +green_spire_hunters,Byte,0x0,0x0 +green_spire_investigate,Byte,0x0,0x0 +green_spire_follow_monitor,Byte,0x0,0x0 +green_spire_deploy_weapon,Byte,0x0,0x0 +green_spire_shutdown,Byte,0x0,0x0 +green_spire_defeat_boss,Byte,0x0,0x0 +green_spire_observation_room_terminal,Byte,0x0,0x0 +green_spire_observation_room_door,Byte,0x0,0x0 +green_spire_elevator_started,Byte,0x0,0x0 +yellow_spire_goto_top,Byte,0x0,0x0 +yellow_spire_shutdown,Byte,0x0,0x0 +yellow_spire_enter,Byte,0x0,0x0 +yellow_spire_collector_room_terminal,Byte,0x0,0x0 +yellow_spire_girders_socket,Byte,0x0,0x0 +yellow_spire_observation_terminal,Byte,0x0,0x0 +yellow_spire_boss_terminal,Byte,0x0,0x0 +gibbon_DestroySilos,Byte,0x0,0x0 +gibbon_DestroyRepairBays,Byte,0x0,0x0 +gibbon_Silo01,Byte,0x0,0x0 +gibbon_Silo02,Byte,0x0,0x0 +gibbon_Silo03,Byte,0x0,0x0 +gibbon_Silo04,Byte,0x0,0x0 +gibbon_Silo05,Byte,0x0,0x0 +gibbon_RepairBay01,Byte,0x0,0x0 +gibbon_RepairBay02,Byte,0x0,0x0 +gibbon_RepairBay03,Byte,0x0,0x0 +gibbon_RepairBay04,Byte,0x0,0x0 +mandrill_Investigate,Byte,0x0,0x0 +mandrill_DisableCrane,Byte,0x0,0x0 +mandrill_TransportDestroy,Byte,0x0,0x0 +mandrill_RaiseSilos,Byte,0x0,0x0 +mandrill_Silo01,Byte,0x0,0x0 +bonobo_ClearPath,Byte,0x0,0x0 +bonobo_Gate01,Byte,0x0,0x0 +bonobo_Gate02,Byte,0x0,0x0 +bonobo_Gate03,Byte,0x0,0x0 +bonobo_switch_hack,Byte,0x0,0x0 +bonobo_destroy_power,Byte,0x0,0x0 +alpha_kill,Byte,0x0,0x0 +bravo_kill,Byte,0x0,0x0 +charlie_kill,Byte,0x0,0x0 +delta_kill,Byte,0x0,0x0 +echo_kill,Byte,0x0,0x0 +foxtrot_kill,Byte,0x0,0x0 +golf_kill,Byte,0x0,0x0 +hotel_kill,Byte,0x0,0x0 +india_kill,Byte,0x0,0x0 +juliet_kill,Byte,0x0,0x0 +kilo_kill,Byte,0x0,0x0 +lima_kill,Byte,0x0,0x0 +mike_kill,Byte,0x0,0x0 +november_kill,Byte,0x0,0x0 +oscar_kill,Byte,0x0,0x0 +papa_kill,Byte,0x0,0x0 +quebec_kill,Byte,0x0,0x0 +romeo_kill,Byte,0x0,0x0 +sierra_kill,Byte,0x0,0x0 +tango_kill,Byte,0x0,0x0 +aluminum_kill,Byte,0x0,0x0 +beryllium_kill,Byte,0x0,0x0 +cesium_kill,Byte,0x0,0x0 +dubnium_kill,Byte,0x0,0x0 +einsteinium_kill,Byte,0x0,0x0 +fermium_kill,Byte,0x0,0x0 +gallium_kill,Byte,0x0,0x0 +helium_kill,Byte,0x0,0x0 +iridium_kill,Byte,0x0,0x0 +lithium_kill,Byte,0x0,0x0 +magnesium_kill,Byte,0x0,0x0 +nobelium_kill,Byte,0x0,0x0 +osmium_kill,Byte,0x0,0x0 +plutonium_kill,Byte,0x0,0x0 +radium_kill,Byte,0x0,0x0 +pilotbase_cylix_seen,Boolean,0x0,0x0 +pilotbase_reunite,Byte,0x0,0x0 +pilotbase_gantry,Byte,0x0,0x0 +pilotbase_terminal,Byte,0x0,0x0 +pilotbase_murdergate,Byte,0x0,0x0 +pilotbase_dock_terminal,Byte,0x0,0x0 +pilotbase_dock_pelican,Byte,0x0,0x0 +pilotbase_game_finished_vo,Boolean,0x0,0x0 +pris_island_complete_prison,Byte,0x0,0x0 +pris_island_complete_fob,Byte,0x0,0x0 +pris_investigate,Byte,0x0,0x0 +pris_locate_signal_1,Byte,0x0,0x0 +pris_enter_prison,Byte,0x0,0x0 +pris_end_lockdown,Byte,0x0,0x0 +pris_power_gravlift,Byte,0x0,0x0 +pris_fight_reinforcements,Byte,0x0,0x0 +pris_loc_sensor,Byte,0x0,0x0 +pris_locate_signal_2,Byte,0x0,0x0 +pris_rescue_spartan,Byte,0x0,0x0 +pris_defeat_chak_lok,Byte,0x0,0x0 +prison_bridge,Byte,0x0,0x0 +banishedship_DeactivateCannon,Byte,0x3,0x3 +banishedship_LocateBridge,Byte,0x3,0x3 +banishedship_ScupperShip,Byte,0x0,0x0 +banishedship_DestroyManifold_01,Byte,0x0,0x0 +banishedship_DestroyManifold_02,Byte,0x0,0x0 +banishedship_OverloadEngines,Byte,0x0,0x0 +banishedship_EscapeToPelican,Byte,0x0,0x0 +banishedship_GrappleToPelican,Byte,0x0,0x0 +banishedship_OverrideEngines,Byte,0x0,0x0 +banishedship_PingTutorial,Boolean,0x1,0x1 +banishedship_GrappleTutorial,Boolean,0x0,0x0 +banishedship_ArmoryTwoDirectivesCompleted,Boolean,0x0,0x0 +banishedship_BridgeKilledAllEnemies,Boolean,0x0,0x0 +underbelly_locate_weapon,Byte,0x0,0x0 +underbelly_get_index,Byte,0x0,0x0 +underbelly_reach_surface,Byte,0x0,0x0 +underbelly_investigate_dead_spartan_stone,Byte,0x0,0x0 +underbelly_temple_socket,Byte,0x0,0x0 +underbelly_temple_terminal,Byte,0x0,0x0 +underbelly_defeat_tremonious,Byte,0x0,0x0 +underbelly_index_terminal,Byte,0x0,0x0 +underbelly_defend_middle_terminal,Byte,0x0,0x0 +underbelly_grav_lift_socket,Byte,0x0,0x0 +underbelly_temple_bloodgate_and_terminal,Byte,0x0,0x0 +underbelly_temple_socket_waypoint,Byte,0x0,0x0 +underbelly_temple_cradle_waypoint,Byte,0x0,0x0 +underbelly_campfire_cathedral,Byte,0x0,0x0 +underbelly_campfire_cortana_exit,Byte,0x0,0x0 +underbelly_campfire_temple,Byte,0x0,0x0 +refine_goto_refinery,Byte,0x0,0x0 +refine_find,Byte,0x0,0x0 +refine_descend,Byte,0x0,0x0 +refine_disable_laser,Byte,0x0,0x0 +refine_overload_regs,Byte,0x0,0x0 +refine_interact_regulator_1,Byte,0x0,0x0 +refine_disable_regulator_1,Byte,0x0,0x0 +refine_disable_cooling_pylons_1_1,Byte,0x0,0x0 +refine_disable_cooling_pylons_1_2,Byte,0x0,0x0 +refine_interact_regulator_2,Byte,0x0,0x0 +refine_disable_regulator_2,Byte,0x0,0x0 +refine_disable_cooling_pylons_2_1,Byte,0x0,0x0 +refine_disable_cooling_pylons_2_2,Byte,0x0,0x0 +refine_com_room_return,Byte,0x0,0x0 +refine_disable_laser2,Byte,0x0,0x0 +refine_defeat_bassman,Byte,0x0,0x0 +refine_goto_laser_hole,Byte,0x0,0x0 +refine_goto_dungeon,Byte,0x0,0x0 +poi_base_aa_island,Byte,0x0,0x0 +aa_island_gun_east,Byte,0x0,0x0 +aa_island_gun_east_icon,Byte,0x0,0x0 +aa_island_gun_north,Byte,0x0,0x0 +aa_island_gun_north_icon,Byte,0x0,0x0 +aa_island_gun_west,Byte,0x0,0x0 +aa_island_gun_west_icon,Byte,0x0,0x0 +aa_island_return_pelican,Byte,0x0,0x0 +aa_island_defeat_spartan_killers,Byte,0x0,0x0 +aa_island_locate_pilot,Byte,0x0,0x0 +boss_hq_exterior_extend_bridge,Byte,0x0,0x0 +boss_hq_exterior_exit,Byte,0x0,0x0 +boss_hq_interior_challenge_01,Byte,0x0,0x0 +boss_hq_interior_challenge_02,Byte,0x0,0x0 +boss_hq_interior_reach_03,Byte,0x0,0x0 +boss_hq_interior_spartan_killer,Byte,0x0,0x0 +boss_hq_interior_boss_time,Byte,0x0,0x0 +boss_hq_interior_freedom,Byte,0x0,0x0 +boss_hq_interior_hotdog_01,Byte,0x0,0x0 +boss_hq_interior_hotdog_02,Byte,0x0,0x0 +boss_hq_interior_hotdog_03,Byte,0x0,0x0 +boss_hq_interior_hotdog_04,Byte,0x0,0x0 +boss_hq_interior_challenge_waypoint,Byte,0x0,0x0 +boss_hq_interior_try_free_pilot,Byte,0x0,0x0 +cortana_palace_get_to_boss,Byte,0x0,0x0 +cortana_palace_retrieve_weapon,Byte,0x0,0x0 +cortana_palace_stop_boss,Byte,0x0,0x0 +cortana_palace_escape,Byte,0x0,0x0 +cortana_palace_judgementroom_elevator,Byte,0x0,0x0 +cortana_palace_dropsite_terminal,Byte,0x0,0x0 +cortana_palace_entrancehallsaccess_socket,Byte,0x0,0x0 +cortana_palace_atrium_terminal,Byte,0x0,0x0 +cortana_palace_atrium_exitdoor,Byte,0x0,0x0 +cortana_palace_cortana_room_2_terminal,Byte,0x0,0x0 +cortana_palace_cortana_room_2_cutscene,Byte,0x0,0x0 +cortana_palace_sentinelroom_exitdoor,Byte,0x0,0x0 +cortana_palace_cortana_room_3_elevator,Byte,0x0,0x0 +cortana_palace_judgmentroom_terminal,Byte,0x0,0x0 +poi_fob_aspen_capture,Byte,0x0,0x0 +poi_fob_birch_capture,Byte,0x0,0x0 +poi_fob_cherry_capture,Byte,0x0,0x0 +poi_fob_dogwood_capture,Byte,0x0,0x0 +poi_fob_elm_capture,Byte,0x0,0x0 +poi_fob_maple_capture,Byte,0x0,0x0 +poi_fob_oak_capture,Byte,0x0,0x0 +poi_fob_palm_capture,Byte,0x0,0x0 +poi_fob_pecan_capture,Byte,0x0,0x0 +poi_fob_pine_capture,Byte,0x0,0x0 +poi_fob_redwood_capture,Byte,0x0,0x0 +poi_fob_sequoia_capture,Byte,0x0,0x0 +poi_fob_spruce_capture,Byte,0x0,0x0 +poi_fob_willow_capture,Byte,0x0,0x0 +nar_towers_initialized,Boolean,0x0,0x0 +tower_forerunner_north,Byte,0x0,0x0 +tower_forerunner_south,Byte,0x0,0x0 +tower_forerunner_east,Byte,0x0,0x0 +tower_forerunner_west,Byte,0x0,0x0 +baboon_EndLockdown,Byte,0x0,0x0 +baboon_ExposePanels,Byte,0x0,0x0 +baboon_DestroyGenerators,Byte,0x0,0x0 +baboon_generator01,Byte,0x0,0x0 +baboon_generator02,Byte,0x0,0x0 +baboon_generator03,Byte,0x0,0x0 +baboon_generator04,Byte,0x0,0x0 +baboon_discoveredNarrative,Byte,0x0,0x0 +baboon_lockdownNarrative,Byte,0x0,0x0 +baboon_commsArrayReinforcements,Byte,0x0,0x0 +dallas_digsite_complete,Byte,0x0,0x0 +dallas_investigate_conservatory,Byte,0x0,0x0 +dallas_investigate_dead_spartan_makovich,Byte,0x0,0x0 +dallas_locate_pyre,Byte,0x0,0x0 +dallas_survive_ambush,Byte,0x0,0x0 +dallas_retrieve_weapon,Byte,0x0,0x0 +dallas_investigate_dead_spartan_sorel,Byte,0x0,0x0 +dallas_invisible_guilty_a,Byte,0x0,0x0 +dallas_invisible_guilty_b_01,Byte,0x0,0x0 +dallas_invisible_guilty_b_02,Byte,0x0,0x0 +dallas_invisible_guilty_b_all,Byte,0x0,0x0 +dallas_elbow_one,Byte,0x0,0x0 +dallas_elbow_two,Byte,0x0,0x0 +dallas_invisible_drop_down,Byte,0x0,0x0 +dallas_invisible_drop_fight_done,Byte,0x0,0x0 +dallas_elbow_three,Byte,0x0,0x0 +dallas_elbow_four,Byte,0x0,0x0 +dallas_conservatory_check,Byte,0x0,0x0 +dallas_investigate_cradle,Byte,0x0,0x0 +dallas_call_elevator,Byte,0x0,0x0 +dallas_invisible_control_elevator_ready,Byte,0x0,0x0 +dallas_campfire_observation,Byte,0x0,0x0 +dallas_campfire_dropdown,Byte,0x0,0x0 +dallas_campfire_ribcage,Byte,0x0,0x0 +dallas_elevator_started,Byte,0x0,0x0 +dallas_interior,Byte,0x0,0x0 +houston_find_entrance,Byte,0x0,0x0 +houston_power_gravlift,Byte,0x0,0x0 +houston_nexus_south,Byte,0x0,0x0 +houston_nexus_west,Byte,0x0,0x0 +houston_nexus_north,Byte,0x0,0x0 +houston_nexus_east,Byte,0x0,0x0 +houston_nexus_terminal_entry,Byte,0x0,0x0 +houston_nexus_terminal_end,Byte,0x0,0x0 +houston_piston_terminal,Byte,0x0,0x0 +houston_gondola_terminal,Byte,0x0,0x0 +houston_plaza_terminal,Byte,0x0,0x0 +houston_nexus_west_cradle,Boolean,0x0,0x0 +houston_nexus_north_cradle,Boolean,0x0,0x0 +houston_nexus_east_cradle,Boolean,0x0,0x0 +austin_invisible_index_mirrored_plinth,Byte,0x0,0x0 +austin_rescue_pilot,Byte,0x0,0x0 +austin_escape_dungeon,Byte,0x0,0x0 +austin_activate_lift,Byte,0x0,0x0 +austin_activate_lift01,Byte,0x0,0x0 +austin_activate_lift02,Byte,0x0,0x0 +austin_skull_capacitor,Boolean,0x0,0x0 +austin_find_plinth,Byte,0x0,0x0 +austin_invisible_gravlift_a_plinth,Byte,0x0,0x0 +austin_invisible_chapel_split,Byte,0x0,0x0 +austin_invisible_chapel_east,Byte,0x0,0x0 +austin_invisible_chapel_west,Byte,0x0,0x0 +austin_invisible_chapel_gravlift,Byte,0x0,0x0 +austin_invisible_gravlift_b_plinth,Byte,0x0,0x0 +austin_invisible_final,Byte,0x0,0x0 +austin_invisible_final_second_door,Byte,0x0,0x0 +austin_index_mirrored_plinth_bloodgate,Byte,0x0,0x0 +austin_campfire_canopy_vista,Byte,0x0,0x0 +austin_campfire_chapel_entry,Byte,0x0,0x0 +austin_airlock_entered,Byte,0x0,0x0 +poi_periwinkle,Byte,0x0,0x0 +aa_island_enter_pelican,Byte,0x0,0x0 +periwinkle_houston_arrival,Byte,0x0,0x0 +periwinkle_arrival,Byte,0x0,0x0 +periwinkle_arrival_plinth_nseq_complete,Boolean,0x0,0x0 +periwinkle_spire_key,Byte,0x0,0x0 +periwinkle_houston_waypoints,Byte,0x0,0x0 +periwinkle_houston_return,Byte,0x0,0x0 +fr_main_first_key,Byte,0x0,0x0 +fr_main_all_keys,Byte,0x0,0x0 +fr_main_north_tracker,Byte,0x0,0x0 +fr_main_south_tracker,Byte,0x0,0x0 +fr_main_east_tracker,Byte,0x0,0x0 +fr_main_west_tracker,Byte,0x0,0x0 +fr_north_enter_area,Byte,0x0,0x0 +fr_north_hack_terminal,Byte,0x0,0x0 +fr_north_key_switch,Byte,0x0,0x0 +fr_south_enter_area,Byte,0x0,0x0 +fr_south_hack_terminal,Byte,0x0,0x0 +fr_south_key_switch,Byte,0x0,0x0 +fr_east_enter_area,Byte,0x0,0x0 +fr_east_hack_terminal,Byte,0x0,0x0 +fr_east_key_switch,Byte,0x0,0x0 +fr_west_enter_area,Byte,0x0,0x0 +fr_west_hack_terminal,Byte,0x0,0x0 +fr_west_key_switch,Byte,0x0,0x0 +Loadout-IsValid,Boolean,0x0,0x0 +Loadout-FirstWeaponExists,Boolean,0x0,0x0 +Loadout-FirstWeaponTag,Long,0x0,0x0 +Loadout-FirstWeaponConfigTag,Long,0x0,0x0 +Loadout-FirstWeaponVariant,Long,0x0,0x0 +Loadout-FirstWeaponAmmoLoaded,Long,0x0,0x0 +Loadout-FirstWeaponTotalAmmo,Long,0x0,0x0 +Loadout-FirstWeaponAge,Byte,0x0,0x0 +Loadout-SecondWeaponExists,Boolean,0x0,0x0 +Loadout-SecondWeaponTag,Long,0x0,0x0 +Loadout-SecondWeaponConfigTag,Long,0x0,0x0 +Loadout-SecondWeaponVariant,Long,0x0,0x0 +Loadout-SecondWeaponAmmoLoaded,Long,0x0,0x0 +Loadout-SecondWeaponTotalAmmo,Long,0x0,0x0 +Loadout-SecondWeaponAge,Byte,0x0,0x0 +Loadout-ThirdWeaponExists,Boolean,0x0,0x0 +Loadout-ThirdWeaponTag,Long,0x0,0x0 +Loadout-ThirdWeaponConfigTag,Long,0x0,0x0 +Loadout-ThirdWeaponVariant,Long,0x0,0x0 +Loadout-ThirdWeaponAmmoLoaded,Long,0x0,0x0 +Loadout-ThirdWeaponTotalAmmo,Long,0x0,0x0 +Loadout-ThirdWeaponAge,Byte,0x0,0x0 +Loadout-FourthWeaponExists,Boolean,0x0,0x0 +Loadout-FourthWeaponTag,Long,0x0,0x0 +Loadout-FourthWeaponConfigTag,Long,0x0,0x0 +Loadout-FourthWeaponVariant,Long,0x0,0x0 +Loadout-FourthWeaponAmmoLoaded,Long,0x0,0x0 +Loadout-FourthWeaponTotalAmmo,Long,0x0,0x0 +Loadout-FourthWeaponAge,Byte,0x0,0x0 +Loadout-FirstGrenadeExists,Boolean,0x0,0x0 +Loadout-FirstGrenadeType,Byte,0x0,0x0 +Loadout-FirstGrenadeCount,Byte,0x0,0x0 +Loadout-SecondGrenadeExists,Boolean,0x0,0x0 +Loadout-SecondGrenadeType,Byte,0x0,0x0 +Loadout-SecondGrenadeCount,Byte,0x0,0x0 +Loadout-ThirdGrenadeExists,Boolean,0x0,0x0 +Loadout-ThirdGrenadeType,Byte,0x0,0x0 +Loadout-ThirdGrenadeCount,Byte,0x0,0x0 +Loadout-FourthGrenadeExists,Boolean,0x0,0x0 +Loadout-FourthGrenadeType,Byte,0x0,0x0 +Loadout-FourthGrenadeCount,Byte,0x0,0x0 +Loadout-InputSlotsValid,Boolean,0x0,0x0 +Loadout-FirstInputSlotTag,Long,0x0,0x0 +Loadout-FirstInputSlotEnergy,Byte,0x0,0x0 +Loadout-FirstInputSlotEnergyDelay,Byte,0x0,0x0 +Loadout-SecondInputSlotTag,Long,0x0,0x0 +Loadout-SecondInputSlotEnergy,Byte,0x0,0x0 +Loadout-SecondInputSlotEnergyDelay,Byte,0x0,0x0 +Loadout-ThirdInputSlotTag,Long,0x0,0x0 +Loadout-ThirdInputSlotEnergy,Byte,0x0,0x0 +Loadout-ThirdInputSlotEnergyDelay,Byte,0x0,0x0 +Loadout-SupplyEnergy,Long,0x0,0x0 +tod_current_time,Byte,0x0,0x0 +tod_lock_time,Boolean,0x0,0x0 +nar_ref_extractor_seen,Boolean,0x0,0x0 +nar_ref_antigonum_hologram_seen,Boolean,0x0,0x0 +nar_ref_extractor_console_activated,Boolean,0x0,0x0 +nar_ref_destroyed_pylon_any_base,Boolean,0x0,0x0 +nar_ref_destroyed_all_plyons_any_base,Boolean,0x0,0x0 +nar_ref_venting_reset,Boolean,0x0,0x0 +nar_ref_control_room_console_activated,Boolean,0x0,0x0 +nar_ref_unscevent_capturedmar_first_seen,Boolean,0x0,0x0 +nar_ref_mongoose_first_summon,Boolean,0x0,0x0 +nar_ref_gungoose_first_summon,Boolean,0x0,0x0 +nar_ref_warthog_first_summon,Boolean,0x0,0x0 +nar_ref_rockethog_first_summon,Boolean,0x0,0x0 +nar_ref_rallyhog_first_summon,Boolean,0x0,0x0 +nar_ref_scorpion_first_summon,Boolean,0x0,0x0 +nar_ref_wasp_first_summon,Boolean,0x0,0x0 +FirstVehicleExists,Boolean,0x0,0x0 +FirstVehicleBSP,Long,0x0,0x0 +FirstVehicleTag,Long,0x0,0x0 +FirstVehicleConfigTag,Long,0x0,0x0 +FirstVehicleVariant,Long,0x0,0x0 +FirstVehicleLocationX,Long,0x0,0x0 +FirstVehicleLocationY,Long,0x0,0x0 +FirstVehicleLocationZ,Long,0x0,0x0 +FirstVehicleFacingX,Long,0x0,0x0 +FirstVehicleFacingY,Long,0x0,0x0 +FirstVehicleFacingZ,Long,0x0,0x0 +SecondVehicleExists,Boolean,0x0,0x0 +SecondVehicleBSP,Long,0x0,0x0 +SecondVehicleTag,Long,0x0,0x0 +SecondVehicleConfigTag,Long,0x0,0x0 +SecondVehicleVariant,Long,0x0,0x0 +SecondVehicleLocationX,Long,0x0,0x0 +SecondVehicleLocationY,Long,0x0,0x0 +SecondVehicleLocationZ,Long,0x0,0x0 +SecondVehicleFacingX,Long,0x0,0x0 +SecondVehicleFacingY,Long,0x0,0x0 +SecondVehicleFacingZ,Long,0x0,0x0 +Valor-Points,Long,0x0,0x0 +valor_reward_read_mongoose,Boolean,0x0,0x0 +valor_reward_read_sidearm_pistol,Boolean,0x0,0x0 +valor_reward_read_assault_rifle,Boolean,0x0,0x0 +valor_reward_read_AssaultRifleMarine,Boolean,0x0,0x0 +valor_reward_read_razorbackhog,Boolean,0x0,0x0 +valor_reward_read_frag_grenade,Boolean,0x0,0x0 +valor_reward_read_combat_shotgun,Boolean,0x0,0x0 +valor_reward_read_CombatShotgunMarine,Boolean,0x0,0x0 +valor_reward_read_warthog,Boolean,0x0,0x0 +valor_reward_read_commando_rifle,Boolean,0x0,0x0 +valor_reward_read_CommandoRifleMarine,Boolean,0x0,0x0 +valor_reward_read_battle_rifle,Boolean,0x0,0x0 +valor_reward_read_BattleRifleMarine,Boolean,0x0,0x0 +valor_reward_read_gungoose,Boolean,0x0,0x0 +valor_reward_read_sniper_rifle,Boolean,0x0,0x0 +valor_reward_read_SniperRifleMarine,Boolean,0x0,0x0 +valor_reward_read_spnkr_rocket_launcher,Boolean,0x0,0x0 +valor_reward_read_RocketLauncherMarine,Boolean,0x0,0x0 +valor_reward_read_scorpion,Boolean,0x0,0x0 +valor_reward_read_mlrs,Boolean,0x0,0x0 +valor_reward_read_sidearm_pistol_elite,Boolean,0x0,0x0 +valor_reward_read_assault_rifle_tactical,Boolean,0x0,0x0 +valor_reward_read_combat_shotgun_choke,Boolean,0x0,0x0 +valor_reward_read_wasp,Boolean,0x0,0x0 +valor_reward_read_commando_rifle_suburban,Boolean,0x0,0x0 +valor_reward_read_br_scout,Boolean,0x0,0x0 +valor_reward_read_sniper_rifle_dmr,Boolean,0x0,0x0 +valor_reward_read_hydra_surgical_strike,Boolean,0x0,0x0 +valor_reward_read_rockethog,Boolean,0x0,0x0 +valor_reward_read_sword_striker,Boolean,0x0,0x0 +valor_reward_read_hammer_frontlines,Boolean,0x0,0x0 +valor_reward_read_arc_zapper,Boolean,0x0,0x0 +valor_reward_read_spike_revolver,Boolean,0x0,0x0 +valor_reward_read_plasma_pistol_unbound,Boolean,0x0,0x0 +valor_reward_read_needler_seeker,Boolean,0x0,0x0 +valor_reward_read_skewer_explosive,Boolean,0x0,0x0 +valor_reward_read_hotrod_gun_smartbounce,Boolean,0x0,0x0 +valor_reward_read_volt_action_overclocked,Boolean,0x0,0x0 +valor_reward_read_heatwave_overcooked,Boolean,0x0,0x0 +valor_reward_read_plasma_wetwork_auto,Boolean,0x0,0x0 +valor_reward_read_plasma_plasmablaster_commando,Boolean,0x0,0x0 +valor_reward_read_provoker_bouncing,Boolean,0x0,0x0 +valor_reward_read_hardlight_sentinel_beam_heatrod,Boolean,0x0,0x0 +valor_reward_read_spnker_rocket_launcher_tracking,Boolean,0x0,0x0 +valor_reward_read_escharums_axe_gravity_hammer,Boolean,0x0,0x0 +valor_reward_read_jega_energy_sword,Boolean,0x0,0x0 +Achievement_01_AintAfraidOfNoGhost,Boolean,0x0,0x0 +Achievement_02_TheresTwoOfYouNow,Boolean,0x0,0x0 +Achievement_03_StrongFoundations,Boolean,0x0,0x0 +Achievement_04_RingReverie,Boolean,0x0,0x0 +Achievement_05_TowerStruggle,Boolean,0x0,0x0 +Achievement_06_CanYouDigIt,Boolean,0x0,0x0 +Achievement_08_MoreLikeExSpire,Boolean,0x0,0x0 +Achievement_09_BatteryNotIncluded,Boolean,0x0,0x0 +Achievement_10_BrothersGrim,Boolean,0x0,0x0 +Achievement_12_WhatWillItTake,Boolean,0x0,0x0 +Achievement_13_HoldThatThought,Boolean,0x0,0x0 +Achievement_15_HouseParty,Boolean,0x0,0x0 +Achievement_16_EchoLocation,Boolean,0x0,0x0 +Achievement_17_EndlessPossibilities,Boolean,0x0,0x0 +Achievement_55_MixThingsUpToShootYourWayOut,Boolean,0x0,0x0 +Achievement_56_StickAround,Boolean,0x0,0x0 +Achievement_57_GotTheDrop,Boolean,0x0,0x0 +Achievement_58_ToughWayToGo,Boolean,0x0,0x0 +Achievement_59_PowerDrill,Boolean,0x0,0x0 +Achievement_60_ConservationOfMomentum,Boolean,0x0,0x0 +Achievement_60_ConservationOfMomentum_Start,Long,0x0,0x0 +Achievement_61_WildWeasel,Boolean,0x0,0x0 +Achievement_61_WildWeasel_Start,Long,0x0,0x0 +Achievement_62_ItReallyDoesBeatAnything,Boolean,0x0,0x0 +Achievement_63_Backstabber,Boolean,0x0,0x0 +Achievement_64_ReckoningAtRange,Boolean,0x0,0x0 +Achievement_65_TurnaboutIsFairPlay,Boolean,0x0,0x0 +Achievement_66_WhosTheBoss,Boolean,0x0,0x0 +Achievement_67_BreachingWithBrevity,Boolean,0x0,0x0 +Achievement_67_BreachingWithBrevity_Start,Long,0x0,0x0 +Achievement_68_ForzaVeloce,Boolean,0x0,0x0 +Achievement_69_PassingTheGas,Boolean,0x0,0x0 +Achievement_70_ThatsItYouPeaked,Boolean,0x0,0x0 +Achievement_75_WhipRidingTheGhost,Boolean,0x0,0x0 +Achievement_77_BringShielaHomeSafely,Boolean,0x0,0x0 +Achievement_78_TakesOneToMakeOne,Boolean,0x0,0x0 +Achievement_79_ThoughtWeCouldUseSomeBackup,Boolean,0x0,0x0 +Equipment_Points,Long,0x0,0x0 +Grapple_Upgrade_Level,Byte,0x0,0x0 +Evade_Upgrade_Level,Byte,0x0,0x0 +Wall_Upgrade_Level,Byte,0x0,0x0 +Sensor_Upgrade_Level,Byte,0x0,0x0 +Shield_Upgrade_Level,Byte,0x0,0x0 +Grapple_Upgrade_Read_Level,Byte,0x0,0x0 +Evade_Upgrade_Read_Level,Byte,0x0,0x0 +Wall_Upgrade_Read_Level,Byte,0x0,0x0 +Sensor_Upgrade_Read_Level,Byte,0x0,0x0 +Shield_Upgrade_Read_Level,Byte,0x0,0x0 +Grapple-Use-Count,Long,0x0,0x0 +Wall-Use-Count,Long,0x0,0x0 +Sensor-Use-Count,Long,0x0,0x0 +Evade-Use-Count,Long,0x0,0x0 +Visor-Use-Count,Long,0x0,0x0 +StatSecondsPlayed,Long,0x5D,0x5D +StatFusionCoilsThrown,Long,0x0,0x0 +StatFlocksKilled,Long,0x0,0x0 +StatGruntsLaunchedKilled,Long,0x0,0x0 +StatFragGrenadeKills,Long,0x0,0x0 +StatPlasmaGrenadeKills,Long,0x0,0x0 +StatLightningGrenadeKills,Long,0x0,0x0 +StatSpikeGrenadeKills,Long,0x0,0x0 +StatSidearmPistolKills,Long,0x0,0x0 +StatMagnumKills,Long,0x0,0x0 +StatShotgunKills,Long,0x0,0x0 +StatSMGKills,Long,0x0,0x0 +StatAssaultRifleKills,Long,0x0,0x0 +StatBattleRifleKills,Long,0x0,0x0 +StatVakara78Kills,Long,0x0,0x0 +StatDMRKills,Long,0x0,0x0 +StatSawKills,Long,0x0,0x0 +StatSniperRifleKills,Long,0x0,0x0 +StatReachGrenadeLauncherKills,Long,0x0,0x0 +StatRailGunKills,Long,0x0,0x0 +StatSpartanLaserKills,Long,0x0,0x0 +StatCovenantCarbineKills,Long,0x0,0x0 +StatStormRifleKills,Long,0x0,0x0 +StatBeamRifleKills,Long,0x0,0x0 +StatNeedlerKills,Long,0x0,0x0 +StatPlasmaPistolKills,Long,0x0,0x0 +StatEnergySwordKills,Long,0x0,0x0 +StatFuelRodCannonKills,Long,0x0,0x0 +StatCovenantGrenadeLauncherKills,Long,0x0,0x0 +StatGravityHammerKills,Long,0x0,0x0 +StatBeamRifleH2Kills,Long,0x0,0x0 +StatPlasmaRifleKills,Long,0x0,0x0 +StatSpikerKills,Long,0x0,0x0 +StatGatlingMortarKills,Long,0x0,0x0 +StatBeltFedMachineGunKills,Long,0x0,0x0 +StatCombatShotgunKills,Long,0x0,0x0 +StatCommandoRifleKills,Long,0x0,0x0 +StatDoubleBarrelShotgunKills,Long,0x0,0x0 +StatHeatwaveKills,Long,0x0,0x0 +StatHotrodKills,Long,0x0,0x0 +StatLiquidatorKills,Long,0x0,0x0 +StatPlasmaBlasterKills,Long,0x0,0x0 +StatReconSMGKills,Long,0x0,0x0 +StatSlagMakerKills,Long,0x0,0x0 +StatSkewerKills,Long,0x0,0x0 +StatSpikeRevolverKills,Long,0x0,0x0 +StatVoltActionKills,Long,0x0,0x0 +StatWetworkKills,Long,0x0,0x0 +StatArcZapperKills,Long,0x0,0x0 +StatSentinelBeamKils,Long,0x0,0x0 +StatRocketLaucherKills,Long,0x0,0x0 +StatScatterShotKills,Long,0x0,0x0 +StatHexWallKills,Long,0x0,0x0 +StatKnockBackAbilityKills,Long,0x0,0x0 +StatCarbineKills,Long,0x0,0x0 +StatSentinelBeamKills,Long,0x0,0x0 +StatGrappleHookKills,Long,0x0,0x0 +StatGrappleHijackGhosts,Long,0x0,0x0 +core_angelfood,Byte,0x0,0x0 +core_beignet,Byte,0x0,0x0 +core_cannoli,Byte,0x0,0x0 +core_danish,Byte,0x0,0x0 +core_empanada,Byte,0x0,0x0 +core_fritter,Byte,0x0,0x0 +core_gingerbread,Byte,0x0,0x0 +core_honeycomb,Byte,0x0,0x0 +core_jellyroll,Byte,0x0,0x0 +core_keylime,Byte,0x0,0x0 +core_muffin,Byte,0x0,0x0 +core_pancake,Byte,0x0,0x0 +core_strudel,Byte,0x0,0x0 +core_turnover,Byte,0x0,0x0 +core_victoria,Byte,0x0,0x0 +core_waffle,Byte,0x0,0x0 +core_zeppole,Byte,0x0,0x0 +core_amandine,Byte,0x0,0x0 +core_brownie,Byte,0x0,0x0 +core_cake,Byte,0x0,0x0 +core_donut,Byte,0x0,0x0 +core_eclair,Byte,0x0,0x0 +core_fudge,Byte,0x0,0x0 +core_gelato,Byte,0x0,0x0 +core_haupia,Byte,0x0,0x0 +core_icecream,Byte,0x0,0x0 +core_jaffa,Byte,0x0,0x0 +core_kolache,Byte,0x0,0x0 +core_lemonbar,Byte,0x0,0x0 +core_mochi,Byte,0x0,0x0 +core_napoleon,Byte,0x0,0x0 +core_pudding,Byte,0x0,0x0 +core_rosette,Byte,0x0,0x0 +core_sundae,Byte,0x0,0x0 +core_tart,Byte,0x0,0x0 +core_waldorf,Byte,0x0,0x0 +core_gummyworm,Byte,0x0,0x0 +core_hottoddy,Byte,0x0,0x0 +core_kitkat,Byte,0x0,0x0 +core_stroopwafel,Byte,0x0,0x0 +core_shortbread,Byte,0x0,0x0 +core_rockcandy,Byte,0x0,0x0 +core_meltaway,Byte,0x0,0x0 +core_dreampie,Byte,0x0,0x0 +core_biscotti,Byte,0x0,0x0 +armor_asgard,Byte,0x0,0x0 +armor_baldr,Byte,0x0,0x0 +armor_bifrost,Byte,0x0,0x0 +armor_brokkr,Byte,0x0,0x0 +armor_eitri,Byte,0x0,0x0 +armor_eostre,Byte,0x0,0x0 +armor_fenrir,Byte,0x0,0x0 +armor_freya,Byte,0x0,0x0 +armor_frigg,Byte,0x0,0x0 +armor_ginnungagap,Byte,0x0,0x0 +armor_gungnir,Byte,0x0,0x0 +armor_heimdall,Byte,0x0,0x0 +armor_hel,Byte,0x0,0x0 +armor_huginn,Byte,0x0,0x0 +armor_jormungandr,Byte,0x0,0x0 +armor_leif,Byte,0x0,0x0 +armor_loki,Byte,0x0,0x0 +armor_midgard,Byte,0x0,0x0 +armor_muninn,Byte,0x0,0x0 +armor_niflheim,Byte,0x0,0x0 +armor_norn,Byte,0x0,0x0 +armor_odin,Byte,0x0,0x0 +armor_ragnarok,Byte,0x0,0x0 +armor_sif,Byte,0x0,0x0 +armor_skadi,Byte,0x0,0x0 +armor_sleipnir,Byte,0x0,0x0 +armor_surt,Byte,0x0,0x0 +armor_thor,Byte,0x0,0x0 +armor_tyr,Byte,0x0,0x0 +armor_valhalla,Byte,0x0,0x0 +armor_valkyrie,Byte,0x0,0x0 +armor_vanir,Byte,0x0,0x0 +armor_vidar,Byte,0x0,0x0 +armor_yggdrasil,Byte,0x0,0x0 +forerunner_totem_andromeda,Byte,0x0,0x0 +forerunner_totem_cancer,Byte,0x0,0x0 +forerunner_totem_draco,Byte,0x0,0x0 +forerunner_totem_gemini,Byte,0x0,0x0 +forerunner_totem_hydra,Byte,0x0,0x0 +forerunner_totem_libra,Byte,0x0,0x0 +forerunner_totem_mensa,Byte,0x0,0x0 +spartan_griffin,Byte,0x0,0x0 +spartan_makovich,Byte,0x0,0x0 +spartan_sorel,Byte,0x0,0x0 +spartan_horvath,Byte,0x0,0x0 +spartan_vettel,Byte,0x0,0x0 +spartan_stone,Byte,0x0,0x0 +spartan_kovan,Byte,0x0,0x0 +grapple_hook,Boolean,0x0,0x0 +unsc_marine_first,Boolean,0x0,0x0 +forerunner_totems_first_detect,Boolean,0x0,0x0 +forerunner_totems_first_approach,Boolean,0x0,0x0 +forerunner_totems_first_scan,Boolean,0x0,0x0 +forerunner_totems_second_scan,Boolean,0x0,0x0 +forerunner_totems_third_scan,Boolean,0x0,0x0 +forerunner_totems_fourth_scan,Boolean,0x0,0x0 +forerunner_totems_fifth_scan,Boolean,0x0,0x0 +forerunner_totems_sixth_scan,Boolean,0x0,0x0 +forerunner_totems_seventh_scan,Boolean,0x0,0x0 +skull_first_detect,Boolean,0x0,0x0 +skull_first_pickup,Boolean,0x0,0x0 +deadspartan_first_detect,Boolean,0x0,0x0 +deadspartan_first_sight,Boolean,0x0,0x0 +ban_scanner_first_encounter,Boolean,0x0,0x0 +hvt_first_defeated,Boolean,0x0,0x0 +fob_first_approach,Boolean,0x0,0x0 +aluminum_kill_codex_read,Boolean,0x0,0x0 +beryllium_kill_codex_read,Boolean,0x0,0x0 +cesium_kill_codex_read,Boolean,0x0,0x0 +dubnium_kill_codex_read,Boolean,0x0,0x0 +einsteinium_kill_codex_read,Boolean,0x0,0x0 +fermium_kill_codex_read,Boolean,0x0,0x0 +gallium_kill_codex_read,Boolean,0x0,0x0 +helium_kill_codex_read,Boolean,0x0,0x0 +iridium_kill_codex_read,Boolean,0x0,0x0 +lithium_kill_codex_read,Boolean,0x0,0x0 +magnesium_kill_codex_read,Boolean,0x0,0x0 +nobelium_kill_codex_read,Boolean,0x0,0x0 +osmium_kill_codex_read,Boolean,0x0,0x0 +plutonium_kill_codex_read,Boolean,0x0,0x0 +radium_kill_codex_read,Boolean,0x0,0x0 +forerunner_totem_andromeda_codex_read,Boolean,0x0,0x0 +forerunner_totem_cancer_codex_read,Boolean,0x0,0x0 +forerunner_totem_draco_codex_read,Boolean,0x0,0x0 +forerunner_totem_gemini_codex_read,Boolean,0x0,0x0 +forerunner_totem_hydra_codex_read,Boolean,0x0,0x0 +forerunner_totem_libra_codex_read,Boolean,0x0,0x0 +forerunner_totem_mensa_codex_read,Boolean,0x0,0x0 +core_angelfood_codex_read,Boolean,0x0,0x0 +core_beignet_codex_read,Boolean,0x0,0x0 +core_cannoli_codex_read,Boolean,0x0,0x0 +core_danish_codex_read,Boolean,0x0,0x0 +core_empanada_codex_read,Boolean,0x0,0x0 +core_fritter_codex_read,Boolean,0x0,0x0 +core_gingerbread_codex_read,Boolean,0x0,0x0 +core_honeycomb_codex_read,Boolean,0x0,0x0 +core_jellyroll_codex_read,Boolean,0x0,0x0 +core_keylime_codex_read,Boolean,0x0,0x0 +core_muffin_codex_read,Boolean,0x0,0x0 +core_pancake_codex_read,Boolean,0x0,0x0 +core_strudel_codex_read,Boolean,0x0,0x0 +core_turnover_codex_read,Boolean,0x0,0x0 +core_victoria_codex_read,Boolean,0x0,0x0 +core_waffle_codex_read,Boolean,0x0,0x0 +core_zeppole_codex_read,Boolean,0x0,0x0 +core_amandine_codex_read,Boolean,0x0,0x0 +core_brownie_codex_read,Boolean,0x0,0x0 +core_cake_codex_read,Boolean,0x0,0x0 +core_donut_codex_read,Boolean,0x0,0x0 +core_eclair_codex_read,Boolean,0x0,0x0 +core_fudge_codex_read,Boolean,0x0,0x0 +core_gelato_codex_read,Boolean,0x0,0x0 +core_haupia_codex_read,Boolean,0x0,0x0 +core_icecream_codex_read,Boolean,0x0,0x0 +core_jaffa_codex_read,Boolean,0x0,0x0 +core_kolache_codex_read,Boolean,0x0,0x0 +core_lemonbar_codex_read,Boolean,0x0,0x0 +core_mochi_codex_read,Boolean,0x0,0x0 +core_napoleon_codex_read,Boolean,0x0,0x0 +core_rosette_codex_read,Boolean,0x0,0x0 +core_pudding_codex_read,Boolean,0x0,0x0 +core_sundae_codex_read,Boolean,0x0,0x0 +core_tart_codex_read,Boolean,0x0,0x0 +core_waldorf_codex_read,Boolean,0x0,0x0 +core_gummyworm_codex_read,Boolean,0x0,0x0 +core_hottoddy_codex_read,Boolean,0x0,0x0 +core_kitkat_codex_read,Boolean,0x0,0x0 +spartan_griffin_codex_read,Boolean,0x0,0x0 +spartan_horvath_codex_read,Boolean,0x0,0x0 +spartan_makovich_codex_read,Boolean,0x0,0x0 +spartan_kovan_codex_read,Boolean,0x0,0x0 +spartan_sorel_codex_read,Boolean,0x0,0x0 +spartan_stone_codex_read,Boolean,0x0,0x0 +spartan_vettel_codex_read,Boolean,0x0,0x0 +skull_ant_codex_read,Boolean,0x0,0x0 +skull_beetle_codex_read,Boolean,0x0,0x0 +skull_cockroach_codex_read,Boolean,0x0,0x0 +skull_firefly_codex_read,Boolean,0x0,0x0 +skull_grub_codex_read,Boolean,0x0,0x0 +skull_hornet_codex_read,Boolean,0x0,0x0 +skull_junebug_codex_read,Boolean,0x0,0x0 +skull_katydid_codex_read,Boolean,0x0,0x0 +skull_louse_codex_read,Boolean,0x0,0x0 +skull_moth_codex_read,Boolean,0x0,0x0 +skull_netwing_codex_read,Boolean,0x0,0x0 +skull_vespid_codex_read,Boolean,0x0,0x0 +armor_asgard_codex_read,Boolean,0x0,0x0 +armor_baldr_codex_read,Boolean,0x0,0x0 +armor_bifrost_codex_read,Boolean,0x0,0x0 +armor_brokkr_codex_read,Boolean,0x0,0x0 +armor_eitri_codex_read,Boolean,0x0,0x0 +armor_eostre_codex_read,Boolean,0x0,0x0 +armor_fenrir_codex_read,Boolean,0x0,0x0 +armor_frigg_codex_read,Boolean,0x0,0x0 +armor_ginnungagap_codex_read,Boolean,0x0,0x0 +armor_gungnir_codex_read,Boolean,0x0,0x0 +armor_heimdall_codex_read,Boolean,0x0,0x0 +armor_hel_codex_read,Boolean,0x0,0x0 +armor_huginn_codex_read,Boolean,0x0,0x0 +armor_jormungandr_codex_read,Boolean,0x0,0x0 +armor_leif_codex_read,Boolean,0x0,0x0 +armor_loki_codex_read,Boolean,0x0,0x0 +armor_midgard_codex_read,Boolean,0x0,0x0 +armor_muninn_codex_read,Boolean,0x0,0x0 +armor_niflheim_codex_read,Boolean,0x0,0x0 +armor_norn_codex_read,Boolean,0x0,0x0 +armor_odin_codex_read,Boolean,0x0,0x0 +armor_ragnarok_codex_read,Boolean,0x0,0x0 +armor_sif_codex_read,Boolean,0x0,0x0 +armor_skadi_codex_read,Boolean,0x0,0x0 +armor_sleipnir_codex_read,Boolean,0x0,0x0 +armor_surt_codex_read,Boolean,0x0,0x0 +armor_thor_codex_read,Boolean,0x0,0x0 +armor_tyr_codex_read,Boolean,0x0,0x0 +armor_valhalla_codex_read,Boolean,0x0,0x0 +armor_valkyrie_codex_read,Boolean,0x0,0x0 +armor_vanir_codex_read,Boolean,0x0,0x0 +armor_vidar_codex_read,Boolean,0x0,0x0 +armor_yggdrasil_codex_read,Boolean,0x0,0x0 +first_acquisition_armor_locker,Boolean,0x0,0x0 +first_acquisition_game_skull,Boolean,0x0,0x0 +first_acquisition_dead_spartan,Boolean,0x0,0x0 +first_acquisition_memory_core,Boolean,0x0,0x0 +first_acquisition_unsc_datapad,Boolean,0x0,0x0 +first_acquisition_ban_datapad,Boolean,0x0,0x0 +first_acquisition_halsey_datapad,Boolean,0x0,0x0 +first_acquisition_forerunner_totem,Boolean,0x0,0x0 +first_acquisition_comm_tower,Boolean,0x0,0x0 +hvts_are_read,Long,0x0,0x0 +campfire_spawn_id,Long,0x2CF1FE58,0x2CF1FE58 +campfire_zone_set_id,Long,0x2,0x2 +campfire_map_id,Long,0xA0B35DCE,0xA0B35DCE +campfire_mission_id,Long,0x1,0x1 +campfire_objective_count,Byte,0x0,0x0 +campfire_golden_path_complete,Boolean,0x0,0x0 diff --git a/src/InfiniteTool/Data/6.10021.10921.0/offsets.json b/src/InfiniteTool/Data/6.10021.10921.0/offsets.json index 2d91b9b..2d03cc1 100644 --- a/src/InfiniteTool/Data/6.10021.10921.0/offsets.json +++ b/src/InfiniteTool/Data/6.10021.10921.0/offsets.json @@ -6,19 +6,30 @@ "PlayerDatum_TlsIndexOffset": "0x0442A098", // manual discovery, player_datum: null, "ParticipantDatum_TlsIndexOffset": "0x442D398", // manual discovery, class i343::Participant::ParticipantDatum "PersistenceUnknown_TlsIndexOffset": "0x41CB350", // manual discovery, reference from persitence method + "PersistenceUnknown2_TlsIndexOffset": "0x41C8EE0", // manual discovery "PersistenceData_TlsIndexOffset": "0x44B4BC0", // manual discovery - "Persistence_KeysFromStrings_Batch": "0xA9A104", // first function call in imp - "Persistence_GetKeyTypes_Batch": "0xA99114", // first function call in imp - "Persistence_GetBools_Batch": "0x2579778", // first function call in imp - "Persistence_GetBytes_Batch": "0xA99938", // first function call in imp - "Persistence_GetLongs_Batch": "0x257A5AC", // first function call in imp - "Persistence_GetBoolsForParticipant_Batch": "0x2579E68", // first function call in imp - "Persistence_GetBytesForParticipant_Batch": "0xA9986C", // first function call in imp - "Persistence_GetLongsForParticipant_Batch": "0x2579474", // first function call in imp - "Persistence_SetBoolsForParticipant_Batch": "0x2579D20", // first function call in imp - "Persistence_SetBytesForParticipant_Batch": "0x257A2B0", // first function call in imp - "Persistence_SetLongsForParticipant_Batch": "0x257964C", // first function call in imp - "StartMap": "0x0", - "StartMapAtSpawn": "0x0", - "RestartMapAtSpawn": "0x0" + + "Persistence_BatchTryCreateKeysFromStrings": "0xa9a104", + "Persistence_BatchGetKeyTypes": "0xa99114", + "Persistence_BatchGetBoolKeys": "0x2579778", + "Persistence_BatchGetByteKeys": "0xa99938", + "Persistence_BatchGetLongKeys": "0x257a5ac", + "Persistence_BatchGetBoolKeysForParticipant": "0x2579e68", + "Persistence_BatchGetByteKeysForParticipant": "0xa9986c", + "Persistence_BatchGetLongKeysForParticipant": "0x2579474", + "Persistence_BatchSetBoolKeys": "0x257a8bc", + "Persistence_BatchSetByteKeys": "0x25792c4", + "Persistence_BatchSetLongKeys": "0x257ad14", + "Persistence_BatchSetBoolKeysForParticipant": "0x2579d20", + "Persistence_BatchSetByteKeysForParticipant": "0x257a2b0", + "Persistence_BatchSetLongKeysForParticipant": "0x257964c", + "Persistence_BatchRemoveBoolKeyOverrides": "0x257abc0", + "Persistence_BatchRemoveByteKeyOverrides": "0x2579170", + "Persistence_BatchRemoveLongKeyOverrides": "0x257aa6c", + "Persistence_BatchRemoveBoolKeyOverrideForParticipant": "0x2578e60", + "Persistence_BatchRemoveByteKeyOverrideForParticipant": "0x2579918", + "Persistence_BatchRemoveLongKeyOverrideForParticipant": "0x2578a3c", + "StartLevel": "0x230756c", + "StartLevelAtSpawn": "0x23075d4", + "ResetLevelAtSpawn": "0x2307410" } \ No newline at end of file diff --git a/src/InfiniteTool/Data/6.10021.11755.0/offsets.json b/src/InfiniteTool/Data/6.10021.11755.0/offsets.json new file mode 100644 index 0000000..1493ea4 --- /dev/null +++ b/src/InfiniteTool/Data/6.10021.11755.0/offsets.json @@ -0,0 +1,37 @@ +{ + "MainThreadEntry": "0xBECAF8", // manual discovery via breakpoint in checkpoint fn + "Checkpoint_TlsIndexOffset": "0x41C9748", + "RevertFlagOffset": "0x3B68950", + "CheckpointInfoOffset": "0x415A450", + "PlayerDatum_TlsIndexOffset": "0x0442A098", // manual discovery, player_datum: null, + "ParticipantDatum_TlsIndexOffset": "0x442D398", // manual discovery, class i343::Participant::ParticipantDatum + "PersistenceUnknown_TlsIndexOffset": "0x41CB350", // manual discovery, reference from persitence method + "PersistenceUnknown2_TlsIndexOffset": "0x41C8EE0", // manual discovery, deep within Persistence_BatchSetByteKeys, third call ,last call ,2nd to last call, only call + "PersistenceData_TlsIndexOffset": "0x44B4BC0", // manual discovery + + "Persistence_BatchTryCreateKeysFromStrings": "0xa9a014", + "Persistence_BatchGetKeyTypes": "0xa99024", + "Persistence_BatchGetBoolKeys": "0x257978c", + "Persistence_BatchGetByteKeys": "0xa99848", + "Persistence_BatchGetLongKeys": "0x257a5c0", + "Persistence_BatchGetBoolKeysForParticipant": "0x2579e7c", + "Persistence_BatchGetByteKeysForParticipant": "0xa9977c", + "Persistence_BatchGetLongKeysForParticipant": "0x2579488", + "Persistence_BatchSetBoolKeys": "0x257a8d0", + "Persistence_BatchSetByteKeys": "0x25792d8", + "Persistence_BatchSetLongKeys": "0x257ad28", + "Persistence_BatchSetBoolKeysForParticipant": "0x2579d34", + "Persistence_BatchSetByteKeysForParticipant": "0x257a2c4", + "Persistence_BatchSetLongKeysForParticipant": "0x2579660", + "Persistence_BatchRemoveBoolKeyOverrides": "0x257abd4", + "Persistence_BatchRemoveByteKeyOverrides": "0x2579184", + "Persistence_BatchRemoveLongKeyOverrides": "0x257aa80", + "Persistence_BatchRemoveBoolKeyOverrideForParticipant": "0x2578e74", + "Persistence_BatchRemoveByteKeyOverrideForParticipant": "0x257992c", + "Persistence_BatchRemoveLongKeyOverrideForParticipant": "0x2578a50", + "Player_SaveLoadoutToPersistentStorage": "0x25ec7d4", + "StartLevel": "0x230770c", + "StartLevelAtSpawn": "0x2307774", + "ResetLevelAtSpawn": "0x23075b0", + "game_revert": "0x20bb748" +} \ No newline at end of file diff --git a/src/InfiniteTool/Formats/ProgressionData.cs b/src/InfiniteTool/Formats/ProgressionData.cs new file mode 100644 index 0000000..6c72c17 --- /dev/null +++ b/src/InfiniteTool/Formats/ProgressionData.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using static InfiniteTool.GameInterop.GamePersistence; + +namespace InfiniteTool.Formats +{ + public class ProgressionData + { + private const string V1 = "InfiniteProgressV1"; + public const string CurrentVersion = V1; + + public uint Participant { get; } + public List Entries { get; } + + public ProgressionData(uint participant, List entries) + { + this.Participant = participant; + this.Entries = entries; + } + + public void Write(Stream stream) + { + using var writer = new StreamWriter(stream); + writer.WriteLine("InfiniteProgressV1"); + writer.WriteLine($"ParticipantID:0x{this.Participant:X}"); + writer.WriteLine("KeyName,DataType,GlobalValue,ParticipantValue"); + foreach (var entry in this.Entries) + { + writer.WriteLine($"{entry.KeyName},{entry.DataType},0x{entry.GlobalValue:X},0x{entry.ParticipantValue:X}"); + } + } + + public static ProgressionData? FromStream(Stream stream) + { + using var reader = new StreamReader(stream); + + var version = reader.ReadLine(); + if (version != CurrentVersion) return null; + + var participant = reader.ReadLine(); + if(participant == null) return null; + var participantId = Convert.ToUInt32(participant.Split(':')[1], 16); + + var header = reader.ReadLine(); + + var entries = new List(); + + string? entryLine = null; + while ((entryLine = reader.ReadLine()) != null) + { + var parts = entryLine.Split(','); + + entries.Add(new ProgressionEntry() + { + KeyName = parts[0], + DataType = parts[1], + GlobalValue = Convert.ToUInt32(parts[2], 16), + ParticipantValue = Convert.ToUInt32(parts[3], 16), + }); + } + + return new ProgressionData(participantId, entries); + } + } +} diff --git a/src/InfiniteTool/GameContext.cs b/src/InfiniteTool/GameContext.cs index ec97d63..eef38ec 100644 --- a/src/InfiniteTool/GameContext.cs +++ b/src/InfiniteTool/GameContext.cs @@ -35,7 +35,7 @@ public class GameContext ["Silent Auditorium"] = InfiniteMap.SilentAuditorium, }; - public List PersistenceEntries { get; private set; } = new(); + public List PersistenceEntries { get; private set; } = new(); public ObservableCollection Checkpoints { get; private set; } = new() { diff --git a/src/InfiniteTool/GameInterop/ArenaAllocator.cs b/src/InfiniteTool/GameInterop/ArenaAllocator.cs index e25f31e..d073e84 100644 --- a/src/InfiniteTool/GameInterop/ArenaAllocator.cs +++ b/src/InfiniteTool/GameInterop/ArenaAllocator.cs @@ -70,7 +70,7 @@ public ArenaAllocator(IRemoteProcess remoteProcess, int size) // ArrayPool will give us at least the bytes we ask for, tending towards 2^N, so we'll just use that this.size = this.localCopy.Length; - this.allocationBase = remoteProcess.Allocate(size); + this.allocationBase = remoteProcess.Allocate(this.size); this.freeSpot = this.allocationBase; } diff --git a/src/InfiniteTool/GameInterop/EngineDataTypes/BlamEngineList.cs b/src/InfiniteTool/GameInterop/EngineDataTypes/BlamEngineList.cs index 391b0ac..19f0337 100644 --- a/src/InfiniteTool/GameInterop/EngineDataTypes/BlamEngineList.cs +++ b/src/InfiniteTool/GameInterop/EngineDataTypes/BlamEngineList.cs @@ -34,6 +34,7 @@ public unsafe class BlamEngineList where T : unmanaged nint head; nint tail; nint end; + nint count; public nint Address => location; @@ -121,11 +122,32 @@ public void AddValue(T value) this.SyncTo(); } + /// + /// Add the values to the list. !! When adding bits, it will add at the next byte, not the next bit !! + /// + /// public void AddValues(Span values) { - var bytes = MemoryMarshal.AsBytes(values); + Span bytes; + if(typeof(T) == typeof(bit)) + { + // TODO: implement proper bit-level appending? + + bytes = new byte[(int)Math.Ceiling(values.Length / 8f)]; + + for (var i = 0; i < count; i++) + { + var bit = (bit)(object)values[i]; + + var byteIndex = Math.DivRem(i, 8, out var bitIndex); + bytes[byteIndex] = bit.Set(bytes[byteIndex], bitIndex); + } + } + else + { + bytes = MemoryMarshal.AsBytes(values); + } - // TODO: bit handling proc.WriteAt(this.tail, bytes); this.tail += sizeof(T) * values.Length; this.SyncTo(); @@ -149,6 +171,8 @@ public void SyncFrom() proc.ReadAt(this.location + sizeof(nint), out this.tail); proc.ReadAt(this.location + sizeof(nint) + sizeof(nint), out this.end); + + proc.ReadAt(this.location + sizeof(nint) + sizeof(nint) + sizeof(nint), out this.count); } public void SyncTo() @@ -159,6 +183,8 @@ public void SyncTo() proc.WriteAt(this.location + sizeof(nint) + sizeof(nint), this.end); } + + public static implicit operator nint(BlamEngineList list) => list.Address; } public struct bit @@ -175,6 +201,15 @@ public bit(byte value, int index) this.Value = ((value >> index) & 0x1) == 0x1; } + public byte Set(byte value, int index) + { + if (!this.Value) return value; + + value |= (byte)(0x1 << index); + + return value; + } + public static implicit operator bit(bool value) => new bit(value); public static implicit operator bool(bit value) => value.Value; diff --git a/src/InfiniteTool/GameInterop/GameInstance.cs b/src/InfiniteTool/GameInterop/GameInstance.cs index 71a53da..c94cdf9 100644 --- a/src/InfiniteTool/GameInterop/GameInstance.cs +++ b/src/InfiniteTool/GameInterop/GameInstance.cs @@ -30,6 +30,7 @@ public CheckpointData(string levelName, TimeSpan gameTime, byte[] checkpointData [AddINotifyPropertyChangedInterface] public class GameInstance { + private const string LatestVersion = "6.10021.10921.0"; private readonly IOffsetProvider offsetProvider; private readonly ILogger logger; private InfiniteOffsets offsets = new InfiniteOffsets(); @@ -60,7 +61,8 @@ public GameInstance(IOffsetProvider offsetProvider, ILogger logger internal void TriggerRevert() { this.logger.LogInformation("Revert requested"); - this.RemoteProcess.Write(this.RevertFlagOffset, stackalloc byte[] { 0x22 }); + //this.RemoteProcess.Write(this.RevertFlagOffset, stackalloc byte[] { 0x22 }); + this.RemoteProcess.CallFunction(this.offsets.GameRevert); } internal void TriggerCheckpoint() @@ -75,7 +77,8 @@ public void StartMap(InfiniteMap map) { if(this.scenarioStringLocations.TryGetValue(map, out var location)) { - this.RemoteProcess.CallFunction(this.offsets.StartMap, location); + this.logger.LogInformation("Starting map {map}//{location}", map, location); + this.RemoteProcess.CallFunction(this.offsets.StartLevel, location); } } @@ -220,11 +223,15 @@ private void SetupWorkspace() } } - public void LoadOffsets() + public string GetGameVersion() { - var version = this.RemoteProcess.Process?.MainModule?.FileVersionInfo.FileVersion; + // TODO: winstore version on the exe is not available, need to find a reliable source of version info to not have latest version hardcoded for winstore fallback + return this.RemoteProcess.Process?.MainModule?.FileVersionInfo.FileVersion ?? LatestVersion; + } - this.offsets = this.offsetProvider.GetOffsets(version); + public void LoadOffsets() + { + this.offsets = this.offsetProvider.GetOffsets(GetGameVersion()); } public unsafe void PopulateAddresses() @@ -252,26 +259,46 @@ private unsafe void GetMainThreadInfo() foreach (var thread in this.RemoteProcess.Threads) { - var thandle = Win32.OpenThread(ThreadAccess.QUERY_INFORMATION, false, (uint)thread.Id); if (thandle == IntPtr.Zero) - throw new Win32Exception(Marshal.GetLastWin32Error()); + { + logger.LogError(new Win32Exception(Marshal.GetLastWin32Error()), "Error during thread scanning"); + } var entry = new IntPtr(); var hr = Win32.NtQueryInformationThread(thandle, ThreadInformationClass.ThreadQuerySetWin32StartAddress, ref entry, Marshal.SizeOf(entry), out var entryReq); if (hr != 0) - throw new Win32Exception(hr); + { + Win32.CloseHandle(thandle); + logger.LogError(new Win32Exception(Marshal.GetLastWin32Error()), "Error during thread scanning, start address query {hr}", hr); + continue; + } + + logger.LogInformation($"Inspecting TID: {thread.Id,5:x}, start: {entry:x}, expect: {expectedThreadEntry:x}"); if (entry != expectedThreadEntry) { + Win32.CloseHandle(thandle); continue; } - hr = Win32.NtQueryInformationThread(thandle, ThreadInformationClass.ThreadBasicInformation, ref tinfo, Marshal.SizeOf(tinfo), out var tinfoReq); if (hr != 0) - throw new Win32Exception(hr); + { + Win32.CloseHandle(thandle); + logger.LogError(new Win32Exception(Marshal.GetLastWin32Error()), "Error during thread scanning, TBI query {hr}", hr); + continue; + } + + if(tinfo.TebBaseAddress == IntPtr.Zero) + { + Win32.CloseHandle(thandle); + logger.LogWarning($"TEB base address from discovered thread was zero, TID:{thread.Id,5:x}, start: {entry:x}"); + continue; + } + + logger.LogInformation($"Reading TEB for TID: {thread.Id,5:x}, start: {entry:x}, teb: {tinfo.TebBaseAddress}"); this.RemoteProcess.ReadAt(tinfo.TebBaseAddress, out teb); @@ -280,12 +307,9 @@ private unsafe void GetMainThreadInfo() logger.LogInformation($"TID: {thread.Id,5:x}, ENTRY: {entry:x16}, TEB: {tinfo.TebBaseAddress:x16}, TLS Expansion: {teb.TlsExpansionSlots:x16}"); Win32.CloseHandle(thandle); + break; } - var checkpoint = ReadMainTebPointer(304); - - logger.LogInformation($"Checkpoint: {checkpoint:x16}"); - Win32.CloseHandle(handle); } diff --git a/src/InfiniteTool/GameInterop/GamePersistence.cs b/src/InfiniteTool/GameInterop/GamePersistence.cs index 6677620..548750e 100644 --- a/src/InfiniteTool/GameInterop/GamePersistence.cs +++ b/src/InfiniteTool/GameInterop/GamePersistence.cs @@ -16,6 +16,7 @@ public class GamePersistence private readonly ILogger logger; private InfiniteOffsets offsets; private ArenaAllocator? allocator; + private bool NeedsReBootstrapped = false; private string[] persistenceKeys = InteropConstantData.PersistenceKeys.Keys.ToArray(); private Dictionary stringToKeyMap = new(); private IRemoteProcess process => this.instance.RemoteProcess; @@ -38,6 +39,8 @@ private void Instance_OnAttachHandler(object sender, EventArgs? args) public void Bootstrap() { + this.NeedsReBootstrapped = false; + if (this.allocator != null) { try @@ -58,7 +61,7 @@ public void Bootstrap() inList.AddAsciiStrings(allocator, persistenceKeys); this.process.CallFunction( - this.offsets.Persistence_KeysFromStrings_Batch, + this.offsets.Persistence_BatchTryCreateKeysFromStrings, 0x0, keyList.Address, inList.Address); @@ -72,6 +75,7 @@ public void Bootstrap() this.logger.LogWarning($"Mismatch of string to key results, sent {persistenceKeys.Length}, got back {items}"); } + stringToKeyMap.Clear(); for (var i = 0; i < items; i++) { var val = keyList.GetValue(i); @@ -85,6 +89,7 @@ public void Bootstrap() else { this.logger.LogWarning($"Miss on string to key, sent '{persistenceKeys[i]}', got back {val:x16}"); + this.NeedsReBootstrapped = true; } } @@ -93,9 +98,19 @@ public void Bootstrap() this.allocator = allocator; } - public List GetAllProgress() + private void EnsureBoostrapped() { - if (this.allocator == null) return new List(); + if(this.NeedsReBootstrapped) + { + this.Bootstrap(); + } + } + + public List GetAllProgress() + { + this.EnsureBoostrapped(); + + if (this.allocator == null) return new List(); var keys = this.stringToKeyMap.ToArray(); @@ -117,13 +132,13 @@ public List GetAllProgress() var participantId = (nint)(CurrentParticipantId << 16); - process.CallFunction(this.offsets.Persistence_GetBools_Batch, 0x0, globalBools.Address, keyList.Address); - process.CallFunction(this.offsets.Persistence_GetBytes_Batch, 0x0, globalBytes.Address, keyList.Address); - process.CallFunction(this.offsets.Persistence_GetLongs_Batch, 0x0, globalLongs.Address, keyList.Address); + process.CallFunction(this.offsets.Persistence_BatchGetBoolKeys, 0x0, globalBools, keyList); + process.CallFunction(this.offsets.Persistence_BatchGetByteKeys, 0x0, globalBytes, keyList); + process.CallFunction(this.offsets.Persistence_BatchGetLongKeys, 0x0, globalLongs, keyList); - process.CallFunction(this.offsets.Persistence_GetBoolsForParticipant_Batch, 0x0, participantBools.Address, participantId, keyList.Address); - process.CallFunction(this.offsets.Persistence_GetBytesForParticipant_Batch, 0x0, participantBytes.Address, participantId, keyList.Address); - process.CallFunction(this.offsets.Persistence_GetLongsForParticipant_Batch, 0x0, participantLongs.Address, participantId, keyList.Address); + process.CallFunction(this.offsets.Persistence_BatchGetBoolKeysForParticipant, 0x0, participantBools, participantId, keyList); + process.CallFunction(this.offsets.Persistence_BatchGetByteKeysForParticipant, 0x0, participantBytes, participantId, keyList); + process.CallFunction(this.offsets.Persistence_BatchGetLongKeysForParticipant, 0x0, participantLongs, participantId, keyList); globalBools.SyncFrom(); globalBytes.SyncFrom(); @@ -142,7 +157,7 @@ public List GetAllProgress() var globalLongValues = globalLongs.GetValues(0, keys.Length); var participantLongValues = participantLongs.GetValues(0, keys.Length); - var results = new List(keys.Length); + var results = new List(keys.Length); var i = 0; foreach (var (str, key) in keys) @@ -165,7 +180,7 @@ public List GetAllProgress() _ => 0, }; - results.Add(new Entry() + results.Add(new ProgressionEntry() { KeyName = str, DataType = type.ToString(), @@ -181,6 +196,96 @@ public List GetAllProgress() } } + public void SetProgress(List entries) + { + this.EnsureBoostrapped(); + + var boolSet = new List<(uint key, uint globalVal, uint participantVal)>(); + var byteSet = new List<(uint key, uint globalVal, uint participantVal)>(); + var longSet = new List<(uint key, uint globalVal, uint participantVal)>(); + + foreach (var entry in entries) + { + if(stringToKeyMap.TryGetValue(entry.KeyName, out var key) + && InteropConstantData.PersistenceKeys.TryGetValue(entry.KeyName, out var type)) + { + switch (type) + { + case PersistenceValueType.Boolean: + boolSet.Add((key, entry.GlobalValue, entry.ParticipantValue)); + break; + case PersistenceValueType.Byte: + byteSet.Add((key, entry.GlobalValue, entry.ParticipantValue)); + break; + case PersistenceValueType.Long: + longSet.Add((key, entry.GlobalValue, entry.ParticipantValue)); + break; + } + } + } + + lock(allocator) + { + var boolKeys = allocator.AllocateList(boolSet.Count); + var byteKeys = allocator.AllocateList(byteSet.Count); + var longKeys = allocator.AllocateList(longSet.Count); + boolKeys.AddValues(boolSet.Select(b => b.key).ToArray()); + byteKeys.AddValues(byteSet.Select(b => b.key).ToArray()); + longKeys.AddValues(longSet.Select(b => b.key).ToArray()); + + var globalBools = allocator.AllocateList(boolSet.Count); + var globalBytes = allocator.AllocateList(byteSet.Count); + var globalLongs = allocator.AllocateList(longSet.Count); + globalBools.AddValues(boolSet.Select(b => new bit(b.globalVal != 0)).ToArray()); + globalBytes.AddValues(byteSet.Select(b => (short)b.globalVal).ToArray()); + globalLongs.AddValues(longSet.Select(b => b.globalVal).ToArray()); + var globalBoolResults = allocator.AllocateList(boolSet.Count); + var globalByteResults = allocator.AllocateList(byteSet.Count); + var globalLongResults = allocator.AllocateList(longSet.Count); + + var participantBools = allocator.AllocateList(boolSet.Count); + var participantBytes = allocator.AllocateList(byteSet.Count); + var participantLongs = allocator.AllocateList(longSet.Count); + participantBools.AddValues(boolSet.Select(b => new bit(b.participantVal != 0)).ToArray()); + participantBytes.AddValues(byteSet.Select(b => (short)b.participantVal).ToArray()); + participantLongs.AddValues(longSet.Select(b => b.participantVal).ToArray()); + var participantBoolResults = allocator.AllocateList(boolSet.Count); + var participantByteResults = allocator.AllocateList(byteSet.Count); + var participantLongResults = allocator.AllocateList(longSet.Count); + + var participantId = (nint)(CurrentParticipantId << 16); + + this.PrepareForPersistenceCalls(); + + // Clear overrides + process.CallFunction(this.offsets.Persistence_BatchRemoveBoolKeyOverrides, 0x0, DiscardList(), boolKeys); + process.CallFunction(this.offsets.Persistence_BatchRemoveByteKeyOverrides, 0x0, DiscardList(), byteKeys); + process.CallFunction(this.offsets.Persistence_BatchRemoveLongKeyOverrides, 0x0, DiscardList(), longKeys); + process.CallFunction(this.offsets.Persistence_BatchRemoveBoolKeyOverrideForParticipant, 0x0, DiscardList(), participantId, boolKeys); + process.CallFunction(this.offsets.Persistence_BatchRemoveByteKeyOverrideForParticipant, 0x0, DiscardList(), participantId, byteKeys); + process.CallFunction(this.offsets.Persistence_BatchRemoveLongKeyOverrideForParticipant, 0x0, DiscardList(), participantId, longKeys); + + // Set new values + process.CallFunction(this.offsets.Persistence_BatchSetBoolKeys, 0x0, globalBoolResults, boolKeys, globalBools); + process.CallFunction(this.offsets.Persistence_BatchSetByteKeys, 0x0, globalByteResults, byteKeys, globalBytes); + process.CallFunction(this.offsets.Persistence_BatchSetLongKeys, 0x0, globalLongResults, longKeys, globalLongs); + process.CallFunction(this.offsets.Persistence_BatchSetBoolKeysForParticipant, 0x0, participantBoolResults, participantId, boolKeys, participantBools); + process.CallFunction(this.offsets.Persistence_BatchSetByteKeysForParticipant, 0x0, participantByteResults, participantId, byteKeys, participantBytes); + process.CallFunction(this.offsets.Persistence_BatchSetLongKeysForParticipant, 0x0, participantLongResults, participantId, longKeys, participantLongs); + + //process.CallFunction(this.offsets.Player_SaveLoadoutToPersistentStorage, participantId); + + allocator.Reclaim(zero: true); + } + + nint DiscardList() + { + // Allocate enough room for list header to get results back in + // Body isn't required as outputs seem to be allocated by the engine? + return allocator.Allocate(BlamEngineList.GetRequiredSize(0).header); + } + } + private void PrepareForPersistenceCalls() { process.Read(this.offsets.PersistenceData_TlsIndexOffset, out int persistenceIndex); @@ -189,6 +294,9 @@ private void PrepareForPersistenceCalls() process.Read(this.offsets.PersistenceUnknown_TlsIndexOffset, out int unknownIndexA); process.SetTlsValue(unknownIndexA, instance.ReadMainTebPointer(unknownIndexA)); + process.Read(this.offsets.PersistenceUnknown2_TlsIndexOffset, out int unknownIndexB); + process.SetTlsValue(unknownIndexB, instance.ReadMainTebPointer(unknownIndexB)); + process.Read(this.offsets.PlayerDatum_TlsIndexOffset, out int playerDatumIndex); process.SetTlsValue(playerDatumIndex, instance.ReadMainTebPointer(playerDatumIndex)); @@ -202,7 +310,7 @@ private void PrepareForPersistenceCalls() this.CurrentParticipantId = participantId; } - public class Entry : INotifyPropertyChanged + public class ProgressionEntry : INotifyPropertyChanged { public string KeyName { get; set; } diff --git a/src/InfiniteTool/GameInterop/InfiniteOffsets.cs b/src/InfiniteTool/GameInterop/InfiniteOffsets.cs index 94cd1c2..ecb033d 100644 --- a/src/InfiniteTool/GameInterop/InfiniteOffsets.cs +++ b/src/InfiniteTool/GameInterop/InfiniteOffsets.cs @@ -1,37 +1,74 @@ -namespace InfiniteTool +using System.Text.Json.Serialization; + +namespace InfiniteTool { public class InfiniteOffsets { - public nint MainThreadEntry { get; set; } = 0x467010; + public nint MainThreadEntry { get; set; } + + public nint Checkpoint_TlsIndexOffset { get; set; } + + public nint RevertFlagOffset { get; set; } + + public nint CheckpointInfoOffset { get; set; } + + public nint PlayerDatum_TlsIndexOffset { get; set; } + public nint ParticipantDatum_TlsIndexOffset { get; set; } + + public nint PersistenceUnknown_TlsIndexOffset { get; set; } + public nint PersistenceUnknown2_TlsIndexOffset { get; set; } + + public nint PersistenceData_TlsIndexOffset { get; set; } + + public nint Persistence_BatchTryCreateKeysFromStrings { get; set; } + + public nint Persistence_BatchGetKeyTypes { get; set; } + + public nint Persistence_BatchGetBoolKeys { get; set; } + + public nint Persistence_BatchGetByteKeys { get; set; } + + public nint Persistence_BatchGetLongKeys { get; set; } + + public nint Persistence_BatchGetBoolKeysForParticipant { get; set; } + + public nint Persistence_BatchGetByteKeysForParticipant { get; set; } + + public nint Persistence_BatchGetLongKeysForParticipant { get; set; } + + public nint Persistence_BatchSetBoolKeys { get; set; } + + public nint Persistence_BatchSetByteKeys { get; set; } + + public nint Persistence_BatchSetLongKeys { get; set; } + + public nint Persistence_BatchSetBoolKeysForParticipant { get; set; } + + public nint Persistence_BatchSetByteKeysForParticipant { get; set; } + + public nint Persistence_BatchSetLongKeysForParticipant { get; set; } + + public nint Persistence_BatchRemoveBoolKeyOverrides { get; set; } + + public nint Persistence_BatchRemoveByteKeyOverrides { get; set; } - public nint Checkpoint_TlsIndexOffset { get; set; } = 0x49DF8BC; + public nint Persistence_BatchRemoveLongKeyOverrides { get; set; } - public nint RevertFlagOffset { get; set; } = 0x44FFEC8; + public nint Persistence_BatchRemoveBoolKeyOverrideForParticipant { get; set; } - public nint CheckpointInfoOffset { get; set; } = 0x4CC1440; // + public nint Persistence_BatchRemoveByteKeyOverrideForParticipant { get; set; } - public nint PlayerDatum_TlsIndexOffset { get; set; } = 0x5194E80; - public nint ParticipantDatum_TlsIndexOffset { get; set; } = 0x5198158; + public nint Persistence_BatchRemoveLongKeyOverrideForParticipant { get; set; } - public nint PersistenceUnknown_TlsIndexOffset { get; set; } = 0x49DF468; - public nint PersistenceData_TlsIndexOffset { get; set; } = 0x52252A0; + public nint Player_SaveLoadoutToPersistentStorage { get; set; } - public nint Persistence_KeysFromStrings_Batch { get; set; } = 0x1497860; - public nint Persistence_GetKeyTypes_Batch { get; set; } = 0x1497A90; + public nint StartLevel { get; set; } - public nint Persistence_GetBools_Batch { get; set; } = 0x1476E90; - public nint Persistence_GetBytes_Batch { get; set; } = 0x1498A70; - public nint Persistence_GetLongs_Batch { get; set; } = 0x1498800; - public nint Persistence_GetBoolsForParticipant_Batch { get; set; } = 0x14771E0; - public nint Persistence_GetBytesForParticipant_Batch { get; set; } = 0x1477630; - public nint Persistence_GetLongsForParticipant_Batch { get; set; } = 0x1477810; + public nint StartLevelAtSpawn { get; set; } - public nint Persistence_SetBoolsForParticipant_Batch { get; set; } = 0x1475160; - public nint Persistence_SetBytesForParticipant_Batch { get; set; } = 0x1475E00; - public nint Persistence_SetLongsForParticipant_Batch { get; set; } = 0x1476AA0; + public nint ResetLevelAtSpawn { get; set; } - public nint StartMap { get; set; } = 0x0; - public nint StartMapAtSpawn { get; set; } = 0x0; - public nint RestartMapAtSpawn { get; set; } = 0x0; + [JsonPropertyName("game_revert")] + public nint GameRevert { get; set; } } } diff --git a/src/InfiniteTool/GameInterop/OffsetProvider.cs b/src/InfiniteTool/GameInterop/OffsetProvider.cs index aadd68f..82359ba 100644 --- a/src/InfiniteTool/GameInterop/OffsetProvider.cs +++ b/src/InfiniteTool/GameInterop/OffsetProvider.cs @@ -7,7 +7,7 @@ namespace InfiniteTool.GameInterop { public interface IOffsetProvider { - InfiniteOffsets GetOffsets(string? version); + InfiniteOffsets GetOffsets(string version); } public class JsonOffsetProvider : IOffsetProvider @@ -23,13 +23,9 @@ public JsonOffsetProvider() this.jsonOptions = options; } - public InfiniteOffsets GetOffsets(string? version) + + public InfiniteOffsets GetOffsets(string version) { - if(version == null) - { - return new InfiniteOffsets(); - } - var file = Path.Combine(Environment.CurrentDirectory, "Data", version, "offsets.json"); try diff --git a/src/InfiniteTool/InfiniteTool.csproj b/src/InfiniteTool/InfiniteTool.csproj index 6fb077b..9fff783 100644 --- a/src/InfiniteTool/InfiniteTool.csproj +++ b/src/InfiniteTool/InfiniteTool.csproj @@ -15,6 +15,8 @@ PreserveNewest + + @@ -32,7 +34,7 @@ - + diff --git a/src/InfiniteTool/Keybinds/KeyBinds.cs b/src/InfiniteTool/Keybinds/KeyBinds.cs index 99e5cf1..831d3f3 100644 --- a/src/InfiniteTool/Keybinds/KeyBinds.cs +++ b/src/InfiniteTool/Keybinds/KeyBinds.cs @@ -1,5 +1,7 @@ using InfiniteTool.WPF; +using System; using System.Collections.Generic; +using System.IO; using System.Windows; using System.Windows.Controls; using System.Windows.Input; @@ -8,17 +10,16 @@ namespace InfiniteTool.Keybinds { public static class KeyBinds { - private static Dictionary bindings = new() - { - ["cp"] = (ModifierKeys.None, Key.F9), - ["revert"] = (ModifierKeys.None, Key.F10), - ["toggleCheckpointSuppression"] = (ModifierKeys.None, Key.F11) - }; + private const string BindingConfigFile = "keybinds.cfg"; + + private static Dictionary bindings = new(); private static ModifierKeys NoRepeat = (ModifierKeys)0x4000; public static void Initialize(Window window, Hotkeys hotkeys) { + LoadBindings(); + var bindables = window.FindChildren - + @@ -76,7 +79,7 @@ - + + + --> diff --git a/src/InfiniteTool/MainWindow.xaml.cs b/src/InfiniteTool/MainWindow.xaml.cs index 9b71cd9..3d5666a 100644 --- a/src/InfiniteTool/MainWindow.xaml.cs +++ b/src/InfiniteTool/MainWindow.xaml.cs @@ -1,8 +1,11 @@ -using InfiniteTool.GameInterop; +using InfiniteTool.Formats; +using InfiniteTool.GameInterop; using InfiniteTool.Keybinds; using Microsoft.Extensions.Logging; using Microsoft.Win32; using PropertyChanged; +using System; +using System.Diagnostics; using System.IO; using System.Windows; @@ -118,20 +121,48 @@ private void saveProgression_Click(object sender, RoutedEventArgs e) if (save.ShowDialog(this) ?? false) { using var file = save.OpenFile(); - using var writer = new StreamWriter(file); - writer.WriteLine("InfiniteProgressV1"); - writer.WriteLine($"ParticipantID:0x{this.Game.Persistence.CurrentParticipantId:X}"); - writer.WriteLine("KeyName,DataType,GlobalValue,ParticipantValue"); - foreach (var entry in this.Game.PersistenceEntries) - { - writer.WriteLine($"{entry.KeyName},{entry.DataType},0x{entry.GlobalValue:X},0x{entry.ParticipantValue:X}"); - } + var progress = new ProgressionData(this.Game.Persistence.CurrentParticipantId, this.Game.PersistenceEntries); + progress.Write(file); + } + } + + private void loadProgression_Click(object sender, RoutedEventArgs e) + { + var open = new OpenFileDialog(); + open.DefaultExt = ".infprog"; + open.AddExtension = true; + open.FileName = "progress.infprog"; + open.DereferenceLinks = false; + open.Filter = "Infinite Progress Files (*.infprog) | *.infprog"; + if (open.ShowDialog(this) ?? false) + { + using var file = open.OpenFile(); + var data = ProgressionData.FromStream(file); + + if (data == null) return; + + this.Game.Persistence.SetProgress(data.Entries); } } private void speedrunPostLights_Click(object sender, RoutedEventArgs e) { + var gameVersion = Game.Instance.GetGameVersion(); + if (gameVersion == null) return; + + var progPath = Path.Combine(Environment.CurrentDirectory, "Data", gameVersion, "lightskip.infprog"); + if (!File.Exists(progPath)) return; + var file = File.OpenRead(progPath); + var data = ProgressionData.FromStream(file); + if (data == null) return; + + this.Game.Persistence.SetProgress(data.Entries); + } + + private void openLogLocation_Click(object sender, RoutedEventArgs e) + { + Process.Start("explorer.exe", string.Format("/select,\"{0}\"", App.LogLocation)); } } }