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 = ShopController.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(); quests = UberStateController.Quests.Where((UberState s) => s.ValueOr(new UberValue(0)).Int == s.Value.Int).Select(s => s.Name).ToHashSet(); teleporters = Teleporter.TeleporterStates.Keys.Where((TeleporterType t) => (new Teleporter(t)).Has()).Select((TeleporterType t) => t.GetDescription()).ToHashSet(); flags = SeedController.Flags.Select(s => s.GetDescription()).ToHashSet(); } catch (Exception e) { Randomizer.Error("TrackData()", e); } }
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 Update() { if (NeedsNewGameInit) { NewGameInit(); } bool SkipListners = SkipListenersNextUpdate; SkipListenersNextUpdate = false; var memory = Randomizer.Memory; Dictionary <long, UberState> uberStates = memory.GetUberStates(); foreach (KeyValuePair <long, UberState> pair in uberStates) { try { UberState state = pair.Value; UberId key = state.GetUberId(); if (UberStates.TryGetValue(key, out UberState oldState)) { UberValue value = state.Value; UberValue oldValue = oldState.Value; if (value.Int != oldValue.Int) { var oldValFmt = oldState.FmtVal(); // get this now because we overwrite the value by reference if (ShouldRevert(state)) { Randomizer.Log($"Reverting state change of {state.Name} from {oldValFmt} to {state.FmtVal()}", false); memory.WriteUberState(oldState); continue; } HandleSpecial(state); UberStates[key].Value = state.Value; if (!SkipListners) { var pos = Randomizer.Memory.Position(); bool found = false; if (value.Int > 0) { found = SeedController.OnUberState(state); } if ((value.Int == 0 || !found) && !(state.GroupName == "statsUberStateGroup" || state.GroupName == "achievementsGroup")) { Randomizer.Log($"State change: {state.Name} {state.ID} {state.GroupName} {state.GroupID} {state.Type} {state.FmtVal()} (was {oldValFmt}, pos ({Math.Round(pos.X)},{Math.Round(pos.Y)}) )", false); } } } } else { UberStates[key] = state.Clone(); } } catch (Exception e) { Randomizer.Error($"USC.Update {pair}", e); } } }
public static void RegisterCheckable(CheckableHint ch) { if (nextCheckable == 20) { Randomizer.Error("HC.RegisterCheckable", "Max 10 checkable hints supported"); return; } CheckableHints[ch] = new UberId(6, nextCheckable++); }
public static void PopulateTrackedConds() { try { foreach (var line in File.ReadAllLines(Randomizer.BasePath + "state_data.csv")) { var data = line.Split(','); _trackedConds.Add(new UberStateCondition(data[1].ParseToInt("PopulateTrackedConds.GID"), data[2])); } } catch (Exception e) { Randomizer.Error("PopulateTrackedConds", e); } }
public static void OnLoad(int slot) { try { if (slot != CurrentSlot) { // slot swap CurrentSlot = slot; Data = new SaveData(slot); } Data.Load(); } catch (Exception e) { Randomizer.Error("OnLoad", e); } }
public static void Update() { try { discord?.RunCallbacks(); } catch (Exception e) { if (e is NullReferenceException) { return; } Randomizer.Error("Discord callbacks", e, false); } }
public static void Init() { try { if (File.Exists(targetsFile)) { using (var sr = new StreamReader(targetsFile)) using (JsonReader reader = new JsonTextReader(sr)) { var serializer = new JsonSerializer(); relevantRVAs = serializer.Deserialize <Dictionary <String, UInt64> >(reader); } } } catch (Exception e) { Randomizer.Error("RVAFinder.Init", e); } }
public static void OnTeleporterActivated(String identifier) { try { if (identifier == "kwoloksCavernSaveRoomA") { (HintsController.CurrentZone == ZoneType.Glades ? TeleporterType.Glades : TeleporterType.Hollow).p().Grant(true); } else { TpsByID[identifier].p().Grant(true); } } catch (Exception e) { Randomizer.Error($"OTA, key of {identifier}", e); } }
public static void Write() { try { Last = new TrackData(); if (File.Exists(trackFilePath)) { File.Delete(trackFilePath); } using (var sw = new StreamWriter(trackFilePath)) sw.Write(JsonConvert.SerializeObject(Last)); IgnoreUpdateFrames = 5; } catch (IOException) { // that's fine } catch (Exception e) { Randomizer.Error("TrackFile.Write:", e); // less fine! } }
public static void OnNewGame(int slot) { try { // overwrite the message log TODO: save a backup maybe? File.WriteAllText(Randomizer.MessageLog, ""); SeedController.ReadSeed(); UberStateController.NeedsNewGameInit = true; UberStateController.UberStates.Clear(); UberStateController.TickingUberStates.Clear(); AHK.OnNewGame(); SaveController.NewGame(slot); BonusItemController.Refresh(); Client.Connect(); } catch (Exception e) { Randomizer.Error("OnNewGame", e); } }
public TrackData() { try { keystones = Randomizer.Memory.Keystones; spiritLight = Randomizer.Memory.Experience; ore = Randomizer.Memory.Ore; skills = SaveController.Data.SkillsFound.Select((AbilityType type) => trackName(type)).ToHashSet(); upgraded = SaveController.Data.OpherUpgraded.Keys.Select((AbilityType type) => $"{type.GetDescription().Replace(" ", "")}").ToHashSet(); if (SaveController.HasAbility(AbilityType.DamageUpgrade1) && SaveController.HasAbility(AbilityType.DamageUpgrade2)) { upgraded.Add(trackName(AbilityType.DamageUpgrade1)); } events = SaveController.Data.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); } }
public static void Initialize() { Disabled = AHK.IniFlag("DisableNetcode"); if (Disabled) { Randomizer.Log("Netcode disabled, skipping discord init", false, "DEBUG"); return; } if (InitRunning) { Randomizer.Log("Init running already, skipping", false, "DEBUG"); return; } InitRunning = true; new Thread(() => { try { if (discord == null) { discord = new Discord.Discord(CLIENT_ID, (UInt64)CreateFlags.Default); } if (UserManager == null) { UserManager = discord.GetUserManager(); } if (ApplicationManager == null) { ApplicationManager = discord.GetApplicationManager(); } Initialized = true; if (GetUser() != null) { Randomizer.Log("User already known, skipping rest of discord init", false, "DEBUG"); Randomizer.Client.Connect(); return; } discord.SetLogHook(LogLevel.Debug, (level, message) => Randomizer.Log($"discord: {message}", level.CompareTo(LogLevel.Info) > 0, level.ToString())); UserManager.OnCurrentUserUpdate += DiscordInitComplete; } catch (Exception e) { Randomizer.Error("DiscInitThread", e); } InitRunning = false; }).Start(); }
public static void Update() { try { if (needWrite) { if (File.Exists(targetsFile)) { File.Delete(targetsFile); } using (var sw = new StreamWriter(targetsFile)) using (JsonWriter writer = new JsonTextWriter(sw)) { writer.Formatting = Formatting.Indented; var serializer = new JsonSerializer(); serializer.Serialize(writer, relevantRVAs); } needWrite = false; } } catch (Exception e) { Randomizer.Error("RVAFinder.Update", e); } }
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 bool HaveHintForZone(ZoneType zone) { try { if (zone == ZoneType.Void) { return(false); } if (ZoneToState.TryGetValue(zone, out UberState state)) { return(state.GetValue().Bool); } else { return(false); } } catch (Exception e) { Randomizer.Error("Hints.HaveHintForZone", e, false); return(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); } }
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 ulong rvaLookup(string sig, bool fromDump = false) { if (fromDump) { if (dumpRVAs.Count == 0) { populateAllRVAs(); relevantRVAs.Clear(); } if (dumpRVAs.ContainsKey(sig)) { relevantRVAs[sig] = dumpRVAs[sig]; needWrite = true; } } if (!relevantRVAs.ContainsKey(sig)) { Randomizer.Error("rvaLookup", new Exception($"Address not found for {sig}")); return(0); } return(relevantRVAs[sig]); }
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 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; } } }
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 UpdateReachableAsync(int sleepTime = 30) { try { Thread.Sleep(sleepTime); // wait to let values update if (Updating) { return; } Updating = true; var argsList = new List <string> { "-jar", $"{Randomizer.BasePath}SeedGen.jar ", "ReachCheck", $"\"{SeedController.SeedFile}\"", $"{InterOp.get_max_health()}", $"{Convert.ToInt32(10*InterOp.get_max_energy())}", $"{UberGet.value(6, 0).Int}", $"{InterOp.get_ore()}", $"{InterOp.get_experience()}", }; // ^ this should probably be an array at this point... // TODO: send which key doors are already open 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"); } var proc = new System.Diagnostics.Process(); proc.StartInfo.FileName = @"java.exe"; proc.StartInfo.Arguments = String.Join(" ", argsList); proc.StartInfo.CreateNoWindow = true; proc.StartInfo.UseShellExecute = false; proc.StartInfo.RedirectStandardOutput = true; proc.StartInfo.WorkingDirectory = Randomizer.BasePath; proc.Start(); if (!proc.WaitForExit(7500)) { 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]); Reachable.Add(cond); } catch (Exception e) { Randomizer.Error($"GetReachableAsync (post-return) while parsing |{rawCond}|", e); } } } // else // Randomizer.Log($"got output |{rawOutput}| from cmd. args: \"{String.Join(" ", argsList)}\" stderr was {proc.StandardError.ReadToEnd()}", false); InterOp.refresh_inlogic_filter(); } catch (Exception e) { Randomizer.Error("GetReachableAsync", e); } Updating = false; }
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) { 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 "hintMessage": 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 "test1": PsuedoLocs.BINDING_ONE.OnCollect(); break; case "test2": PsuedoLocs.BINDING_TWO.OnCollect(); break; case "test3": PsuedoLocs.BINDING_THREE.OnCollect(); break; case "test4": if (SeedController.HasInternalSpoilers) { UberSet.Bool(34543, 11226, true); Print("spoiler unlocked", toMessageLog: false); } break; case "test5": tpCheatToggle = !tpCheatToggle; Print($"TPCheat {(tpCheatToggle ? "enabled" : "disabled")}", 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; 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(Current.Text, Current.Frames / 60f, Current.Pos); 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 ResolveUberStateChange(UberState state, UberValue old) { try { UberId key = state.GetUberId(); if (!UberStates.TryGetValue(key, out UberState oldState)) { oldState = state.Clone(); oldState.Value = old; UberStates.Add(key, oldState); } UberValue value = state.Value; if (value.Int == old.Int) { return; } var oldValFmt = old.FmtVal(state.Type); // get this now because we overwrite the value by reference if (ShouldRevert(state)) { Randomizer.Log($"Reverting state change of {state.Name} from {oldValFmt} to {state.FmtVal()}", false); oldState.Write(); return; } HandleSpecial(state); UberStates[key].Value = state.Value; var pos = InterOp.get_position(); bool found = false; if (value.Int > 0) { var id = state.GetUberId(); if (SkipUberStateMapCount.GetOrElse(key, 0) > 0) { var p = id.toCond().Pickup().Concat(id.toCond(state.ValueAsInt()).Pickup()); if (p.NonEmpty) { SkipUberStateMapCount[key] -= 1; Randomizer.Log($"Suppressed granting {p} from {id}={state.ValueAsInt()}. Will suppress {SkipUberStateMapCount[key]} more times", false, "DEBUG"); return; } } found = SeedController.OnUberState(state); } if (SyncedUberStates.Contains(key)) { Randomizer.Client.SendUpdate(key, state.ValueAsFloat()); } BonusItemController.OnUberState(state); var zone = ZoneType.Void; if (InterOp.get_game_state() == GameState.Game) { zone = InterOp.get_player_area().toZone(); } if (!NeedsNewGameInit && (value.Int == 0 || !found) && !(state.GroupName == "statsUberStateGroup" || state.GroupName == "achievementsGroup" || state.GroupID == 8 || state.GroupID == 10)) { Randomizer.Debug($"State change: {state.GroupName}.{state.Name} ({state.GroupID}|{state.ID}) {state.Type} {oldValFmt}->{state.FmtVal()} at ({Math.Round(pos.X)}, {Math.Round(pos.Y)}) in {zone}"); } //Randomizer.Debug($"{state.GroupName}.{state.Name}, {state.GroupID}, {state.ID}, {state.Type}, {oldValFmt}, {state.FmtVal()}, {zone}, {Math.Round(pos.X)},{Math.Round(pos.Y)}"); } catch (Exception e) { Randomizer.Error($"USC.Update {state}", e); } }