Beispiel #1
0
        public static void NewGameInit()
        {
            var memory = Randomizer.Memory;

            if (!memory.IsLoadingGame())
            {
                Randomizer.Log("New Game Init", false);
                SaveController.SetAbility(AbilityType.SpiritEdge);
                foreach (UberState s in DefaultUberStates)
                {
                    memory.WriteUberState(s);
                }
                foreach (UberState s in Kuberstates)
                {
                    memory.WriteUberState(s);
                }
                foreach (UberState s in DialogAndRumors)
                {
                    memory.WriteUberState(s);
                }

                if (SeedController.KSDoorsOpen)
                {
                    foreach (UberState s in KeystoneDoors)
                    {
                        memory.WriteUberState(s);
                    }
                }

                if (!AHK.IniFlag("ShowShortCutscenes"))
                {
                    foreach (UberState s in ShortCutscenes)
                    {
                        memory.WriteUberState(s);
                    }
                }

                if (!AHK.IniFlag("ShowLongCutscenes"))
                {
                    foreach (UberState s in LongCutscenes)
                    {
                        memory.WriteUberState(s);
                    }
                }

                if (PsuedoLocs.GAME_START.Pickup().NonEmpty)
                {
                    Randomizer.InputUnlockCallback = () => {
                        PsuedoLocs.GAME_START.Pickup().Grant();
                        InterOp.magic_function();
                        InterOp.save();
                    };
                }

                InterOp.discover_everything();
                InterOp.bind_sword();
                InterOp.save();
                NeedsNewGameInit = false;
            }
        }
Beispiel #2
0
        private static string getZoneHintMessage(ZoneType zone, bool justUnlocked)
        {
            if (zone == ZoneType.Void)
            {
                return($"no hint for Void(area {InterOp.get_player_area()})");
            }
            var items = HintObjects.GetOrElse(zone, new List <Checkable>());
            var found = items.FindAll(i => i.Has());

            if (!justUnlocked && !HaveHintForZone(zone))
            {
                return($"{zone}: {found.Count}/?? key items (Hint not unlocked)");
            }
            if (items.Count > 0)
            {
                var g = found.Count == items.Count ? "$" : "";
                if (found.Count > 0)
                {
                    return($"{zone}: {g}{found.Count}/{items.Count}{g} key items\nfound: {String.Join(", ", found.Select(i => i.DisplayName))}");
                }
                else
                {
                    return($"{zone}: {found.Count}/{items.Count} key items");
                }
            }
            return($"No key items in {zone}");
        }
 public static void InitLupoPrices()
 {
     foreach (var lp in lupoPrices)
     {
         InterOp.set_lupo_area_price(lp.Key, 2 * lp.Value);
     }
 }
