<commit_before>﻿// Copyright (c) ppy Pty Ltd <<EMAIL>>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

#nullable disable

using System;
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using osu.Framework.Graphics;
using osu.Game.Storyboards.Drawables;
using osuTK;

namespace osu.Game.Storyboards
{
    public class StoryboardSprite : IStoryboardElementWithDuration
    {
        private readonly List<CommandLoop> loops = new List<CommandLoop>();
        private readonly List<CommandTrigger> triggers = new List<CommandTrigger>();

        public string Path { get; }
        public bool IsDrawable => HasCommands;

        public Anchor Origin;
        public Vector2 InitialPosition;

        public readonly CommandTimelineGroup TimelineGroup = new CommandTimelineGroup();

        public double StartTime
        {
            get
            {
                // To get the initial start time, we need to check whether the first alpha command to exist has an initial value of zero.
                // A start value of zero on an alpha governs, above all else, the first valid display time of a sprite.
                //
                // To make this valid, we need to aggregate all alpha commands across all loops before checking for the first, time-wise, else we could run into a scenario where:
                // L,1000,1
                //  F,0,0,,1          # this NEEDS TO BE considered the StartTime... but has a StartValue greater than zero so won't in the initial pass.
                // F,0,2000,,0        # ..this will be treated as earliest start due to a StartValue of zero.

                double zeroAlphaStartTimeOverride = double.MaxValue;

                var topLevelFirstAlphaCommand = TimelineGroup.Alpha.Commands.FirstOrDefault();
                if (topLevelFirstAlphaCommand?.StartValue == 0)
                    zeroAlphaStartTimeOverride = topLevelFirstAlphaCommand.StartTime;

                foreach (var loop in loops)
                {
                    var loopFirstAlphaCommand = loop.Alpha.Commands.FirstOrDefault();

                    if (loopFirstAlphaCommand == null)
                        continue;

                    double loopFirstAlphaStartTime = loopFirstAlphaCommand.StartTime + loop.LoopStartTime;

                    if (loopFirstAlphaCommand.StartValue == 0)
                    {
                        // Found a loop containing a zero StartValue earlier than previous.
                        zeroAlphaStartTimeOverride = loopFirstAlphaStartTime;
                    }
                    else if (loopFirstAlphaStartTime < zeroAlphaStartTimeOverride)
                    {
                        // If a loop's first alpha command's StartValue is non-zero, we need to check whether the command's StartTime is less than any previously found zero alpha command.
                        // If this is the case, we want to abort zero alpha override logic and use the earliest command time instead.
                        // This is because if the first alpha command is non-zero, the sprite will be shown at that alpha from the time of the first command (of any type, not just alpha).
                        zeroAlphaStartTimeOverride = double.MaxValue;
                        break;
                    }
                }

                if (zeroAlphaStartTimeOverride < double.MaxValue)
                    return zeroAlphaStartTimeOverride;

                // if we got to this point, either no alpha commands were present, or the earliest had a non-zero start value.
                // the sprite's StartTime will be determined by the earliest command, of any type.
                double earliestStartTime = TimelineGroup.StartTime;
                foreach (var l in loops)
                    earliestStartTime = Math.Min(earliestStartTime, l.StartTime);
                return earliestStartTime;
            }
        }<commit_msg>Refactor alpha check to not overwrite sourced overrides with values from later commands<commit_after>﻿// Copyright (c) ppy Pty Ltd <<EMAIL>>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

#nullable disable

using System;
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using osu.Framework.Graphics;
using osu.Game.Storyboards.Drawables;
using osuTK;

namespace osu.Game.Storyboards
{
    public class StoryboardSprite : IStoryboardElementWithDuration
    {
        private readonly List<CommandLoop> loops = new List<CommandLoop>();
        private readonly List<CommandTrigger> triggers = new List<CommandTrigger>();

        public string Path { get; }
        public bool IsDrawable => HasCommands;

        public Anchor Origin;
        public Vector2 InitialPosition;

        public readonly CommandTimelineGroup TimelineGroup = new CommandTimelineGroup();

        public double StartTime
        {
            get
            {
                // To get the initial start time, we need to check whether the first alpha command to exist has an initial value of zero.
                // A start value of zero on an alpha governs, above all else, the first valid display time of a sprite.
                double zeroAlphaStartTimeOverride = double.MaxValue;
                double earliestAlphaTime = double.MaxValue;

                var topLevelFirstAlphaCommand = TimelineGroup.Alpha.Commands.FirstOrDefault();

                if (topLevelFirstAlphaCommand != null)
                {
                    earliestAlphaTime = topLevelFirstAlphaCommand.StartTime;
                    if (topLevelFirstAlphaCommand.StartValue == 0)
                        // The found alpha command has a zero StartValue, so should be used as the new override.
                        zeroAlphaStartTimeOverride = topLevelFirstAlphaCommand.StartTime;
                }

                foreach (var loop in loops)
                {
                    var loopFirstAlphaCommand = loop.Alpha.Commands.FirstOrDefault();

                    if (loopFirstAlphaCommand == null)
                        continue;

                    double loopFirstAlphaStartTime = loopFirstAlphaCommand.StartTime + loop.LoopStartTime;

                    // Found an alpha command with an earlier start time than an override.
                    if (loopFirstAlphaStartTime < earliestAlphaTime)
                    {
                        earliestAlphaTime = loopFirstAlphaStartTime;

                        if (loopFirstAlphaCommand.StartValue == 0)
                        {
                            // The found alpha command has a zero StartValue, so should be used as the new override.
                            zeroAlphaStartTimeOverride = loopFirstAlphaStartTime;
                        }
                        else if (loopFirstAlphaStartTime < zeroAlphaStartTimeOverride)
                        {
                            // The found alpha command's StartValue is non-zero.
                            // In this case, we want to reset any found alpha override (so if this is the new earliest alpha,
                            // we will fall through to the earlier command time logic below).
                            zeroAlphaStartTimeOverride = double.MaxValue;
                            break;
                        }
                    }
                }

                if (zeroAlphaStartTimeOverride < double.MaxValue)
                    return zeroAlphaStartTimeOverride;

                // if we got to this point, either no alpha commands were present, or the earliest had a non-zero start value.
                // the sprite's StartTime will be determined by the earliest command, of any type.
                double earliestStartTime = TimelineGroup.StartTime;
                foreach (var l in loops)
                    earliestStartTime = Math.Min(earliestStartTime, l.StartTime);
                return earliestStartTime;
            }
        }
{'fraction_non_alphanumeric': 0.053943452380952384, 'fraction_numerical': 0.00248015873015873, 'mean_word_length': 1.7829537612146307, 'pattern_counts': {'":': 0, '<': 20, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5513152', 'n_tokens_mistral': 1854, 'n_tokens_neox': 1729, 'n_words': 687}