/// <summary> /// Refreshes the types of columns displayed for judgemnt type hit count. /// </summary> public void RefreshColumns(IModeService service) { // In case of a null service, just display all labels. if (service == null) { Logger.LogWarning($"RankingColumn.RefreshColumn - The specified mode service is null."); judgementLabels.ForEach(l => l.Active = true); return; } // Only display judgement types that are used by this mode. var timing = service.CreateTiming(); int activeCount = 0; judgementLabels.ForEach(l => l.Active = false); foreach (var result in timing.SupportedHitResults()) { activeCount++; judgementLabels[(int)result].Active = true; } // Position these labels. for (int i = 0; i < judgementLabels.Count; i++) { if (judgementLabels[i].Active) { activeCount--; judgementLabels[i].X = JudgementLabelStartX - (activeCount * JudgementLabelInterval); } } }
protected override void PostInitialize() { base.PostInitialize(); originalScreenSize = new Vector2(Screen.width, Screen.height); // Initialize log service for notification. logToNotifService = new LogToNotificationService() { NotificationBox = base.notificationBox, }; Logger.Register(logToNotifService); // Hook events HookEngine(); HookMusicController(); HookScreenNavigator(); HookOverlayNavigator(); HookMapSelection(); HookConfigurations(); HookDownloadStore(); HookMapManager(); HookApi(); // Display splash view. if (ShouldShowFirstView) { screenNavigator.Show <SplashScreen>(); } }
public void DeleteMap(IOriginalMap map) { if (map == null) { Logger.LogWarning("Attempted to delete a null map."); return; } var mapset = map.Detail.Mapset; if (mapset == null) { throw new Exception($"Could not retrieve the mapset of specified map: {map.Metadata.Artist} - {map.Metadata.Title}"); } // Delete the mapset itself if there is only one map. if (mapset.Maps.Count == 1) { DeleteMapset(mapset); return; } // If this map is currently selected, make it select the previous map. var selectedOriginal = selection.Map.Value?.OriginalMap; if (selectedOriginal == map) { selection.SelectMap(mapset.GetMapBefore(selectedOriginal)); } store.DeleteMap(map); mapset.Maps.Remove(map); OnDeleteMap?.Invoke(map); }
public void DeleteMapset(IMapset mapset) { if (mapset == null) { Logger.LogWarning("Attempted to delete a null mapset."); return; } // If this mapset is currently selected, make it select the previous mapset. var selectedMapset = selection.Mapset.Value; if (selectedMapset == mapset) { // If there is only one mapset left in all mapsets, just remove selection. if (allMapsets.Count <= 1) { selection.SelectMapset(null); } else { // Determine which mapset list to choose the previous map from. var mapsetsList = ( (displayedMapsets.Contains(mapset) && displayedMapsets.Count == 1) || displayedMapsets.Count == 0 ? allMapsets : displayedMapsets ); selection.SelectMapset(mapsetsList.GetPrevious(mapset)); } } store.Delete(mapset as Mapset); allMapsets.Remove(mapset); displayedMapsets.Remove(mapset); OnDeleteMapset?.Invoke(mapset); }
public virtual T Get(string name) { if (IsDisposed) { throw new ObjectDisposedException(nameof(ResourceAtlas <T>)); } // If exists in atlas, return it. if (atlas.TryGetValue(name, out T result)) { return(result); } // If doesn't exist, load from resources. var loaded = LoadFromResources(name); if (loaded == null) { Logger.LogWarning($"ResourceAtlas.Get - Could not load resource ({name}) of type ({nameof(T)})"); } else { Set(name, loaded); } return(loaded); }
public ColorPalette GetDifficultyColor(DifficultyType type) { if (difficultyColors.TryGetValue(type, out ColorPalette value)) { return(value); } Logger.LogWarning($"ColorPreset.GetDifficultyColor - Unknown type: {type}"); return(new ColorPalette(Color.black)); }
public ColorPalette GetHitResultColor(HitResultType type) { if (hitResultColors.TryGetValue(type, out ColorPalette value)) { return(value); } Logger.LogWarning($"ColorPreset.GetHitResultColor - Unknown type: {type}"); return(new ColorPalette(Color.white)); }
/// <summary> /// Returns the Graphic component from the specified objct. /// </summary> protected Graphic GetGraphic(IGraphicObject obj) { var graphic = obj.RawObject.GetComponent <Graphic>(); if (graphic == null) { Logger.LogWarning("BaseShaderEffect.GetGraphic - Graphic component not found for object: " + obj.Name); } return(graphic); }
public Task <IMapset> Import(FileInfo file, TaskListener <IMapset> listener = null) { return(Task.Run <IMapset>(async() => { try { // Start importing the file Mapset mapset = await store.Import(file, listener: listener?.CreateSubListener <Mapset>()); if (mapset != null) { // Mapset must be fully loaded. Mapset loadedMapset = store.LoadData(mapset); if (loadedMapset != null) { // Dispatch mapset imported event on main thread. UnityThread.Dispatch(() => { // Add to all mapsets allMapsets.AddOrReplace(loadedMapset); // Reapply filter Search(lastSearch); OnImportMapset?.Invoke(loadedMapset); return null; }); } else { notificationBox?.Add(new Notification() { Message = $"Failed to load imported mapset ({mapset.Metadata.Artist} - {mapset.Metadata.Title})", Type = NotificationType.Error }); } } else { notificationBox?.Add(new Notification() { Message = $"Failed to import mapset at ({file.FullName})", Type = NotificationType.Error }); } listener?.SetFinished(mapset); return mapset; } catch (Exception e) { Logger.LogError($"Error while importing mapset: {e.Message}\n{e.StackTrace}"); listener?.SetFinished(); return null; } })); }
/// <summary> /// Creates a playable map for specified service. /// </summary> private IPlayableMap CreatePlayable(IModeService service) { if (service == null) { Logger.LogWarning($"OriginalMap.CreatePlayable - A null servicer is passed. Skipping this mode."); return(null); } // Conversion var converter = service.CreateConverter(this); if (!converter.IsConvertible) { return(null); } var convertedMap = converter.Convert(); if (convertedMap == null) { Logger.LogWarning($"OriginalMap.CreatePlayable - Failed to convert map for mode: {service.GameMode}"); return(null); } // Processing var processor = service.CreateProcessor(convertedMap); processor.PreProcess(); foreach (var o in convertedMap.HitObjects) { o.ApplyMapProperties(convertedMap.ControlPoints, convertedMap.Detail.Difficulty); } processor.PostProcess(); // Calculate difficulty. var difficultyCalculator = service.CreateDifficultyCalculator(convertedMap); if (difficultyCalculator == null) { Logger.LogWarning($"OriginalMap.CreatePlayable - Difficulty calculator is null for mode: {service.GameMode}"); return(null); } convertedMap.Difficulty = difficultyCalculator.Calculate(); if (convertedMap.Difficulty == null) { Logger.LogWarning($"OriginalMap.CreatePlayable - Failed to calculate difficulty for mode: {service.GameMode}"); return(null); } // Finished convertedMap.PlayableMode = service.GameMode; return(convertedMap); }
public PrefStorage(string id) { this.id = id; try { json = JsonConvert.DeserializeObject <JObject>(PlayerPrefs.GetString(id, "{}")); } catch (Exception e) { Logger.LogError($"PrefStorage - Failed to parse prefs of id ({id}): {e.Message}"); json = new JObject(); } }
/// <summary> /// Sets the count display for specified game mode. /// </summary> public void SetMapCount(GameModeType gameMode, int count) { var service = ModeManager.GetService(gameMode); if (service == null) { Logger.LogInfo($"Encountered an unsupported gameMode: {gameMode}"); return; } iconSprite.SpriteName = service.GetIconName(32); label.Text = count.ToString("N0"); }
/// <summary> /// Creates a new Color with string values. /// Supported formats: /// #{rr}{gg}{bb}{aa} /// #{rr}{gg}{bb} /// ** Cases are non-sensitive. /// ** Hashtag (#) not required. /// </summary> public static Color Create(string str) { int r = 255, g = 255, b = 255, a = 255; if (str[0] == '#') { str = str.Substring(1); } switch (str.Length) { case 3: r = ParseHex(str[0]) * 16 + ParseHex(str[0]); g = ParseHex(str[1]) * 16 + ParseHex(str[1]); b = ParseHex(str[2]) * 16 + ParseHex(str[2]); break; case 4: r = ParseHex(str[0]) * 16 + ParseHex(str[0]); g = ParseHex(str[1]) * 16 + ParseHex(str[1]); b = ParseHex(str[2]) * 16 + ParseHex(str[2]); a = ParseHex(str[3]) * 16 + ParseHex(str[3]); break; case 6: r = ParseHex(str[0]) * 16 + ParseHex(str[1]); g = ParseHex(str[2]) * 16 + ParseHex(str[3]); b = ParseHex(str[4]) * 16 + ParseHex(str[5]); break; case 8: r = ParseHex(str[0]) * 16 + ParseHex(str[1]); g = ParseHex(str[2]) * 16 + ParseHex(str[3]); b = ParseHex(str[4]) * 16 + ParseHex(str[5]); a = ParseHex(str[6]) * 16 + ParseHex(str[7]); break; default: Logger.LogWarning($"HexColor.Create - Invalid hex string: {str}"); break; } return(new Color( r * ByteReciprocal, g * ByteReciprocal, b * ByteReciprocal, a * ByteReciprocal )); }
/// <summary> /// Triggers actions on certain system events. /// </summary> private void HookEngine() { // Start listening to any exceptions that occurs during game. AppDomain.CurrentDomain.UnhandledException += (object sender, UnhandledExceptionEventArgs e) => { var exception = e.ExceptionObject as Exception; Logger.LogError($"Unhandled exception: {exception.ToString()}"); }; Application.logMessageReceived += (condition, stackTrace, type) => { if (type == LogType.Exception) { Logger.LogError($"Unhandled exception: {condition}\n{stackTrace}"); } }; }
/// <summary> /// Records the specified play record under the current player. /// </summary> public Task <IRecord> RecordScore(IScoreProcessor scoreProcessor, int playTime, TaskListener <IRecord> listener = null) { return(Task.Run <IRecord>(async() => { try { if (scoreProcessor == null || scoreProcessor.JudgeCount <= 0) { listener?.SetFinished(); return null; } // Retrieve user and user stats. var currentMap = currentParameter.Map; var user = UserManager.CurrentUser.Value; var userStats = user.GetStatistics(currentMap.PlayableMode); // Record the play result to records database and user statistics. Record newRecord = new Record(currentMap, user, scoreProcessor, playTime); lastRecord = newRecord; // Retrieve old records for the map and user. var records = await RecordStore.GetTopRecords(currentMap, user, limit: null, listener: listener?.CreateSubListener <List <IRecord> >()); // Save as cleared play. if (scoreProcessor.IsFinished) { RecordStore.SaveRecord(newRecord); var bestRecord = records == null || records.Count == 0 ? null : records[0]; userStats.RecordPlay(newRecord, bestRecord); } // Save as failed play. else { userStats.RecordIncompletePlay(newRecord); } listener?.SetFinished(newRecord); return newRecord; } catch (Exception e) { Logger.LogError($"Error while recording score: {e.Message}\n{e.StackTrace}"); listener?.SetFinished(); return null; } })); }
/// <summary> /// Determines the desired audio type from specified url. /// </summary> private AudioType GetAudioType(string url) { if (url.EndsWith("mp3", StringComparison.OrdinalIgnoreCase)) { return(AudioType.MPEG); } else if (url.EndsWith("ogg", StringComparison.OrdinalIgnoreCase)) { return(AudioType.OGGVORBIS); } else if (url.EndsWith("wav", StringComparison.OrdinalIgnoreCase)) { return(AudioType.WAV); } Logger.LogInfo($"AudioRequest.GetAudioType - Unknown audio type for url: {url}"); return(AudioType.UNKNOWN); }
public void CreatePlayable(IModeManager modeManager) { // Playable maps shouldn't support this action. if (IsPlayable) { Logger.LogWarning($"OriginalMap.CreatePlayable - This action is not supported for playable maps!"); return; } this.playableMaps.Clear(); foreach (var service in modeManager.PlayableServices()) { var playableMap = CreatePlayable(service); if (playableMap != null) { this.playableMaps[service.GameMode] = playableMap; } } }
public override void Decode(StreamReader stream, T result) { SectionType section = SectionType.None; string line; while ((line = stream.ReadLine()) != null) { if (ShouldSkipLine(line)) { continue; } // If found a new section if (line.StartsWith("[", StringComparison.Ordinal) && line.EndsWith("]", StringComparison.Ordinal)) { // Parse the section type string sectionString = line.Substring(1, line.Length - 2); try { section = (SectionType)Enum.Parse(typeof(SectionType), sectionString); } catch (Exception e) { // If an error occurred, throw an exception. section = SectionType.None; throw e; } continue; } try { DecodeLine(result, section, line); } catch (Exception e) { Logger.LogError( $"OsuDecoder.Decode - Failed to decode line: {line}, Error: {e.Message}" ); } } }
/// <summary> /// Disposes the view based on its hide action type. /// </summary> protected virtual void DisposeInternal(INavigationView view) { view.OnPostHide(); switch (view.HideAction) { case HideActionType.Recycle: view.Active = false; break; case HideActionType.Destroy: views.Remove(view); GameObject.Destroy(view.RawObject); break; default: Logger.LogWarning($"Navigator.DisposeInternal - Unsupported hide action type: {view.HideAction}"); break; } }
public void TestLogger() { LogAssert.ignoreFailingMessages = true; Logger.Log("1"); Logger.LogWarning("2"); Logger.LogError("3"); Logger.OnWarning += (message) => { Logger.Log($"Dispatched warning: {message}"); }; Logger.OnError += (message) => { Logger.Log($"Dispatched error: {message}"); }; Logger.Log("a"); Logger.LogWarning("b"); Logger.LogError("c"); }
/// <summary> /// Shows the map actions dialog overlay. /// </summary> public void ShowMapActions(IOriginalMap map) { if (map == null) { Logger.LogWarning("Attempted to show map actions for a null map."); return; } var dialogModel = OverlayNavigator.Show <DialogOverlay>().Model; dialogModel.SetMessage($"Select an action for the version ({map.Detail.Version})"); dialogModel.AddOption(new DialogOption() { Callback = () => OnMapActionDelete(map), Label = "Delete", Color = ColorPreset.Warning }); dialogModel.AddOption(new DialogOption() { Label = "Cancel", Color = ColorPreset.Negative }); }
/// <summary> /// Event called from deep linker when the path indicates API response. /// </summary> private void OnDeepLinkApi(WebLink link) { if (link.Parameters.TryGetValue("response", out string response)) { try { var bytes = Convert.FromBase64String(response); string decodedResponse = Encoding.UTF8.GetString(bytes); var authResponse = new AuthResponse(new CustomWebResponse() { IsSuccess = true, TextData = decodedResponse }); authResponse.Evaluate(); HandleResponse(authResponse); } catch (Exception e) { // TODO: Log Logger.LogError($"Failed to parse deeplink response: {response}\n{e.ToString()}"); } } }
public void TestDummyLogger() { LogAssert.ignoreFailingMessages = true; var dummy = new DummyLogService(); Logger.Register(dummy); Assert.IsFalse(dummy.LoggedNormal); Assert.IsFalse(dummy.LoggedWarning); Assert.IsFalse(dummy.LoggedError); Logger.Log("AA"); Logger.LogWarning("BB"); try { Logger.LogError("CC"); } catch (Exception) {} Assert.IsTrue(dummy.LoggedNormal); Assert.IsTrue(dummy.LoggedWarning); Assert.IsTrue(dummy.LoggedError); }
public BaseHitObject Parse(string text) { try { string[] splits = text.Split(','); Vector2 pos = new Vector2(ParseUtils.ParseFloat(splits[0]), ParseUtils.ParseFloat(splits[1])); float startTime = ParseUtils.ParseFloat(splits[2]) + offset; HitObjectType type = (HitObjectType)ParseUtils.ParseInt(splits[3]); int comboOffset = (int)(type & HitObjectType.ComboOffset) >> 4; type &= ~HitObjectType.ComboOffset; bool isNewCombo = (int)(type & HitObjectType.NewCombo) != 0; type &= ~HitObjectType.NewCombo; var soundType = (SoundType)ParseUtils.ParseInt(splits[4]); var customSample = new CustomSampleInfo(); // Now parse the actual hit objects. BaseHitObject result = null; // If this object is a hit circle if ((type & HitObjectType.Circle) != 0) { result = CreateCircle(pos, isNewCombo, comboOffset); if (splits.Length > 5) { ParseCustomSample(splits[5], customSample); } } else if ((type & HitObjectType.Slider) != 0) { PathType pathType = PathType.Catmull; float length = 0; string[] pointSplits = splits[5].Split('|'); // Find the number of valid slider node points. int pointCount = 1; foreach (var p in pointSplits) { if (p.Length > 1) { pointCount++; } } // Parse node points var nodePoints = new Vector2[pointCount]; nodePoints[0] = Vector2.zero; int pointIndex = 1; foreach (var p in pointSplits) { // Determine which path type was found. if (p.Length == 1) { switch (p) { case "C": pathType = PathType.Catmull; break; case "B": pathType = PathType.Bezier; break; case "L": pathType = PathType.Linear; break; case "P": pathType = PathType.PerfectCurve; break; } continue; } // Parse point position string[] pointPos = p.Split(':'); nodePoints[pointIndex++] = new Vector2(ParseUtils.ParseFloat(pointPos[0]), ParseUtils.ParseFloat(pointPos[1])) - pos; } // Change perfect curve to linear if certain conditions meet. if (nodePoints.Length == 3 && pathType == PathType.PerfectCurve && IsLinearPerfectCurve(nodePoints)) { pathType = PathType.Linear; } // Parse slider repeat count int repeatCount = ParseUtils.ParseInt(splits[6]); if (repeatCount > 9000) { throw new Exception(); } // Osu file has +1 addition to the actual number of repeats. repeatCount = Math.Max(0, repeatCount - 1); if (splits.Length > 7) { length = Math.Max(0, ParseUtils.ParseFloat(splits[7])); } if (splits.Length > 10) { ParseCustomSample(splits[10], customSample); } // Number of repeats + start(1) + end(1) int nodeCount = repeatCount + 2; // Parse per-node sound samples var nodeCustomSamples = new List <CustomSampleInfo>(); for (int i = 0; i < nodeCount; i++) { nodeCustomSamples.Add(customSample.Clone()); } if (splits.Length > 9 && splits[9].Length > 0) { string[] sets = splits[9].Split('|'); for (int i = 0; i < nodeCount; i++) { if (i >= sets.Length) { break; } ParseCustomSample(sets[i], nodeCustomSamples[i]); } } // Set all nodes' sample types to default. var nodeSampleTypes = new List <SoundType>(); for (int i = 0; i < nodeCount; i++) { nodeSampleTypes.Add(soundType); } // Parse per-node sample types if (splits.Length > 8 && splits[8].Length > 0) { string[] nodeSampleSplits = splits[8].Split('|'); for (int i = 0; i < nodeCount; i++) { if (i > nodeSampleSplits.Length) { break; } nodeSampleTypes[i] = (SoundType)ParseUtils.ParseInt(nodeSampleSplits[i]); } } // Map sample types to custom sample infos. var nodeSamples = new List <List <SoundInfo> >(nodeCount); for (int i = 0; i < nodeCount; i++) { nodeSamples.Add(GetSamples(nodeSampleTypes[i], nodeCustomSamples[i])); } result = CreateSlider(pos, isNewCombo, comboOffset, nodePoints, length, pathType, repeatCount, nodeSamples); // Hit sound for the root slider should be played at the end. result.Samples = nodeSamples[nodeSamples.Count - 1]; } else if ((type & HitObjectType.Spinner) != 0) { float endTime = Math.Max(startTime, ParseUtils.ParseFloat(splits[5]) + offset); result = CreateSpinner(pos, isNewCombo, comboOffset, endTime); if (splits.Length > 6) { ParseCustomSample(splits[6], customSample); } } else if ((type & HitObjectType.Hold) != 0) { float endTime = Math.Max(startTime, ParseUtils.ParseFloat(splits[2] + offset)); // I can understand all others except this, because Hold type only exists for Mania mode. if (splits.Length > 5 && !string.IsNullOrEmpty(splits[5])) { string[] sampleSplits = splits[5].Split(':'); endTime = Math.Max(startTime, ParseUtils.ParseFloat(sampleSplits[0])); ParseCustomSample(string.Join(":", sampleSplits.Skip(1).ToArray()), customSample); } result = CreateHold(pos, isNewCombo, comboOffset, endTime + offset); } if (result == null) { Logger.LogVerbose("HitObjectParser.Parse - Unknown hit object for line: " + text); return(null); } result.StartTime = startTime; if (result.Samples.Count == 0) { result.Samples = GetSamples(soundType, customSample); } isFirstObject = false; return(result); } catch (Exception e) { Logger.LogError($"HitObjectParser.Parse - Failed to parse line: {text}, Error: {e.Message}"); } return(null); }
/// <summary> /// Decodes color value for specified line. /// </summary> protected void DecodeColor(T result, string line) { var pair = GetKeyValue(line); bool isCombo = pair.Key.StartsWith("Combo", StringComparison.Ordinal); string[] colorData = pair.Value.Split(','); // Invalid format if (colorData.Length < 3 || colorData.Length > 4) { Logger.LogWarning( $"OsuDecoder.DecodeColor - Invalid color data format. Must be (R, G, B) or (R, G, B, A). ({pair.Value})" ); return; } // Try parse color Color color; try { color = new Color( byte.Parse(colorData[0]) / 255f, byte.Parse(colorData[1]) / 255f, byte.Parse(colorData[2]) / 255f, (colorData.Length > 3 ? byte.Parse(colorData[3]) : 255) / 255f ); } catch (Exception) { Logger.LogWarning( $"OsuDecoder.DecodeColor - Invalid color element. Each element must be a valid byte value. ({pair.Value})" ); return; } // If a combo color property if (isCombo) { IComboColorable colorable = result as IComboColorable; if (colorable == null) { return; } // Remove default combo colors first. if (!hasComboColor) { colorable.ComboColors.Clear(); hasComboColor = true; } // Add color colorable.ComboColors.Add(color); } else { ICustomColorable colorable = result as ICustomColorable; if (colorable == null) { return; } // Add color colorable.CustomColors[pair.Key] = color; } }