Beispiel #4
0
        public static void ProgressWithHints(ZoneType _zone = ZoneType.Void, bool justUnlocked = false)
        {
            int duration = justUnlocked ? 300 : 240;

            if (SeedController.HintsDisabled || InterOp.get_game_state() != GameState.Game)
            {
                if (!justUnlocked)
                {
                    AHK.SendPlainText(new PlainText(SeedController.Progress, duration), justUnlocked);
                }
                return;
            }

            var zone = _zone == ZoneType.Void ? CurrentZone : _zone;
            var msg  = getZoneHintMessage(zone, justUnlocked);

            if (justUnlocked)
            {
                msg = $"Bought hint: {msg}";
            }
            else
            {
                msg = $"{SeedController.Progress}\n{msg}{GetKeySkillHints()}";
            }
            AHK.SendPlainText(new PlainText(msg, duration), justUnlocked);
        }
        private static UberState createUberStateEntry(UberId id)
        {
            if (!InterOp.get_uber_state_exists(id.GroupID, id.ID))
            {
                Randomizer.Error("cuse", $"Failed to find {id} in uber state system.", false);
                return(null);
            }

            byte[] buffer = new byte[256];
            int    len    = InterOp.get_uber_state_name(id.GroupID, id.ID, buffer, buffer.Length);
            string name   = System.Text.Encoding.ASCII.GetString(buffer, 0, len);

            len = InterOp.get_uber_state_group_name(id.GroupID, id.ID, buffer, buffer.Length);
            string groupName = System.Text.Encoding.ASCII.GetString(buffer, 0, len);

            var s = new UberState()
            {
                ID        = id.ID,
                GroupID   = id.GroupID,
                Name      = name,
                GroupName = groupName,
                Type      = InterOp.get_uber_state_type(id.GroupID, id.ID),
            };

            s.Value = CreateValue(s.Type, InterOp.get_uber_state_value(id.GroupID, id.ID));
            return(s);
        }
        public static void Init()
        {
            Engine.ExecRaw(Program);

            Ready = true;
            bool cursorLock   = IniFlag("CursorLock");
            bool disableDebug = IniFlag("DisableDebugControls");

            if (cursorLock || disableDebug)
            {
                Randomizer.TitleScreenCallback = () => {
                    if (disableDebug)
                    {
                        Randomizer.Memory.Debug = false;
                    }
                    if (cursorLock)
                    {
                        InterOp.toggle_cursorlock();
                    }
                };
            }

            if (IniFlag("dev"))
            {
                Randomizer.Dev = true;
            }
        }
 public TrackData()
 {
     if (TrackFileController.DontTrackYet)
     {
         keystones   = 0;
         spiritLight = 0;
         ore         = 0;
         skills      = new HashSet <String>();
         upgraded    = new HashSet <String>();
         events      = new HashSet <String>();
         teleporters = new HashSet <String>();
     }
     try {
         keystones   = InterOp.get_keystones();
         spiritLight = InterOp.get_experience();
         ore         = InterOp.get_ore();
         skills      = SaveController.SkillsFound.Select((AbilityType type) => trackName(type)).ToHashSet();
         upgraded    = SaveController.UpgradedWeapons.Select((AbilityType type) => $"{type.GetDescription().Replace(" ", "")}").ToHashSet();
         if (SaveController.HasAbility(AbilityType.DamageUpgrade1) && SaveController.HasAbility(AbilityType.DamageUpgrade2))
         {
             upgraded.Add(trackName(AbilityType.DamageUpgrade1));
         }
         events      = SaveController.WorldEvents.Select((QuestEventType type) => type.GetDescription()).ToHashSet();
         teleporters = Teleporter.TeleporterStates.Keys.Where((TeleporterType t) => (new Teleporter(t)).Has()).Select((TeleporterType t) => t.GetDescription()).ToHashSet();
     }
     catch (Exception e) {
         Randomizer.Error("TrackData()", e);
     }
 }
Beispiel #8
0
        public static void Init()
        {
            Engine.ExecRaw(Program);
            Engine.ExecRaw(Binds);

            Ready = true;
            bool cursorLock   = IniFlag("CursorLock");
            bool disableDebug = IniFlag("DisableDebugControls");

            if (cursorLock || disableDebug)
            {
                Randomizer.TitleScreenCallback = () => {
                    if (disableDebug)
                    {
                        InterOp.set_debug_controls(false);
                    }
                    if (cursorLock)
                    {
                        InterOp.toggle_cursorlock();
                    }
                };
            }

            if (IniFlag("dev"))
            {
                Randomizer.Dev = true;
            }
            int maxLogLines = Randomizer.Dev ? 1000 : 100;
            var logLines    = File.ReadAllLines(Randomizer.LogFile);

            if (logLines.Length > maxLogLines)
            {
                File.WriteAllLines(Randomizer.LogFile, logLines.Skip(logLines.Length / 2));
            }
        }
