예제 #1
0
        /// <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>();
            }
        }
예제 #3
0
        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);
        }
예제 #4
0
        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);
        }
예제 #6
0
 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));
 }
예제 #7
0
 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));
 }
예제 #8
0
        /// <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);
        }
예제 #9
0
 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;
         }
     }));
 }
예제 #10
0
        /// <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();
     }
 }
예제 #12
0
        /// <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");
        }
예제 #13
0
        /// <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}");
         }
     };
 }
예제 #15
0
        /// <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;
                }
            }));
        }
예제 #16
0
 /// <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);
 }
예제 #17
0
        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;
                }
            }
        }
예제 #18
0
        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}"
                        );
                }
            }
        }
예제 #19
0
        /// <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;
            }
        }
예제 #20
0
        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");
        }
예제 #21
0
        /// <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
            });
        }
예제 #22
0
 /// <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()}");
         }
     }
 }
예제 #23
0
        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);
        }
예제 #24
0
        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);
        }
예제 #25
0
        /// <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;
            }
        }