public void Tick(OsuStatus status, OsuMemoryStatus rawStatus, StructuredOsuMemoryReader reader) { _notUpdatingTokens.WaitOne(); _notUpdatingMemoryValues.Reset(); lock (_lockingObject) { if (!ReferenceEquals(OsuMemoryData, reader.OsuMemoryAddresses)) { OsuMemoryData = reader.OsuMemoryAddresses; _rawData.Play = OsuMemoryData.Player; } if ((OsuStatus)_liveTokens["status"].Token.Value != status) { _liveTokens["status"].Token.Value = status; } _liveTokens["rawStatus"].Token.Value = rawStatus; if (status != OsuStatus.Playing && status != OsuStatus.Watching) { var rawAudioTime = Retry.RetryMe(() => reader.ReadProperty(OsuMemoryData.GeneralData, nameof(GeneralData.AudioTime)), (val => val != null), 5); if (int.TryParse(rawAudioTime?.ToString(), out var audioTime)) { _rawData.PlayTime = audioTime; } reader.Read(OsuMemoryData.Skin); UpdateLiveTokens(status); _lastStatus = status; _notUpdatingMemoryValues.Set(); return; } if (_lastStatus != OsuStatus.Playing && _lastStatus != OsuStatus.Watching) { _newPlayStarted.Set(); Thread.Sleep(500);//Initial play delay } reader.Read(OsuMemoryData.Player); _rawData.PlayTime = OsuMemoryData.GeneralData.AudioTime; _liveTokens["time"].Update(); _lastStatus = status; } _notUpdatingMemoryValues.Set(); }
public void Tick(OsuStatus status, OsuMemoryStatus rawStatus, StructuredOsuMemoryReader reader) { _notUpdatingTokens.WaitOne(); _notUpdatingMemoryValues.Reset(); lock (_lockingObject) { if (!ReferenceEquals(OsuMemoryData, reader.OsuMemoryAddresses)) { OsuMemoryData = reader.OsuMemoryAddresses; } if ((OsuStatus)_liveTokens["status"].Token.Value != status) { _liveTokens["status"].Token.Value = status; } _liveTokens["rawStatus"].Token.Value = rawStatus; int playTime = OsuMemoryData.GeneralData.AudioTime; switch (status) { case OsuStatus.Playing: case OsuStatus.Watching: if (_lastStatus != OsuStatus.Playing && _lastStatus != OsuStatus.Watching) { _newPlayStarted.Set(); Thread.Sleep(500); //Initial play delay } reader.TryRead(OsuMemoryData.Player); if (!ReferenceEquals(_rawData.Play, OsuMemoryData.Player)) { _rawData.Play = OsuMemoryData.Player; } //TODO: support for live multiplayer leaderboard if (!ReadLeaderboard) { //Read whole leaderboard once if (reader.TryRead(OsuMemoryData.LeaderBoard)) { ReadLeaderboard = true; if (!ReferenceEquals(_rawData.LeaderBoard, OsuMemoryData.LeaderBoard)) { _rawData.LeaderBoard = OsuMemoryData.LeaderBoard; } } } else { //Throttle whole leaderboard reads - Temporary solution until multiplayer detection is implemented, this should be only done in multiplayer if (_nextLeaderBoardUpdate < DateTime.UtcNow) { reader.TryRead(OsuMemoryData.LeaderBoard); _nextLeaderBoardUpdate = DateTime.UtcNow.AddMilliseconds(_settings.Get <int>(MultiplayerLeaderBoardUpdateRate)); } else { //...then update main player data if (OsuMemoryData.LeaderBoard.HasLeaderBoard) { reader.TryRead(OsuMemoryData.LeaderBoard.MainPlayer); } } } break; case OsuStatus.ResultsScreen: ReadLeaderboard = false; reader.TryRead(OsuMemoryData.ResultsScreen); if (!ReferenceEquals(_rawData.Play, OsuMemoryData.ResultsScreen)) { _rawData.Play = OsuMemoryData.ResultsScreen; } playTime = Convert.ToInt32(_rawData.PpCalculator?.BeatmapLength ?? 0); break; default: ReadLeaderboard = false; _rawData.LeaderBoard = new LeaderBoard(); reader.TryRead(OsuMemoryData.Skin); _lastStatus = status; break; } _rawData.PlayTime = playTime; _liveTokens["time"].Update(); _lastStatus = status; } _notUpdatingMemoryValues.Set(); }
private async void OnShown(object sender, EventArgs eventArgs) { if (!string.IsNullOrEmpty(_osuWindowTitleHint)) { Text += $": {_osuWindowTitleHint}"; } Text += $" ({(Environment.Is64BitProcess ? "x64" : "x86")})"; _sreader.InvalidRead += SreaderOnInvalidRead; await Task.Run(async() => { Stopwatch stopwatch; double readTimeMs, readTimeMsMin, readTimeMsMax; _sreader.WithTimes = true; var readUsingProperty = false; var baseAddresses = new OsuBaseAddresses(); while (true) { if (cts.IsCancellationRequested) { return; } if (!_sreader.CanRead) { Invoke((MethodInvoker)(() => { textBox_Data.Text = "osu! process not found"; })); await Task.Delay(_readDelay); continue; } stopwatch = Stopwatch.StartNew(); if (readUsingProperty) { baseAddresses.Beatmap.Id = ReadInt(baseAddresses.Beatmap, nameof(CurrentBeatmap.Id)); baseAddresses.Beatmap.SetId = ReadInt(baseAddresses.Beatmap, nameof(CurrentBeatmap.SetId)); baseAddresses.Beatmap.MapString = ReadString(baseAddresses.Beatmap, nameof(CurrentBeatmap.MapString)); baseAddresses.Beatmap.FolderName = ReadString(baseAddresses.Beatmap, nameof(CurrentBeatmap.FolderName)); baseAddresses.Beatmap.OsuFileName = ReadString(baseAddresses.Beatmap, nameof(CurrentBeatmap.OsuFileName)); baseAddresses.Beatmap.Md5 = ReadString(baseAddresses.Beatmap, nameof(CurrentBeatmap.Md5)); baseAddresses.Beatmap.Ar = ReadFloat(baseAddresses.Beatmap, nameof(CurrentBeatmap.Ar)); baseAddresses.Beatmap.Cs = ReadFloat(baseAddresses.Beatmap, nameof(CurrentBeatmap.Cs)); baseAddresses.Beatmap.Hp = ReadFloat(baseAddresses.Beatmap, nameof(CurrentBeatmap.Hp)); baseAddresses.Beatmap.Od = ReadFloat(baseAddresses.Beatmap, nameof(CurrentBeatmap.Od)); baseAddresses.Beatmap.Status = ReadShort(baseAddresses.Beatmap, nameof(CurrentBeatmap.Status)); baseAddresses.Skin.Folder = ReadString(baseAddresses.Skin, nameof(Skin.Folder)); baseAddresses.GeneralData.RawStatus = ReadInt(baseAddresses.GeneralData, nameof(GeneralData.RawStatus)); baseAddresses.GeneralData.GameMode = ReadInt(baseAddresses.GeneralData, nameof(GeneralData.GameMode)); baseAddresses.GeneralData.Retries = ReadInt(baseAddresses.GeneralData, nameof(GeneralData.Retries)); baseAddresses.GeneralData.AudioTime = ReadInt(baseAddresses.GeneralData, nameof(GeneralData.AudioTime)); baseAddresses.GeneralData.Mods = ReadInt(baseAddresses.GeneralData, nameof(GeneralData.Mods)); } else { _sreader.TryRead(baseAddresses.Beatmap); _sreader.TryRead(baseAddresses.Skin); _sreader.TryRead(baseAddresses.GeneralData); } if (baseAddresses.GeneralData.OsuStatus == OsuMemoryStatus.SongSelect) { _sreader.TryRead(baseAddresses.SongSelectionScores); } else { baseAddresses.SongSelectionScores.Scores.Clear(); } if (baseAddresses.GeneralData.OsuStatus == OsuMemoryStatus.ResultsScreen) { _sreader.TryRead(baseAddresses.ResultsScreen); } if (baseAddresses.GeneralData.OsuStatus == OsuMemoryStatus.Playing) { _sreader.TryRead(baseAddresses.Player); //TODO: flag needed for single/multi player detection (should be read once per play in singleplayer) _sreader.TryRead(baseAddresses.LeaderBoard); _sreader.TryRead(baseAddresses.KeyOverlay); if (readUsingProperty) { //Testing reading of reference types(other than string) _sreader.TryReadProperty(baseAddresses.Player, nameof(Player.Mods), out var dummyResult); } } else { baseAddresses.LeaderBoard.Players.Clear(); } var hitErrors = baseAddresses.Player?.HitErrors; if (hitErrors != null) { var hitErrorsCount = hitErrors.Count; hitErrors.Clear(); hitErrors.Add(hitErrorsCount); } stopwatch.Stop(); readTimeMs = stopwatch.ElapsedTicks / (double)TimeSpan.TicksPerMillisecond; lock (_minMaxLock) { if (readTimeMs < _memoryReadTimeMin) { _memoryReadTimeMin = readTimeMs; } if (readTimeMs > _memoryReadTimeMax) { _memoryReadTimeMax = readTimeMs; } // copy value since we're inside lock readTimeMsMin = _memoryReadTimeMin; readTimeMsMax = _memoryReadTimeMax; } try { Invoke((MethodInvoker)(() => { textBox_readTime.Text = $" ReadTimeMS: {readTimeMs}{Environment.NewLine}" + $" Min ReadTimeMS: {readTimeMsMin}{Environment.NewLine}" + $"Max ReadTimeMS: {readTimeMsMax}{Environment.NewLine}"; textBox_Data.Text = JsonConvert.SerializeObject(baseAddresses, Formatting.Indented); textBox_ReadTimes.Text = JsonConvert.SerializeObject(_sreader.ReadTimes, Formatting.Indented); })); } catch (ObjectDisposedException) { return; } _sreader.ReadTimes.Clear(); await Task.Delay(_readDelay); } }, cts.Token); }
private void OnShown(object sender, EventArgs eventArgs) { if (!string.IsNullOrEmpty(_osuWindowTitleHint)) { Text += $": {_osuWindowTitleHint}"; } _ = Task.Run(async() => { try { Stopwatch stopwatch; double readTimeMs, readTimeMsMin, readTimeMsMax; var playContainer = new PlayContainerEx(); var playReseted = false; var baseAddresses = new OsuBaseAddresses(); while (true) { if (cts.IsCancellationRequested) { return; } var patternsToRead = GetPatternsToRead(); stopwatch = Stopwatch.StartNew(); #region OsuBase var mapId = -1; var mapSetId = -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(); mapSetId = _reader.GetMapSetId(); 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 IsReplay bool isReplay = false; if (status == OsuMemoryStatus.Playing && patternsToRead.IsReplay) { isReplay = _reader.IsReplay(); } #endregion #region PlayContainer double hp = 0; var playerName = string.Empty; var hitErrorCount = -1; var playingMods = -1; double displayedPlayerHp = 0; int scoreV2 = -1; 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(); scoreV2 = _reader.ReadScoreV2(); } 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(); readTimeMs = stopwatch.ElapsedTicks / (double)TimeSpan.TicksPerMillisecond; 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 = $"Id:{mapId} setId:{mapSetId}"; 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 + $"scoreV2: {scoreV2} {Environment.NewLine}" + $"IsReplay: {isReplay} {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) { } }); }