Beispiel #9
0
        public static void Update()
        {
            try {
                RVAFinder.Update();
                if (!Memory.IsHooked)
                {
                    Memory.HookProcess();
                }

                if (Memory.GameState == GameState.TitleScreen)
                {
                    if (TitleScreenCallback != null)
                    {
                        OnTitleScreen();
                    }
                    UberStateController.SkipListenersNextUpdate = true;
                }
                else if (Memory.GameState == GameState.Game)
                {
                    UberStateController.Update();
                    if (InputUnlockCallback != null && InterOp.player_can_move())
                    {
                        OnInputUnlock();
                    }
                    SeedController.UpdateGoal();
                    TrackFileController.Update();
                }
                AHK.Tick();
            } catch (Exception e) {
                Log($"Update error: {e.Message}\n{e.StackTrace}");
            }
        }
 public static void Update()
 {
     try {
         var gs = InterOp.get_game_state();
         if (gs == GameState.TitleScreen)
         {
             UberStateController.SkipListeners = true;
             if (TitleScreenCallback != null)
             {
                 OnTitleScreen();
             }
         }
         else if (gs == GameState.Game)
         {
             UberStateController.SkipListeners = false;
             UberStateController.Update();
             if (InputUnlockCallback != null && InterOp.player_can_move())
             {
                 OnInputUnlock();
             }
             SeedController.UpdateGoal();
             TrackFileController.Update();
         }
         AHK.Tick();
         BonusItemController.Update();
         DiscordController.Update();
         Client.Update();
     } catch (Exception e) {
         Log($"Update error: {e.Message}\n{e.StackTrace}");
     }
 }
 public static void UpdateReachable(int sleepTime = 30)
 {
     if (InterOp.get_game_state() == GameState.Game)
     {
         var t = new Thread(() => UpdateReachableAsync(sleepTime));
         t.Start();
     }
 }
        public static int Bootstrap(string dllPath)
        {
            if (!Initialize())
            {
                return(1);
            }

            InterOp.RegisterCSharpBindings();
            return(0);
        }
Beispiel #13
0
        public static void OnMapPan(AreaType type)
        {
            if (SeedController.HintsDisabled)
            {
                return;
            }
            var msg = getZoneHintMessage(type.toZone(), false) + GetKeySkillHints();

            if (msg.Count(c => c == '\n') == 2) // if there's exactly 3 lines, insert an extra linebreak at the top
            {
                msg = "\n" + msg;               // so the middle text isn't obscured by the filter button
            }
            InterOp.update_map_hint(msg);
        }
Beispiel #14
0
        public static void Update()
        {
            float h = InterOp.get_uber_state_value(4, (int)BonusType.HealthRegen);

            if (h > 0)
            {
                InterOp.add_health(h * 0.0028f);
            }
            float e = InterOp.get_uber_state_value(4, (int)BonusType.EnergyRegen);

            if (e > 0)
            {
                InterOp.add_energy(e * 0.00028f);
            }
        }
 public virtual void Grant(bool skipBase = false)
 {
     if (skipBase)
     {
         return;
     }
     if (Frames > 0)
     {
         AHK.Pickup(ToString(), Frames);
     }
     SaveController.Data.FoundCount++;
     if (NeedsMagic())
     {
         InterOp.magic_function();
     }
 }
Beispiel #16
0
        public static void SetAbility(AbilityType ability, bool setTo = true)
        {
            if (setTo)
            {
                Data.SkillsFound.Add(ability);
            }
            else
            {
                Data.SkillsFound.Remove(ability);
            }

            InterOp.set_ability(ability, setTo);
            if (ability.Equip().HasValue)
            {
                InterOp.set_equipment(ability.Equip().Value, setTo);
            }

            TrackFileController.Write();
        }
 public static void Update()
 {
     if (InterOp.get_game_state() == GameState.Game)
     {
         DontTrackYet = false;
     }
     if (IgnoreUpdateFrames > 0)
     {
         IgnoreUpdateFrames--;
         return;
     }
     try {
         if (Last == null || Last.ore != InterOp.get_ore() || Last.spiritLight != InterOp.get_experience())
         {
             Write();
         }
     } catch (Exception e) {
         Randomizer.Error("Track.Update", e);
         Randomizer.Log($"Last: {Last}", false);
     }
 }
        public static void Update()
        {
            try {
                if (NeedsNewGameInit)
                {
                    NewGameInit();
                }

                if (!SkipListeners)
                {
                    // We do ToArray here so we can change the hashset while we are looping.
                    foreach (var state in TickingUberStates.ToArray())
                    {
                        // Maybe change this to use our own cache lookup?
                        var value = InterOp.get_uber_state_value(state.GroupID, state.ID);
                        InterOp.set_uber_state_value(state.GroupID, state.ID, value + 1);
                    }
                }

                if (FullSyncNextUpdate)
                {
                    FullSyncNextUpdate = false;
                    Randomizer.Client.SendBulk(SyncedUberStates.Where(uid => uid.State() != null).ToDictionary(uid => uid, (uid) => uid.State().ValueAsFloat()));
                    var bad = SyncedUberStates.Where(uid => uid.State() == null).ToList();
                    foreach (var baduid in bad)
                    {
                        SyncedUberStates.Remove(baduid);
                    }
                }
                while (Randomizer.Client.UberStateQueue.TryTake(out var stateUpdate))
                {
                    var(id, val) = stateUpdate.FromNet();
                    if (id.State().ValueAsFloat() != val)
                    {
                        InterOp.set_uber_state_value(id.GroupID, id.ID, val);
                    }
                }
            }
            catch (Exception e) { Randomizer.Error("USC.Update", e, false); }
        }
