private void SetSkinTokens() { var osuSkinsDirectory = Path.Combine(_settings.Get <string>(SettingNames.Instance.MainOsuDirectory), "Skins"); var skinName = _reader?.GetSkinFolderName() ?? string.Empty; _skinToken.Value = skinName.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0 ? string.Empty : skinName; string skinPath; try { skinPath = Path.Combine(osuSkinsDirectory, (string)_skinToken.Value); } catch (ArgumentException) { skinPath = string.Empty; } _skinPathToken.Value = skinPath; }
private void OnShown(object sender, EventArgs eventArgs) { if (!string.IsNullOrEmpty(_osuWindowTitleHint)) { Text += $": {_osuWindowTitleHint}"; } _ = Task.Run(async() => { try { var playContainer = new PlayContainerEx(); var playReseted = false; while (true) { if (cts.IsCancellationRequested) { return; } var patternsToRead = GetPatternsToRead(); var stopwatch = Stopwatch.StartNew(); #region OsuBase var mapId = -1; var songString = string.Empty; var mapMd5 = string.Empty; var mapFolderName = string.Empty; var osuFileName = string.Empty; var retrys = -1; var gameMode = -1; var mapData = string.Empty; var status = OsuMemoryStatus.Unknown; var statusNum = -1; var playTime = -1; if (patternsToRead.OsuBase) { mapId = _reader.GetMapId(); songString = _reader.GetSongString(); mapMd5 = _reader.GetMapMd5(); mapFolderName = _reader.GetMapFolderName(); osuFileName = _reader.GetOsuFileName(); retrys = _reader.GetRetrys(); gameMode = _reader.ReadSongSelectGameMode(); mapData = $"HP:{_reader.GetMapHp()} OD:{_reader.GetMapOd()}, CS:{_reader.GetMapCs()}, AR:{_reader.GetMapAr()}, setId:{_reader.GetMapSetId()}"; status = _reader.GetCurrentStatus(out statusNum); playTime = _reader.ReadPlayTime(); } #endregion #region Mods var mods = -1; if (patternsToRead.Mods) { mods = _reader.GetMods(); } #endregion #region CurrentSkinData var skinFolderName = string.Empty; if (patternsToRead.CurrentSkinData) { skinFolderName = _reader.GetSkinFolderName(); } #endregion #region PlayContainer double hp = 0; var playerName = string.Empty; var hitErrorCount = -1; var playingMods = -1; double displayedPlayerHp = 0; if (status == OsuMemoryStatus.Playing && patternsToRead.PlayContainer) { playReseted = false; _reader.GetPlayData(playContainer); hp = _reader.ReadPlayerHp(); playerName = _reader.PlayerName(); hitErrorCount = _reader.HitErrors()?.Count ?? -2; playingMods = _reader.GetPlayingMods(); displayedPlayerHp = _reader.ReadDisplayedPlayerHp(); } else if (!playReseted) { playReseted = true; playContainer.Reset(); } #endregion #region TourneyBase // TourneyBase var tourneyIpcState = TourneyIpcState.Unknown; var tourneyIpcStateNumber = -1; var tourneyLeftStars = -1; var tourneyRightStars = -1; var tourneyBO = -1; var tourneyStarsVisible = false; var tourneyScoreVisible = false; if (status == OsuMemoryStatus.Tourney && patternsToRead.TourneyBase) { tourneyIpcState = _reader.GetTourneyIpcState(out tourneyIpcStateNumber); tourneyLeftStars = _reader.ReadTourneyLeftStars(); tourneyRightStars = _reader.ReadTourneyRightStars(); tourneyBO = _reader.ReadTourneyBO(); tourneyStarsVisible = _reader.ReadTourneyStarsVisible(); tourneyScoreVisible = _reader.ReadTourneyScoreVisible(); } #endregion stopwatch.Stop(); var readTimeMs = stopwatch.ElapsedTicks / (double)TimeSpan.TicksPerMillisecond; double readTimeMsMin; double readTimeMsMax; lock (_minMaxLock) { if (readTimeMs < _memoryReadTimeMin) { _memoryReadTimeMin = readTimeMs; } if (readTimeMs > _memoryReadTimeMax) { _memoryReadTimeMax = readTimeMs; } // copy value since we're inside lock readTimeMsMin = _memoryReadTimeMin; readTimeMsMax = _memoryReadTimeMax; } Invoke((MethodInvoker)(() => { textBox_readTime.Text = $" ReadTimeMS: {readTimeMs}{Environment.NewLine}" + $" Min ReadTimeMS: {readTimeMsMin}{Environment.NewLine}" + $"Max ReadTimeMS: {readTimeMsMax}{Environment.NewLine}"; textBox_mapId.Text = mapId.ToString(); textBox_strings.Text = $"songString: \"{songString}\" {Environment.NewLine}" + $"md5: \"{mapMd5}\" {Environment.NewLine}" + $"mapFolder: \"{mapFolderName}\" {Environment.NewLine}" + $"fileName: \"{osuFileName}\" {Environment.NewLine}" + $"Retrys:{retrys} {Environment.NewLine}" + $"mods:{(Mods)mods}({mods}) {Environment.NewLine}" + $"SkinName: \"{skinFolderName}\""; textBox_time.Text = playTime.ToString(); textBox_mapData.Text = mapData; textBox_Status.Text = status + " " + statusNum + " " + gameMode; textBox_CurrentPlayData.Text = playContainer + Environment.NewLine + $"hp________: {hp:00.##} {Environment.NewLine}" + $"displayedHp: {displayedPlayerHp:00.##} {Environment.NewLine}" + $"playingMods:{(Mods)playingMods} ({playingMods}) " + $"PlayerName: {playerName}{Environment.NewLine}" + $"HitErrorCount: {hitErrorCount} "; if (status == OsuMemoryStatus.Tourney) { textBox_TourneyStuff.Text = $"IPC-State: {tourneyIpcState} ({tourneyIpcStateNumber}) | BO {tourneyBO}{Environment.NewLine}" + $"Stars: {tourneyLeftStars} | {tourneyRightStars}{Environment.NewLine}" + $"Warmup/Stars State: {(tourneyStarsVisible ? "stars visible, warmup disabled" : "stars hidden, warmup enabled")}{Environment.NewLine}" + $"Score/Chat state: {(tourneyScoreVisible ? "chat hidden, score visible or no lobby joined" : "chat visible, score hidden")}{Environment.NewLine}"; } else { textBox_TourneyStuff.Text = "no data since not in tourney mode"; } })); await Task.Delay(_readDelay); } } catch (ThreadAbortException) { } }); }
private void InitLiveTokens() { var osuSkinsDirectory = Path.Combine(_settings.Get <string>(SettingNames.Instance.MainOsuDirectory), "Skins"); var notPlaying = (OsuStatus)(OsuStatus.All - OsuStatus.Playing); _liveTokens["status"] = new LiveToken(_tokenSetter("status", OsuStatus.Null, TokenType.Live, "", OsuStatus.Null), null); _liveTokens["skin"] = new LiveToken(_tokenSetter("skin", string.Empty, TokenType.Live, null, string.Empty, notPlaying), () => _reader?.GetSkinFolderName() ?? string.Empty); _liveTokens["skinPath"] = new LiveToken(_tokenSetter("skinPath", string.Empty, TokenType.Live, null, string.Empty, notPlaying), () => { try { return(Path.Combine(osuSkinsDirectory, (string)_liveTokens["skin"].Token.Value)); } catch (ArgumentException ex) { _logger.SetContextData("!skin!", $"{_liveTokens["skin"].Token.Value}"); _logger.SetContextData("osuSkinsDirectory", $"{osuSkinsDirectory}"); _logger.Log(ex, LogLevel.Error); return(string.Empty); } }); _liveTokens["acc"] = new LiveToken(_tokenSetter("acc", _rawData.Play.Acc, TokenType.Live, "{0:0.00}", 0d, OsuStatus.Playing), () => _rawData.Play.Acc); _liveTokens["katsu"] = new LiveToken(_tokenSetter("katsu", _rawData.Play.CKatsu, TokenType.Live, "{0}", (ushort)0, OsuStatus.Playing), () => _rawData.Play.CKatsu); _liveTokens["geki"] = new LiveToken(_tokenSetter("geki", _rawData.Play.CGeki, TokenType.Live, "{0}", (ushort)0, OsuStatus.Playing), () => _rawData.Play.CGeki); _liveTokens["300"] = new LiveToken(_tokenSetter("300", _rawData.Play.C300, TokenType.Live, "{0}", (ushort)0, OsuStatus.Playing), () => _rawData.Play.C300); _liveTokens["100"] = new LiveToken(_tokenSetter("100", _rawData.Play.C100, TokenType.Live, "{0}", (ushort)0, OsuStatus.Playing), () => _rawData.Play.C100); _liveTokens["50"] = new LiveToken(_tokenSetter("50", _rawData.Play.C50, TokenType.Live, "{0}", (ushort)0, OsuStatus.Playing), () => _rawData.Play.C50); _liveTokens["miss"] = new LiveToken(_tokenSetter("miss", _rawData.Play.CMiss, TokenType.Live, "{0}", (ushort)0, OsuStatus.Playing), () => _rawData.Play.CMiss); _liveTokens["mapPosition"] = new LiveToken(_tokenSetter("mapPosition", TimeSpan.Zero, TokenType.Live, "{0:mm\\:ss}", TimeSpan.Zero), () => { if (_rawData.PlayTime != 0) { return(TimeSpan.FromMilliseconds(_rawData.PlayTime)); } return(TimeSpan.Zero); }); _liveTokens["time"] = new LiveToken(_tokenSetter("time", 0d, TokenType.Live, "{0:0.00}", 0d), () => { if (_rawData.PlayTime != 0) { return(_rawData.PlayTime / 1000d); } return(0d); }); _liveTokens["timeLeft"] = new LiveToken(_tokenSetter("timeLeft", TimeSpan.Zero, TokenType.Live, "{0:mm\\:ss}", TimeSpan.Zero), () => { var beatmapLength = _rawData.PpCalculator?.WorkingBeatmap?.Length; if (beatmapLength.HasValue) { var timeLeft = TimeSpan.FromMilliseconds(beatmapLength.Value) - (TimeSpan)_liveTokens["mapPosition"].Token.Value; return(timeLeft.Ticks <= 0 ? TimeSpan.Zero : timeLeft); } return(TimeSpan.Zero); }); _liveTokens["combo"] = new LiveToken(_tokenSetter("combo", _rawData.Play.Combo, TokenType.Live, "{0}", (ushort)0, OsuStatus.Playing), () => _rawData.Play.Combo); _liveTokens["score"] = new LiveToken(_tokenSetter("score", _rawData.Play.Score, TokenType.Live, "{0}", 0, OsuStatus.Playing), () => _rawData.Play.Score); _liveTokens["CurrentMaxCombo"] = new LiveToken(_tokenSetter("CurrentMaxCombo", _rawData.Play.MaxCombo, TokenType.Live, "{0}", (ushort)0, OsuStatus.Playing), () => _rawData.Play.MaxCombo); _liveTokens["PlayerHp"] = new LiveToken(_tokenSetter("PlayerHp", _rawData.Play.Hp, TokenType.Live, "{0:0.00}", 0d, OsuStatus.Playing), () => _rawData.Play.Hp); _liveTokens["PpIfMapEndsNow"] = new LiveToken(_tokenSetter("PpIfMapEndsNow", InterpolatedValues[InterpolatedValueName.PpIfMapEndsNow].Current, TokenType.Live, "{0:0.00}", 0d, OsuStatus.Playing), () => { InterpolatedValues[InterpolatedValueName.PpIfMapEndsNow].Set(_rawData.PPIfBeatmapWouldEndNow()); return(InterpolatedValues[InterpolatedValueName.PpIfMapEndsNow].Current); }); _liveTokens["AimPpIfMapEndsNow"] = new LiveToken(_tokenSetter("AimPpIfMapEndsNow", InterpolatedValues[InterpolatedValueName.AimPpIfMapEndsNow].Current, TokenType.Live, "{0:0.00}", 0d, OsuStatus.Playing), () => { InterpolatedValues[InterpolatedValueName.AimPpIfMapEndsNow].Set(_rawData.AimPPIfBeatmapWouldEndNow); return(InterpolatedValues[InterpolatedValueName.AimPpIfMapEndsNow].Current); }); _liveTokens["SpeedPpIfMapEndsNow"] = new LiveToken(_tokenSetter("SpeedPpIfMapEndsNow", InterpolatedValues[InterpolatedValueName.SpeedPpIfMapEndsNow].Current, TokenType.Live, "{0:0.00}", 0d, OsuStatus.Playing), () => { InterpolatedValues[InterpolatedValueName.SpeedPpIfMapEndsNow].Set(_rawData.SpeedPPIfBeatmapWouldEndNow); return(InterpolatedValues[InterpolatedValueName.SpeedPpIfMapEndsNow].Current); }); _liveTokens["AccPpIfMapEndsNow"] = new LiveToken(_tokenSetter("AccPpIfMapEndsNow", InterpolatedValues[InterpolatedValueName.AccPpIfMapEndsNow].Current, TokenType.Live, "{0:0.00}", 0d, OsuStatus.Playing), () => { InterpolatedValues[InterpolatedValueName.AccPpIfMapEndsNow].Set(_rawData.AccPPIfBeatmapWouldEndNow); return(InterpolatedValues[InterpolatedValueName.AccPpIfMapEndsNow].Current); }); _liveTokens["StrainPpIfMapEndsNow"] = new LiveToken(_tokenSetter("StrainPpIfMapEndsNow", InterpolatedValues[InterpolatedValueName.StrainPpIfMapEndsNow].Current, TokenType.Live, "{0:0.00}", 0d, OsuStatus.Playing), () => { InterpolatedValues[InterpolatedValueName.StrainPpIfMapEndsNow].Set(_rawData.StrainPPIfBeatmapWouldEndNow); return(InterpolatedValues[InterpolatedValueName.StrainPpIfMapEndsNow].Current); }); _liveTokens["PpIfRestFced"] = new LiveToken(_tokenSetter("PpIfRestFced", InterpolatedValues[InterpolatedValueName.PpIfRestFced].Current, TokenType.Live, "{0:0.00}", 0d, OsuStatus.Playing), () => { InterpolatedValues[InterpolatedValueName.PpIfRestFced].Set(_rawData.PPIfRestFCed()); return(InterpolatedValues[InterpolatedValueName.PpIfRestFced].Current); }); _liveTokens["NoChokePp"] = new LiveToken(_tokenSetter("NoChokePp", InterpolatedValues[InterpolatedValueName.NoChokePp].Current, TokenType.Live, "{0:0.00}", 0d, OsuStatus.Playing), () => { InterpolatedValues[InterpolatedValueName.NoChokePp].Set(_rawData.NoChokePp()); return(InterpolatedValues[InterpolatedValueName.NoChokePp].Current); }); _liveTokens["UnstableRate"] = new LiveToken(_tokenSetter("UnstableRate", InterpolatedValues[InterpolatedValueName.UnstableRate].Current, TokenType.Live, "{0:0.000}", 0d, OsuStatus.Playing), () => { InterpolatedValues[InterpolatedValueName.UnstableRate].Set(UnstableRate(_rawData.HitErrors)); return(InterpolatedValues[InterpolatedValueName.UnstableRate].Current); }); HitErrors = _tokenSetter("HitErrors", new List <int>(), TokenType.Live | TokenType.Hidden, defaultValue: new List <int>(), whitelist: OsuStatus.Playing); _liveTokens["LocalTime"] = new LiveToken(_tokenSetter("LocalTime", DateTime.Now.TimeOfDay, TokenType.Live, "{0:hh}:{0:mm}:{0:ss}", DateTime.Now.TimeOfDay, OsuStatus.All), () => DateTime.Now.TimeOfDay); }
private void InitLiveTokens() { var osuSkinsDirectory = Path.Combine(_settings.Get <string>(SettingNames.Instance.MainOsuDirectory), "Skins"); var notPlaying = (OsuStatus)(OsuStatus.All - OsuStatus.Playing); _liveTokens["status"] = new LiveToken(_tokenSetter("status", OsuStatus.Null, TokenType.Normal, "", OsuStatus.Null), null); _liveTokens["skin"] = new LiveToken(_liveTokenSetter("skin", string.Empty, TokenType.Live, null, string.Empty, notPlaying), () => { //TODO: memoryReader sometimes returns malformed skinName string var name = _reader?.GetSkinFolderName() ?? string.Empty; return(name.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0 ? string.Empty : name); }); _liveTokens["skinPath"] = new LiveToken(_liveTokenSetter("skinPath", string.Empty, TokenType.Live, null, string.Empty, notPlaying), () => { try { return(Path.Combine(osuSkinsDirectory, (string)_liveTokens["skin"].Token.Value)); } catch (ArgumentException) { return(string.Empty); } }); _liveTokens["acc"] = new LiveToken(_liveTokenSetter("acc", _rawData.Play.Acc, TokenType.Live, "{0:0.00}", 0d, OsuStatus.Playing), () => _rawData.Play.Acc); _liveTokens["katsu"] = new LiveToken(_liveTokenSetter("katsu", _rawData.Play.CKatsu, TokenType.Live, "{0}", (ushort)0, OsuStatus.Playing), () => _rawData.Play.CKatsu); _liveTokens["geki"] = new LiveToken(_liveTokenSetter("geki", _rawData.Play.CGeki, TokenType.Live, "{0}", (ushort)0, OsuStatus.Playing), () => _rawData.Play.CGeki); _liveTokens["c300"] = new LiveToken(_liveTokenSetter("c300", _rawData.Play.C300, TokenType.Live, "{0}", (ushort)0, OsuStatus.Playing), () => _rawData.Play.C300); _liveTokens["c100"] = new LiveToken(_liveTokenSetter("c100", _rawData.Play.C100, TokenType.Live, "{0}", (ushort)0, OsuStatus.Playing), () => _rawData.Play.C100); _liveTokens["c50"] = new LiveToken(_liveTokenSetter("c50", _rawData.Play.C50, TokenType.Live, "{0}", (ushort)0, OsuStatus.Playing), () => _rawData.Play.C50); _liveTokens["miss"] = new LiveToken(_liveTokenSetter("miss", _rawData.Play.CMiss, TokenType.Live, "{0}", (ushort)0, OsuStatus.Playing), () => _rawData.Play.CMiss); _liveTokens["mapPosition"] = new LiveToken(_liveTokenSetter("mapPosition", TimeSpan.Zero, TokenType.Live, "{0:mm\\:ss}", TimeSpan.Zero), () => { if (_rawData.PlayTime != 0) { return(TimeSpan.FromMilliseconds(_rawData.PlayTime)); } return(TimeSpan.Zero); }); _liveTokens["time"] = new LiveToken(_liveTokenSetter("time", 0d, TokenType.Live, "{0:0.00}", 0d), () => { if (_rawData.PlayTime != 0) { return(_rawData.PlayTime / 1000d); } return(0d); }); _liveTokens["timeLeft"] = new LiveToken(_liveTokenSetter("timeLeft", TimeSpan.Zero, TokenType.Live, "{0:mm\\:ss}", TimeSpan.Zero), () => { var beatmapLength = _rawData.PpCalculator?.WorkingBeatmap?.Length; if (beatmapLength.HasValue) { var timeLeft = TimeSpan.FromMilliseconds(beatmapLength.Value) - (TimeSpan)_liveTokens["mapPosition"].Token.Value; return(timeLeft.Ticks <= 0 ? TimeSpan.Zero : timeLeft); } return(TimeSpan.Zero); }); _liveTokens["combo"] = new LiveToken(_liveTokenSetter("combo", _rawData.Play.Combo, TokenType.Live, "{0}", (ushort)0, OsuStatus.Playing), () => _rawData.Play.Combo); _liveTokens["score"] = new LiveToken(_liveTokenSetter("score", _rawData.Play.Score, TokenType.Live, "{0}", 0, OsuStatus.Playing), () => _rawData.Play.Score); _liveTokens["CurrentMaxCombo"] = new LiveToken(_liveTokenSetter("CurrentMaxCombo", _rawData.Play.MaxCombo, TokenType.Live, "{0}", (ushort)0, OsuStatus.Playing), () => _rawData.Play.MaxCombo); _liveTokens["PlayerHp"] = new LiveToken(_liveTokenSetter("PlayerHp", _rawData.Play.Hp, TokenType.Live, "{0:0.00}", 0d, OsuStatus.Playing), () => _rawData.Play.Hp); _liveTokens["PpIfMapEndsNow"] = new LiveToken(_liveTokenSetter("PpIfMapEndsNow", InterpolatedValues[InterpolatedValueName.PpIfMapEndsNow].Current, TokenType.Live, "{0:0.00}", 0d, OsuStatus.Playing), () => { InterpolatedValues[InterpolatedValueName.PpIfMapEndsNow].Set(_rawData.PPIfBeatmapWouldEndNow()); return(InterpolatedValues[InterpolatedValueName.PpIfMapEndsNow].Current); }); _liveTokens["AimPpIfMapEndsNow"] = new LiveToken(_liveTokenSetter("AimPpIfMapEndsNow", InterpolatedValues[InterpolatedValueName.AimPpIfMapEndsNow].Current, TokenType.Live, "{0:0.00}", 0d, OsuStatus.Playing), () => { InterpolatedValues[InterpolatedValueName.AimPpIfMapEndsNow].Set(_rawData.AimPPIfBeatmapWouldEndNow); return(InterpolatedValues[InterpolatedValueName.AimPpIfMapEndsNow].Current); }); _liveTokens["SpeedPpIfMapEndsNow"] = new LiveToken(_liveTokenSetter("SpeedPpIfMapEndsNow", InterpolatedValues[InterpolatedValueName.SpeedPpIfMapEndsNow].Current, TokenType.Live, "{0:0.00}", 0d, OsuStatus.Playing), () => { InterpolatedValues[InterpolatedValueName.SpeedPpIfMapEndsNow].Set(_rawData.SpeedPPIfBeatmapWouldEndNow); return(InterpolatedValues[InterpolatedValueName.SpeedPpIfMapEndsNow].Current); }); _liveTokens["AccPpIfMapEndsNow"] = new LiveToken(_liveTokenSetter("AccPpIfMapEndsNow", InterpolatedValues[InterpolatedValueName.AccPpIfMapEndsNow].Current, TokenType.Live, "{0:0.00}", 0d, OsuStatus.Playing), () => { InterpolatedValues[InterpolatedValueName.AccPpIfMapEndsNow].Set(_rawData.AccPPIfBeatmapWouldEndNow); return(InterpolatedValues[InterpolatedValueName.AccPpIfMapEndsNow].Current); }); _liveTokens["StrainPpIfMapEndsNow"] = new LiveToken(_liveTokenSetter("StrainPpIfMapEndsNow", InterpolatedValues[InterpolatedValueName.StrainPpIfMapEndsNow].Current, TokenType.Live, "{0:0.00}", 0d, OsuStatus.Playing), () => { InterpolatedValues[InterpolatedValueName.StrainPpIfMapEndsNow].Set(_rawData.StrainPPIfBeatmapWouldEndNow); return(InterpolatedValues[InterpolatedValueName.StrainPpIfMapEndsNow].Current); }); _liveTokens["PpIfRestFced"] = new LiveToken(_liveTokenSetter("PpIfRestFced", InterpolatedValues[InterpolatedValueName.PpIfRestFced].Current, TokenType.Live, "{0:0.00}", 0d, OsuStatus.Playing), () => { InterpolatedValues[InterpolatedValueName.PpIfRestFced].Set(_rawData.PPIfRestFCed()); return(InterpolatedValues[InterpolatedValueName.PpIfRestFced].Current); }); _liveTokens["NoChokePp"] = new LiveToken(_liveTokenSetter("NoChokePp", InterpolatedValues[InterpolatedValueName.NoChokePp].Current, TokenType.Live, "{0:0.00}", 0d, OsuStatus.Playing), () => { InterpolatedValues[InterpolatedValueName.NoChokePp].Set(_rawData.NoChokePp()); return(InterpolatedValues[InterpolatedValueName.NoChokePp].Current); }); _liveTokens["UnstableRate"] = new LiveToken(_liveTokenSetter("UnstableRate", InterpolatedValues[InterpolatedValueName.UnstableRate].Current, TokenType.Live, "{0:0.000}", 0d, OsuStatus.Playing), () => { InterpolatedValues[InterpolatedValueName.UnstableRate].Set(UnstableRate(_rawData.HitErrors)); return(InterpolatedValues[InterpolatedValueName.UnstableRate].Current); }); _liveTokens["ConvertedUnstableRate"] = new LiveToken(_liveTokenSetter("ConvertedUnstableRate", InterpolatedValues[InterpolatedValueName.UnstableRate].Current, TokenType.Live, "{0:0.000}", 0d, OsuStatus.Playing), () => { var ur = (double)_liveTokens["UnstableRate"].Token.Value; if ((CurrentMods & Mods.Dt) != 0) { return(ur / 1.5d); } if ((CurrentMods & Mods.Ht) != 0) { return(ur / 0.75d); } return(ur); }); _liveTokens["HitErrors"] = new LiveToken(_liveTokenSetter("HitErrors", new List <int>(), TokenType.Live, ",", new List <int>(), OsuStatus.Playing), () => _rawData.HitErrors); _liveTokens["LocalTime"] = new LiveToken(_liveTokenSetter("LocalTime", DateTime.Now.TimeOfDay, TokenType.Live, "{0:hh}:{0:mm}:{0:ss}", DateTime.Now.TimeOfDay, OsuStatus.All), () => DateTime.Now.TimeOfDay); }