Beispiel #19
0
        public static void Tick()
        {
            var signal = Engine.ExecFunction("Tick");

            if (signal != null && signal != "none")
            {
                Engine.SetVar("signal", "none");
                HandleSignal(signal);
            }
            FramesTillUnlockReload = Math.Max(0, FramesTillUnlockReload - 1);
            if (FramesTillNextSend > 0)
            {
                FramesTillNextSend--;
            }
            else
            {
                if (CanPrint)
                {
                    Current            = MessageQueue.Peek();
                    FramesTillNextSend = Current.Frames;
                    try {
                        if (Current.Clear)
                        {
                            InterOp.clear_visible_hints();
                        }
                        InterOp.display_hint(Current.Text, Current.Frames / 60f, Current.Pos, Current.Mute);
                        if (IniFlag("LogOnPrint"))
                        {
                            Randomizer.Log($"Sending {Current.Text} for {Current.Frames} ({MessageQueue.Count} remaining in queue)", false);
                        }
                        MessageQueue.Dequeue();
                    } catch (Exception e) { Randomizer.Error("AHK.sendMsg", e, false); }
                }
                else
                {
                    Current = null;
                }
            }
        }
 public static void PopulateUberStates()
 {
     uberStateLookup = new Dictionary <UberId, UberState>();
     unsafe {
         var size   = 0;
         var states = InterOp.get_uber_states(ref size);
         for (var i = 0; i < size; ++i)
         {
             var def       = states[i];
             var name      = Marshal.PtrToStringAnsi(def.Name);
             var groupName = Marshal.PtrToStringAnsi(def.GroupName);
             uberStateLookup.Add(new UberId(def.GroupID, def.ID), new UberState()
             {
                 ID        = def.ID,
                 GroupID   = def.GroupID,
                 Name      = name,
                 GroupName = groupName,
                 Type      = def.Type
             });
         }
     }
 }
 private static void HandleSpecial(UberState state)
 {
     if (state.Name == "arenaBByteStateSerialized" && state.Value.Byte == 4)
     {
         // lumaPoolsStateGroup.arenaByteStateSerialized
         new UberId(5377, 1373).State().Write(state.Value);
     }
     else if (state.Name == "craftCutsceneState" && 0 < state.Value.Byte && state.Value.Byte < 3)
     {
         state.Write(new UberValue((byte)3));
         // Give diamond in the rough pickup.
         new UberId(23987, 14832).State().Write(new UberValue(true));
     }
     // the below is a fix for a vanilla bug where you can just miss getting voice if you
     else if (state.Name == "findToadQuestUberState" && state.Value.Int == 2 ||       // (a) skip the kwolok cutscene too fast
              state.Name == "cleanseWellspringQuestUberState" && state.Value.Int == 4 // (b) come to kwolok after wellspring and get the cutscenes stacked awkwardly
              )
     {
         Randomizer.InputUnlockCallback = () => {
             // this is really questionable!!
             var voiceState = new UberId(46462, 59806).State();
             if (!voiceState.Value.Bool)
             {
                 voiceState.Write(new UberValue(true));
                 InterOp.set_max_health(InterOp.get_max_health() + 10);
                 InterOp.set_max_energy(InterOp.get_max_energy() + 1);
                 InterOp.fill_health();
                 InterOp.fill_energy();
                 InterOp.save();
             }
             // should happen in both branches
             if (SeedController.Flags.Contains(Flag.ALLWISPS))
             {
                 HintsController.ProgressWithHints();
             }
         }
     }
     ;
 }
Beispiel #22
0
 public static void OnLoad(int slot, int backupSlot = -1)
 {
     try {
         if (slot != CurrentSlot)
         {
             if (Randomizer.InputUnlockCallback != null)
             {
                 AHK.Print("Warning: Callback overwritten on slot change!", 240);
                 Randomizer.InputUnlockCallback = null;
             }
             // slot swap
             CurrentSlot = slot;
             Data        = new SaveData(slot);
         }
         UberStateController.SkipListenersNextUpdate = true;
         Data.Load(backupSlot);
         if (DidWeJustDie)
         {
             InterOp.magic_function();
         }
     }
     catch (Exception e) { Randomizer.Error("SaveCont.OnLoad", e); }
 }
 public static void Refresh(this UberId id) => InterOp.refresh_uber_state(id.GroupID, id.ID);
Beispiel #24
0
        public static void HandleSignal(string signal)
        {
            switch (signal)
            {
            case "reload":
                if (FramesTillUnlockReload == 0)
                {
                    iniFlagCache.Clear();
                    FramesTillNextSend = 0;
                    Randomizer.Client.Connect();
                    SeedController.ReadSeed();
                    if (InterOp.get_game_state() == GameState.Game)
                    {
                        PsuedoLocs.RELOAD_SEED.OnCollect();
                    }
                    FramesTillUnlockReload = 120;
                }
                break;

            case "lastPickup":
                FramesTillNextSend = 1; // the only reason this isn't = 0 is that spamming this could get really annoying
                MessageQueue.Enqueue(Last);
                break;

            case "progressAndHints":
                HintsController.ProgressWithHints();
                break;

            case "dev":
                Randomizer.Dev = !Randomizer.Dev;
                Randomizer.Log($"Dev: {Randomizer.Dev}");
                break;

            case "exitapp":
                Environment.Exit(Environment.ExitCode);
                break;

            case "toggleDebug":
                InterOp.set_debug_controls(!InterOp.get_debug_controls());
                Print($"Debug {(InterOp.get_debug_controls() ? "enabled" : "disabled")}", toMessageLog: false);
                break;

            case "toggleCursorLock":
                Print($"Cursor Lock {(InterOp.toggle_cursorlock() ? "enabled" : "disabled")}", toMessageLog: false);
                break;

            case "binding1":
                PsuedoLocs.BINDING_ONE.OnCollect();
                break;

            case "binding2":
                PsuedoLocs.BINDING_TWO.OnCollect();
                break;

            case "binding3":
                PsuedoLocs.BINDING_THREE.OnCollect();
                break;

            case "binding4":
                PsuedoLocs.BINDING_FOUR.OnCollect();
                break;

            case "binding5":
                PsuedoLocs.BINDING_FIVE.OnCollect();
                break;

            case "unlockSpoiers":
                if (SeedController.Settings.RaceMode)
                {
                    return;                             // no cheat
                }
                UberSet.Bool(GameComplete, true);
                Print("spoiler unlocked", toMessageLog: false);
                break;

            case "tpCheat":
                if (SeedController.Settings.RaceMode)
                {
                    return;                             // no cheat
                }
                tpCheatToggle = !tpCheatToggle;
                Print($"TPCheat {(tpCheatToggle ? "enabled" : "disabled")}", toMessageLog: false);
                break;

            case "warpCredits":
                if (UberGet.Bool(GameComplete))
                {
                    InterOp.start_credits();
                }
                else
                {
                    Print($"Credit warp not unlocked!", toMessageLog: false);
                }
                break;

            case "printCoords":
                var pos = InterOp.get_position();
                Print($"{pos.X}, {pos.Y}", toMessageLog: false);
                break;

            case "nameSpoilerToggle":
                MapController.NameLabels = !MapController.NameLabels;
                Print($"Loc name labels {(MapController.NameLabels ? "enabled" : "disabled")}", toMessageLog: false);
                break;

            case "logicprovidertoggle":
                MapController.RustLogic = !MapController.RustLogic;
                Print($"Logic Provider: {(MapController.RustLogic ? "Rust" : "Java")}", toMessageLog: false);
                MapController.UpdateReachable();
                break;

            default:
                Randomizer.Log($"Recieved unknown signal {signal}");
                break;
            }
        }
        public static void Tick()
        {
            var signal = Engine.ExecFunction("Tick");

            if (signal != null && signal != "none")
            {
                Engine.SetVar("signal", "none");
                switch (signal)
                {
                case "reload":
                    if (FramesTillUnlockReload == 0)
                    {
                        FramesTillNextSend = 0;
                        SeedController.ReadSeed();
                        Randomizer.Memory.OnInit();
                        if (Randomizer.Memory.GameState == Memory.GameState.Game)
                        {
                            PsuedoLocs.RELOAD_SEED.Pickup().Grant();
                        }
                        FramesTillUnlockReload = 60;
                    }
                    break;

                case "lastPickup":
                    FramesTillNextSend = 1; // the only reason this isn't = 0 is that spamming this could get really annoying
                    MessageQueue.Enqueue(Last);
                    break;

                case "hintMessage":
                    HintsController.ShowHintMessage();
                    break;

                case "dev":
                    Randomizer.Dev = !Randomizer.Dev;
                    Randomizer.Log($"Dev: {Randomizer.Dev}");
                    break;

                case "exitapp":
                    Environment.Exit(Environment.ExitCode);
                    break;

                case "toggleDebug":
                    Randomizer.Memory.Debug = !Randomizer.Memory.Debug;
                    Print($"Debug {(Randomizer.Memory.Debug ? "enabled" : "disabled")}", toMessageLog: false);
                    break;

                case "toggleCursorLock":
                    Print($"Cursor Lock {(InterOp.toggle_cursorlock() ? "enabled" : "disabled")}", toMessageLog: false);
                    break;

                case "test1":
                    PsuedoLocs.BINDING_ONE.Pickup().Grant();
                    break;

                case "test2":
                    PsuedoLocs.BINDING_TWO.Pickup().Grant();
                    break;

                case "test3":
                    PsuedoLocs.BINDING_THREE.Pickup().Grant();
                    break;

                case "test4":
                    Print("magic", 180, false);
                    InterOp.magic_function();
                    break;

                case "test5":
                    tpCheatToggle = !tpCheatToggle;
                    Print($"TPCheat {(tpCheatToggle ? "enabled" : "disabled")}");
                    break;

                default:
                    Randomizer.Log($"Recieved unknown signal {signal}");
                    break;
                }
            }
            FramesTillUnlockReload = Math.Max(0, FramesTillUnlockReload - 1);
            if (FramesTillNextSend > 0)
            {
                FramesTillNextSend--;
            }
            else
            {
                if (CanPrint)
                {
                    Current            = MessageQueue.Peek();
                    FramesTillNextSend = Current.Frames;
                    try {
                        InterOp.clear_visible_hints();
                        InterOp.display_hint(InterOp.Util.getIl2cppStringPointer(Current.Text), Current.Frames / 60f);
                        if (IniFlag("LogOnPrint"))
                        {
                            Randomizer.Log($"Sending {Current.Text} for {Current.Frames} ({MessageQueue.Count} remaining in queue)", false);
                        }
                        MessageQueue.Dequeue();
                    } catch (Exception e) { Randomizer.Error("AHK.sendMsg", e, false); }
                }
                else
                {
                    Current = null;
                }
            }
        }
Beispiel #26
0
        public bool Met()
        {
            var value = InterOp.get_uber_state_value(Id.GroupID, Id.ID);

            return(Target.HasValue ? Target.Value >= value : value > 0);
        }
        public static void UpdateReachableAsync(int sleepTime = 30)
        {
            try {
                Thread.Sleep(sleepTime); // wait to let values update
                if (Updating)
                {
                    return;
                }
                Updating = true;
                var argsList = RustLogic ? new List <string> {
                    "reach-check",
                    // TODO maybe we won't pass these explicitly? since it's samefolder shit
                    "--areas",
                    $"\"{Randomizer.BasePath}areas.wotw\"",
                    "--locations",
                    $"\"{Randomizer.BasePath}loc_data.csv\"",
                    "--uber-states",
                    $"\"{Randomizer.BasePath}state_data.csv\"",
                } : new List <string> {
                    "-jar",
                    $"\"{Randomizer.BasePath}SeedGen.jar\" ",
                    "ReachCheck"
                };
                argsList.AddRange(new List <string> {
                    $"\"{SeedController.SeedFile}\"",
                    $"{InterOp.get_max_health()}",
                    $"{Convert.ToInt32(10*InterOp.get_max_energy())}",
                    $"{UberGet.value(6, 0).Int}",
                    $"{InterOp.get_ore()}",
                    $"{InterOp.get_experience()}",
                });
                if (RustLogic)
                {
                    argsList.AddRange(TrackedConds.Where(c => c.Met()).Select(t => $"u:{t.Id.GroupID},{t.Id.ID}"));
                }
                argsList.AddRange(SaveController.SkillsFound.Select((AbilityType at) => $"s:{(int)at}"));
                argsList.AddRange(Teleporter.TeleporterStates.Keys.Where(t => new Teleporter(t).Has()).Select(t => $"t:{(int)t}"));
                if (new QuestEvent(QuestEventType.Water).Has())
                {
                    argsList.Add("w:0");
                }
                argsList.AddRange(TrackedShards.Where(sh => new Shard(sh).Has()).Select(t => $"sh:{(int)t}"));
                var proc = new System.Diagnostics.Process();
                proc.StartInfo.FileName               = RustLogic ? @"seedgen.exe" : @"java.exe";
                proc.StartInfo.Arguments              = String.Join(" ", argsList);
                proc.StartInfo.CreateNoWindow         = true;
                proc.StartInfo.UseShellExecute        = false;
                proc.StartInfo.RedirectStandardOutput = true;
                proc.StartInfo.RedirectStandardError  = true;
                proc.StartInfo.WorkingDirectory       = Randomizer.BasePath;
                proc.Start();
                if (!proc.WaitForExit(10000))
                {
                    Randomizer.Warn("MapController.waitForProc", "timed out waiting for reach check", false);
                }
                Reachable.Clear();
                var rawOutput = proc.StandardOutput.ReadToEnd();
                if (rawOutput.Trim() != "")
                {
                    foreach (var rawCond in rawOutput.Split(','))
                    {
                        try {
                            var frags = rawCond.Split('|');
                            var cond  = new UberStateCondition(int.Parse(frags[0]), frags[1]);
                            if (cond.Loc().Type == LocType.Shop)
                            {
                                if (cond.Met() || hintTypes.Contains(cond.Pickup().Type))
                                {
                                    continue; // bought it or it's a hint. Either way it's known to be non progression, so it does not show on the map
                                }
                                if (ShopSlot.Twillen.Any(e => e.State.Equals(cond.Id)))
                                {
                                    Reachable.Add(new UberStateCondition(2, "20000"));
                                }
                                else if (ShopSlot.Opher.Any(e => e.State.Equals(cond.Id)))
                                {
                                    Reachable.Add(new UberStateCondition(1, "20000"));
                                }
                                else if (ShopSlot.LupoStore.Any(e => e.State.Equals(cond.Id)))
                                {
                                    Reachable.Add(new UberStateCondition(48248, "20000"));
                                }
                            }
                            Reachable.Add(cond);
                        }
                        catch (Exception e) { Randomizer.Error($"GetReachableAsync (post-return) while parsing |{rawCond}|", e); }
                    }
                }

                /*
                 * if(Randomizer.Dev)
                 * Randomizer.Log($"Reach check:\nseed_gen_cli.exe {String.Join(" ", argsList)}\n gave output: \n{rawOutput}\n stderr was {proc.StandardError.ReadToEnd()}\nReachable after: {String.Join(" ", Reachable.Select(r => r.ToString()))}", false);
                 */
                InterOp.refresh_inlogic_filter();
            }
            catch (Exception e) { Randomizer.Error("GetReachableAsync", e); }
            Updating = false;
        }
        public static void NewGameInit()
        {
            if (!InterOp.is_loading_game())
            {
                InterOp.clear_quest_messages();
                Randomizer.Log($"New Game Init - {SeedController.SeedName}", false);
                ShopController.SetCostsAfterInit();

                foreach (UberState s in DefaultUberStates)
                {
                    s.Write();
                }
                foreach (UberState s in Kuberstates)
                {
                    s.Write();
                }
                foreach (UberState s in DialogAndRumors)
                {
                    s.Write();
                }

                if (SeedController.KSDoorsOpen)
                {
                    foreach (UberState s in KeystoneDoors)
                    {
                        s.Write();
                    }
                }

                if (!AHK.IniFlag("ShowShortCutscenes"))
                {
                    foreach (UberState s in ShortCutscenes)
                    {
                        s.Write();
                    }
                }

                if (!AHK.IniFlag("ShowLongCutscenes"))
                {
                    foreach (UberState s in LongCutscenes)
                    {
                        s.Write();
                    }
                }

                InterOp.discover_everything();
                if (SeedController.Settings.LegacySeedgen && !SeedController.Flags.Contains(Flag.NOSWORD))
                {
                    SaveController.SetAbility(AbilityType.SpiritEdge);
                    var slotRaw = AHK.IniString("Misc", "SpawnSlot");
                    var slot    = 0;
                    if (slotRaw != string.Empty)
                    {
                        slot = slotRaw.ParseToInt("Spawn Slot Ini") - 1;
                        if (slot > 2 || slot < 0)
                        {
                            AHK.Print($"Ignoring invalid slot specifier {slotRaw}", toMessageLog: false);
                            slot = 0;
                        }
                    }
                    InterOp.bind(slot, 1002);
                }
                if (PsuedoLocs.GAME_START.Pickup().NonEmpty)
                {
                    Randomizer.InputUnlockCallback = () => {
                        MapController.UpdateReachable(2000);
                        PsuedoLocs.GAME_START.OnCollect();
                        InterOp.save();
                    };
                }
                else
                {
                    MapController.UpdateReachable();
                }
                InterOp.set_shard_slots(3);
                InterOp.save();

                NeedsNewGameInit = false;
            }
        }
 public static void HandleSyncedUberStateChange(UberId id, float value)
 {
     InterOp.set_uber_state_value(id.GroupID, id.ID, value);
 }
        public static bool Initialize()
        {
            try {
                if (logThread == null)
                {
                    logThread = new Thread(() => {
                        while (true)
                        {
                            try {
                                var txt = logQueue.Take();
                                while (logQueue.TryTake(out var line))
                                {
                                    txt += line;
                                }
                                File.AppendAllText(LogFile, txt);
                            } catch (Exception e) {
                                if (Dev)
                                {
                                    AHK.Print($"error logging: {e}", toMessageLog: false);
                                }
                            }
                        }
                    });
                    logThread.Start();
                }

                BasePath = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(InterOp.get_base_path());
                Debug($"Init: set base path to {BasePath}");

                if (!Directory.Exists(SaveFolder))
                {
                    Directory.CreateDirectory(SaveFolder);
                }

                if (!File.Exists(SeedPathFile))
                {
                    File.WriteAllText(SeedPathFile, BasePath + ".currentseed");
                }

                foreach (var fileName in new string[] { LogFile, MessageLog })
                {
                    if (!File.Exists(fileName))
                    {
                        File.WriteAllText(fileName, "");
                        Log($"Wrote blank {fileName} (normal for first-time init)");
                    }
                }

                AHK.Init();
                SeedController.ReadSeed(true);

                Client.UberStateRegistered = UberStateController.RegisterSyncedUberState;
                DiscordController.Initialize();

                Debug("Init: Complete", false);
                return(true);
            } catch (Exception e) {
                Log($"init error: {e.Message}\n{e.StackTrace}");
                return(true);
            }
        }