Example #1
0
        private void load(HitObjectType mode)
        {
            this.mode = mode;

            switch (mode)
            {
            case HitObjectType.Circle:
                const int count = 10;

                for (int i = 0; i < count; i++)
                {
                    var h = new HitCircle
                    {
                        StartTime = framedClock.CurrentTime + 600 + i * 80,
                        Position  = new Vector2((i - count / 2) * 14),
                    };

                    add(new DrawableHitCircle(h));
                }
                break;

            case HitObjectType.Slider:
                add(new DrawableSlider(new Slider
                {
                    StartTime     = framedClock.CurrentTime + 600,
                    ControlPoints = new List <Vector2>
                    {
                        new Vector2(-200, 0),
                        new Vector2(400, 0),
                    },
                    Length       = 400,
                    Position     = new Vector2(-200, 0),
                    Velocity     = 1,
                    TickDistance = 100,
                }));
                break;

            case HitObjectType.Spinner:
                add(new DrawableSpinner(new Spinner
                {
                    StartTime = framedClock.CurrentTime + 600,
                    Length    = 1000,
                    Position  = new Vector2(0, 0),
                }));
                break;
            }
        }
Example #2
0
 public HitObject(Vector2 pos, double time, HitObjectType type, bool newCombo, int comboSkip,
                  bool normal, bool whistle, bool finish, bool clap, SampleSet sampleSet, SampleSet additionSet,
                  int index, double volume, string filename)
 {
     Pos  = pos;
     Time = time;
     SetObjectType(type);
     NewCombo     = newCombo;
     ComboSkip    = comboSkip;
     Normal       = normal;
     Whistle      = whistle;
     Finish       = finish;
     Clap         = clap;
     SampleSet    = sampleSet;
     AdditionSet  = additionSet;
     CustomIndex  = index;
     SampleVolume = volume;
     Filename     = filename;
 }
Example #3
0
        public Slider(HitObjectType Type, Vector2 Position, double Time, Color Color, double[] VelocityParameters, String[] Parameters) : base(Type, Position, Time, Color)
        {
            this.Parameters = Parameters;
            PointsPosition  = new List <Vector2>();
            Velocity        = ToVelocity(VelocityParameters[0], VelocityParameters[1]);

            String[] SliderValues = Parameters[0].Split('|');
            CurveType = getCurveType(SliderValues[0]);

            for (var i = 0; i < SliderValues.Length - 1; i++)
            {
                String[] RawPoint = SliderValues[i + 1].Split(':');
                int      X        = Int32.Parse(RawPoint[0]) + 64;
                int      Y        = Int32.Parse(RawPoint[1]) + 56;
                PointsPosition.Add(new Vector2(X, Y));
            }

            Length = Math.Round(Double.Parse(Parameters[2]), 4);
        }
Example #4
0
        public HitSlider(Vector2 startPosition, int time, HitObjectType hitType, HitObjectSoundType hitsound,
                         SliderCurveType sliderType, int repeat, float velocity, int numCurves, int length)
        {
            this.startPosition = startPosition;
            this.Position      = startPosition;
            this.Time          = time;

            this.HitSound   = (int)hitsound;
            this.SliderType = sliderType;
            this.HitType    = (int)hitType;

            this.Repeat    = repeat;
            this.Velocity  = velocity;
            this.Length    = length;
            this.NumCurves = numCurves;



            ConstructSlider();
        }
Example #5
0
 public HitObject(Vector2 pos, double time, HitObjectType type, bool newCombo, int comboSkip,
                  bool normal, bool whistle, bool finish, bool clap, SampleSet sampleSet, SampleSet additionSet,
                  int index, double volume, string filename)
 {
     Pos = pos;
     // Let the end position be the same as the start position before changed later for sliders
     EndPos = Pos;
     Time   = time;
     SetObjectType(type);
     NewCombo     = newCombo;
     ComboSkip    = comboSkip;
     Normal       = normal;
     Whistle      = whistle;
     Finish       = finish;
     Clap         = clap;
     SampleSet    = sampleSet;
     AdditionSet  = additionSet;
     CustomIndex  = index;
     SampleVolume = volume;
     Filename     = filename;
 }
Example #6
0
        public static HitObject createObject(string str)
        {
            string[] split = str.Split(',');

            int pos_x  = int.Parse(split[0]);
            int pos_y  = int.Parse(split[1]);
            int offset = int.Parse(split[2]);
            int typeNo = int.Parse(split[3]);

            int comboSkipCount = (typeNo & 0b0100) > 0 ? (typeNo % 128) / 16 + 1 : 0;

            HitObjectType noteType = (HitObjectType)(typeNo & 0b1011);

            int hitsound = int.Parse(split[4]);

            /* rest of the strings are object type dependent */
            string [] etc = new String[split.Length - 5];
            Array.Copy(split, 5, etc, 0, split.Length - 5);

            /* last string is extras */
            string extras = split[split.Length - 1];

            HitObject obj = new HitObject(pos_x, pos_y, offset, noteType, comboSkipCount, hitsound, extras);

            switch (noteType)
            {
            case HitObjectType.Circle:
                return(new Circle(obj, etc));

            case HitObjectType.Slider:
                return(new Slider(obj, etc));

            case HitObjectType.Spinner:
                return(new Spinner(obj, etc));

            default:
                Console.WriteLine("Invalid Object Type Detected");
                return(null);
            }
        }
Example #7
0
        //Gets a count of each type of hitobject in the beatmap
        //Returns an array of 3 ints, which are the counts of Circles, Sliders,
        //and Spinners respectively
        public int[] GetHitObjectsCount()
        {
            //0 = circles, 1 = sliders, 2 = spinners
            int[] counts = new int[3];

            for (int i = 0; i < hitobjects.GetSize(); i++)
            {
                HitObjectType hobject = hitobjects.GetHitObjectType(i);
                if (hobject == HitObjectType.Circle)
                {
                    counts[0]++;
                }
                else if (hobject == HitObjectType.Slider)
                {
                    counts[1]++;
                }
                else if (hobject == HitObjectType.Spinner)
                {
                    counts[2]++;
                }
            }
            return(counts);
        }
Example #8
0
        private HitObject[] parseHitObjects()
        {
            String[]         RawObjects    = getContent("HitObjects");
            List <HitObject> ParsedObjects = new List <HitObject>();

            foreach (String RawObject in RawObjects)
            {
                String[] Parameters = RawObject.Split(',');

                HitObject     Object = new HitObject();
                HitObjectType Type   = (HitObjectType)Int32.Parse(Parameters[3]);
                ColorIndex += (Type.HasFlag(HitObjectType.SkipColor3) ? 4 : 0) + (Type.HasFlag(HitObjectType.SkipColor2) ? 2 : 0) + (Type.HasFlag(HitObjectType.SkipColor1) ? 1 : 0) + (Type.HasFlag(HitObjectType.NewCombo) ? 1 : 0);
                Vector2 Vector = new Vector2(Int32.Parse(Parameters[0]) + 64, Int32.Parse(Parameters[1]) + 56);

                if (Type.HasFlag(HitObjectType.Circle))
                {
                    Object = new Circle(Type, Vector, Int32.Parse(Parameters[2]), Colors[ColorIndex % Colors.Length]);
                }
                else if (Type.HasFlag(HitObjectType.Slider))
                {
                    List <String> SliderParameters = new List <String>();
                    for (int i = 5; i < Parameters.Length; i++)
                    {
                        SliderParameters.Add(Parameters[i]);
                    }
                    int Time = Int32.Parse(Parameters[2]);
                    Object = new Slider(Type, Vector, Time, Colors[ColorIndex % Colors.Length], new double[] { getBPMAt(Time), getSliderVelocityAt(Time) }, SliderParameters.ToArray());
                }
                else if (Type.HasFlag(HitObjectType.Spinner))
                {
                    Object = new Spinner(Type, Vector, Int32.Parse(Parameters[2]), new Color(255, 255, 255), Int32.Parse(Parameters[5]));
                }

                ParsedObjects.Add(Object);
            }
            return(ParsedObjects.ToArray());
        }
Example #9
0
        public HitState GetHitState(int index)
        {
            UIntPtr hitObjectListPointer      = (UIntPtr)OsuProcess.ReadUInt32(BaseAddress + 0x48);
            UIntPtr hitObjectListItemsPointer = (UIntPtr)OsuProcess.ReadUInt32(hitObjectListPointer + 0x4);
            UIntPtr hitObjectPointer          = (UIntPtr)OsuProcess.ReadUInt32(hitObjectListItemsPointer + 0x8 + 0x4 * index);

            HitObjectType type = (HitObjectType)OsuProcess.ReadInt32(hitObjectPointer + 0x18);

            type &= ~HitObjectType.ComboOffset;
            type &= ~HitObjectType.NewCombo;

            var hitState = OsuProcess.ReadBool(hitObjectPointer + 0x84) ? HitState.Hit : HitState.NotHit;

            switch (type)
            {
            case HitObjectType.Slider:
                UIntPtr startHitCirclePointer = (UIntPtr)OsuProcess.ReadUInt32(hitObjectPointer + 0xCC);

                return(OsuProcess.ReadBool(startHitCirclePointer + 0x84) ? hitState | HitState.SliderStartHit : hitState);

            default:
                return(hitState);
            }
        }
Example #10
0
 public bool IsType(HitObjectType type)
 {
     return(Type.HasFlag(type));
 }
Example #11
0
 public bool IsType(HitObjectType type)
 {
     return(Type.IsType(type));
 }
Example #12
0
        // Returns the string of a Hit Circle to be added to the beatmap.
        public string GetHitCircleData(Vector2 position, int time, HitObjectType hitType, HitObjectSoundType hitSound, Vector2 prevPoint)
        {
            var hc = new HitCircle(position, time, hitType, hitSound, prevPoint, maxNoteDistance);

            return(hc.SerializeForOsu());
        }
Example #13
0
        public static string Process(string dir, bool quick = false, bool usem4a = true, bool free = false, bool previewMode = false)
        {
            Console.WriteLine("Combinating beatmap: " + dir.Split('\\').Last());
            Console.WriteLine();

            if (dir.Length < 1)
            {
                Console.WriteLine("No path specified!");
                return(null);
            }

            List <string> osuFiles = new List <string>(Directory.GetFiles(dir, "*.osu"));

            if (osuFiles.Count < 1)
            {
                Console.WriteLine("No .osu files found!");
                return(null);
            }

            List <string> orderedDifficulties = new List <string>();

            orderedDifficulties.Add(osuFiles.Find(f => f.EndsWith("[Easy].osu")));
            orderedDifficulties.Add(osuFiles.Find(f => f.EndsWith("[Normal].osu")));
            orderedDifficulties.Add(osuFiles.Find(f => f.EndsWith("[Hard].osu")));
            orderedDifficulties.Add(osuFiles.Find(f => f.EndsWith("[Expert].osu")));

            if (orderedDifficulties.FindAll(t => t != null).Count < 1)
            {
                return(null);
            }

            Console.WriteLine("Files found:");
            foreach (string s in orderedDifficulties)
            {
                Console.WriteLine("    * " + Path.GetFileName(s));
            }
            Console.WriteLine();
            Console.WriteLine();

            List <BeatmapDifficulty> difficulties = new List <BeatmapDifficulty>();

            foreach (string f in orderedDifficulties)
            {
                if (f == null)
                {
                    difficulties.Add(null);
                    continue;
                }

                BeatmapDifficulty bd = new BeatmapDifficulty();
                difficulties.Add(bd);

                string currentSection = "";

                foreach (string line in File.ReadAllLines(f))
                {
                    string writeLine = line;

                    if (line.StartsWith("Version:"))
                    {
                        bd.VersionName = line.Replace("Version:", "");
                        continue;
                    }

                    if (line.StartsWith("["))
                    {
                        currentSection = line.Replace("[", "").Replace("]", "");
                    }
                    else if (line.Length > 0)
                    {
                        string[] split = line.Split(',');
                        string[] var   = line.Split(':');
                        string   key   = string.Empty;
                        string   val   = string.Empty;
                        if (var.Length > 1)
                        {
                            key = var[0].Trim();
                            val = var[1].Trim();
                        }

                        switch (currentSection)
                        {
                        case "General":
                            switch (key)
                            {
                            case "AudioFilename":
                                writeLine = "AudioFilename: audio.mp3";
                                break;
                            }

                            break;

                        case "Difficulty":
                            switch (key)
                            {
                            case "HPDrainRate":
                                bd.DifficultyHpDrainRate = Math.Min((byte)10, Math.Max((byte)0, byte.Parse(val)));
                                break;

                            case "CircleSize":
                                bd.DifficultyCircleSize = Math.Min((byte)10, Math.Max((byte)0, byte.Parse(val)));
                                break;

                            case "OverallDifficulty":
                                bd.DifficultyOverall = Math.Min((byte)10, Math.Max((byte)0, byte.Parse(val)));
                                //if (!hasApproachRate) DifficultyApproachRate = DifficultyOverall;
                                break;

                            case "SliderMultiplier":
                                bd.DifficultySliderMultiplier =
                                    Math.Max(0.4, Math.Min(3.6, Double.Parse(val, nfi)));
                                break;

                            case "SliderTickRate":
                                bd.DifficultySliderTickRate =
                                    Math.Max(0.5, Math.Min(8, Double.Parse(val, nfi)));
                                break;
                            }

                            break;

                        case "HitObjects":
                        {
                            HitObjectType type    = (HitObjectType)Int32.Parse(split[3]) & ~HitObjectType.ColourHax;
                            bool          slider  = (type & HitObjectType.Slider) > 0;
                            bool          spinner = (type & HitObjectType.Spinner) > 0;
                            int           time    = (int)Decimal.Parse(split[2], nfi);
                            int           endTime = spinner ? (int)Decimal.Parse(split[5], nfi) : time;

                            int       repeatCount        = 0;
                            double    length             = 0;
                            bool      hadEndpointSamples = false;
                            bool      hold = false;
                            SampleSet ss = SampleSet.None, ssa = SampleSet.None;
                            string[]  samplestring = null;

                            if (slider)
                            {
                                repeatCount        = Int32.Parse(split[6], nfi);
                                length             = double.Parse(split[7], nfi);
                                hadEndpointSamples = split.Length >= 9;

                                hold = (repeatCount > 1 && length < 50) ||
                                       (repeatCount > 4 && length < 100) ||
                                       (hadEndpointSamples && split[4] == "4");

                                if (split.Length > 10)
                                {
                                    samplestring = split[10].Split(':');
                                }
                            }
                            else if (spinner)
                            {
                                if (split.Length > 6)
                                {
                                    samplestring = split[6].Split(':');
                                }
                            }
                            else
                            {
                                if (split.Length > 5)
                                {
                                    samplestring = split[5].Split(':');
                                }
                            }

                            if (samplestring != null)
                            {
                                ss = (SampleSet)Convert.ToInt32(samplestring[0]);
                                if (samplestring.Length > 0)
                                {
                                    ssa = (SampleSet)Convert.ToInt32(samplestring[1]);
                                }
                            }

                            // take the slider's slide sampleset from 20ms after the head in case the head has a different sampleset
                            ControlPoint cp = bd.controlPointAt(slider ? time + 20 : endTime + 5);

                            StringBuilder builder = new StringBuilder();
                            builder.Append(MakeSampleset(cp, ss, ssa));

                            // Object commons
                            builder.Append(',');
                            builder.Append(split[0]);     // X

                            builder.Append(',');
                            builder.Append(split[1]);     // Y

                            builder.Append(',');
                            builder.Append(time.ToString(nfi));     // time

                            HitObjectType type2 = (HitObjectType)Int32.Parse(split[3]);
                            builder.Append(',');
                            builder.Append(hold ? (int)(type2 | HitObjectType.Hold) : (int)type2);     // object type

                            string soundAdditions = MakeSoundAdditions(split[4]);
                            builder.Append(',');
                            builder.Append(soundAdditions);     // sound additions

                            //add addition difficulty-specific information
                            if (slider)
                            {
                                builder.Append(',');
                                builder.Append(split[5]);     // curve type, all control points

                                builder.Append(',');
                                builder.Append(repeatCount.ToString(nfi));     // repeat count

                                builder.Append(',');
                                builder.Append(length.ToString(nfi));     // curve length

                                string[] additions;
                                if (hadEndpointSamples)
                                {
                                    additions = split[8].Split('|');
                                }
                                else
                                {
                                    additions = new string[0];
                                }

                                // nodal hitsamples
                                builder.Append(',');
                                for (int repeatNo = 0; repeatNo <= repeatCount; repeatNo++)
                                {
                                    if (repeatNo > 0)
                                    {
                                        builder.Append('|');
                                    }
                                    if (repeatNo < additions.Length)
                                    {
                                        builder.Append(MakeSoundAdditions(additions[repeatNo]));
                                    }
                                    else
                                    {
                                        builder.Append(soundAdditions);
                                    }
                                }

                                double velocity = bd.VelocityAt(time);

                                //velocity and scoring distance.
                                builder.Append(',');
                                builder.Append(velocity.ToString(nfi));

                                builder.Append(',');
                                builder.Append(bd.ScoringDistanceAt(time).ToString(nfi));

                                double ReboundTime = 1000 * length / velocity;

                                double currTime = time;
                                cp = bd.controlPointAt(currTime + 5);

                                string[] node_samples;
                                if (split.Length > 9)
                                {
                                    // osu!'s separator is different
                                    node_samples = split[9].Split('|');
                                }
                                else
                                {
                                    node_samples = new string[0];
                                }

                                // nodal samplesets
                                for (int repeatNo = 0; repeatNo <= repeatCount; repeatNo++)
                                {
                                    SampleSet node_ss  = ss;
                                    SampleSet node_ssa = ssa;

                                    if (repeatNo < node_samples.Length)
                                    {
                                        string[] pair = node_samples[repeatNo].Split(':');
                                        node_ss = (SampleSet)Convert.ToInt32(pair[0]);
                                        if (pair.Length > 0)
                                        {
                                            node_ssa = (SampleSet)Convert.ToInt32(pair[1]);
                                        }
                                    }

                                    cp = bd.controlPointAt(currTime + 5);
                                    builder.Append(repeatNo == 0 ? ',' : ':');
                                    builder.Append(MakeSampleset(cp, node_ss, node_ssa));
                                    currTime += ReboundTime;
                                }
                            }

                            if (spinner)
                            {
                                builder.Append(',');
                                builder.Append(split[5]);     // end time
                            }

                            bd.HitObjectLines.Add(new HitObjectLine {
                                    StringRepresentation = builder.ToString(), Time = Int32.Parse(line.Split(',')[2])
                                });
                            continue;     //skip direct output
                        }

                        case "TimingPoints":
                        {
                            ControlPoint cp = new ControlPoint(Double.Parse(split[0], nfi),
                                                               Double.Parse(split[1], nfi),
                                                               split[2][0] == '0' ? TimeSignatures.SimpleQuadruple : (TimeSignatures)Int32.Parse(split[2]),
                                                               (SampleSet)Int32.Parse(split[3]),
                                                               split.Length > 4
                                        ? (CustomSampleSet)Int32.Parse(split[4])
                                        : CustomSampleSet.Default,
                                                               Int32.Parse(split[5]),
                                                               split.Length > 6 ? split[6][0] == '1' : true,
                                                               split.Length > 7 ? split[7][0] == '1' : false);
                            bd.ControlPoints.Add(cp);
                            break;
                        }
                        }
                    }

                    bd.HeaderLines.Add(writeLine);
                }
            }


            string metadata = dir + "\\metadata.txt";
            string Artist = "", Title = "", Creator = "";

            if (File.Exists(metadata))
            {
                foreach (string line in File.ReadAllLines(metadata))
                {
                    if (line.Length == 0)
                    {
                        continue;
                    }

                    string[] var = line.Split(':');
                    string   key = string.Empty;
                    string   val = string.Empty;
                    if (var.Length > 1)
                    {
                        key = line.Substring(0, line.IndexOf(':'));
                        val = line.Substring(line.IndexOf(':') + 1).Trim();
                        switch (key)
                        {
                        case "Artist":
                            Artist = val;
                            break;

                        case "Title":
                            Title = val;
                            break;

                        case "Creator":
                            Creator = val;
                            break;
                        }
                    }
                }
            }

            string baseName    = Artist + " - " + Title + " (" + Creator + ")";
            string oscFilename = baseName + ".osc";

            foreach (BeatmapDifficulty d in difficulties)
            {
                if (d != null)
                {
                    ListHelper.StableSort(d.HitObjectLines);
                }
            }

            headerContent = difficulties.Find(d => d != null).HeaderLines;

            string[] splitdir = dir.Split('\\');

            string osz2Filename;

            string baseFileWithLocation = baseName.Substring(baseName.LastIndexOf("\\", StringComparison.Ordinal) + 1);

            if (free && DistBuild)
            {
                osz2Filename = baseFileWithLocation + ".osf2";
            }
            else
            {
                osz2Filename = baseFileWithLocation + (usem4a && !DistBuild ? ".m4a.osz2" : ".osz2");
            }

            string audioFilename = null;

            if (usem4a)
            {
                audioFilename = "";
                foreach (string s in Directory.GetFiles(dir, "*.m4a"))
                {
                    if (s.Contains("_lq"))
                    {
                        continue;
                    }

                    audioFilename = s;
                    break;
                }
            }
            else
            {
                audioFilename = Directory.GetFiles(dir, "*.mp3")[0];
            }

            File.Delete(osz2Filename);

            //write the package initially so we can use it for score testing purposes.
            writePackage(oscFilename, osz2Filename, audioFilename, difficulties, orderedDifficulties);

            //scoring

            Player.Beatmap  = new Beatmap(osz2Filename);
            Player.Autoplay = true;

            //Working on the scoring algorithm for osu!s
            //Basically I need to calculate the total possible score from hitobjects before any multipliers kick in...
            //but I need to know this before the beatmap is loaded.

            //So this means running through the beatmap as if it was being played at the time of package creation
            //(inside BeatmapCombinator).  After I find the score that can be achieved, I can figure out what multiplier
            //i need in order to pad it out to a fixed 1,000,000 max score.

            //I am sure I will run into some rounding issues once I get that far, but we'll see how things go :p.

            ITimeSource         oldTimeSource = Clock.AudioTimeSource;
            FakeAudioTimeSource source        = new FakeAudioTimeSource();

            Clock.AudioTimeSource = source;

            SoundEffectPlayer     oldEffect = AudioEngine.Effect;
            BackgroundAudioPlayer oldMusic  = AudioEngine.Music;

            AudioEngine.Music  = null;
            AudioEngine.Effect = null;

            headerContent.Remove("[HitObjects]");

            headerContent.Add(string.Empty);
            headerContent.Add("[ScoringMultipliers]");

            if (quick)
            {
                processDifficulty(Difficulty.Easy, true);
                processDifficulty(Difficulty.Normal, true);
                processDifficulty(Difficulty.Hard, true);
                processDifficulty(Difficulty.Expert, true);
            }
            else
            {
                if (orderedDifficulties[(int)Difficulty.Easy] != null)
                {
                    headerContent.Add("0: " + processDifficulty(Difficulty.Easy).ToString("G17", nfi));
                }
                if (orderedDifficulties[(int)Difficulty.Normal] != null)
                {
                    headerContent.Add("1: " + processDifficulty(Difficulty.Normal).ToString("G17", nfi));
                }
                if (orderedDifficulties[(int)Difficulty.Expert] != null)
                {
                    headerContent.Add("3: " + processDifficulty(Difficulty.Expert).ToString("G17", nfi));
                }
            }

            if (healthMultiplier != 0)
            {
                headerContent.Add("HP:" + healthMultiplier.ToString("G17", nfi));
            }

            headerContent.Add(string.Empty);
            headerContent.Add("[HitObjects]");

            Player.Beatmap.Dispose();

            Clock.AudioTimeSource = oldTimeSource;
            AudioEngine.Effect    = oldEffect;
            AudioEngine.Music     = oldMusic;

            //only change the filename here so it is not treated as a preview above (else previewpoints will not be filled before necessary).
            if (previewMode)
            {
                osz2Filename = osz2Filename.Replace(".osf2", "_preview.osf2");
            }

            //write the package a second time with new multiplier header data.
            writePackage(oscFilename, osz2Filename, audioFilename, difficulties, orderedDifficulties);

            return(osz2Filename);
        }
Example #14
0
 public static bool IsType(this HitObjectType a, HitObjectType b)
 {
     return((a & b) > 0); //adding in binary results in 0 if both are equal
 }
Example #15
0
 Class321 class = new Class321(this.class297_0, this.Position, this.StartTime, this.Type.IsType(HitObjectType.NewCombo), this.SoundType, this.curveTypes_0, this.SegmentCount, this.SpatialLength, list2, list, this.int_0);
Example #16
0
        private void ParseHitObjects(string line)
        {
            string[] tokens = line.Split(',');

            Point position = new Point(Convert.ToInt32(tokens[0]), Convert.ToInt32(tokens[1]));

            int startTime = Convert.ToInt32(tokens[2]);

            HitObjectType type = (HitObjectType)int.Parse(tokens[3]);

            int comboOffset = (int)(type & HitObjectType.ComboOffset) >> 4;

            type &= ~HitObjectType.ComboOffset;

            bool isNewCombo = type.HasFlag(HitObjectType.NewCombo);

            type &= ~HitObjectType.NewCombo;

            HitSoundType hitSound = (HitSoundType)Convert.ToInt32(tokens[4]);

            HitObject hitObject = null;

            string[] extrasSplit  = tokens.Last().Split(':');
            int      extrasOffset = type.HasFlag(HitObjectType.Hold) ? 1 : 0;
            Extras   extras       = tokens.Last().Contains(":") ? new Extras
            {
                SampleSet      = (SampleSet)Convert.ToInt32(extrasSplit[0 + extrasOffset]),
                AdditionSet    = (SampleSet)Convert.ToInt32(extrasSplit[1 + extrasOffset]),
                CustomIndex    = Convert.ToInt32(extrasSplit[2 + extrasOffset]),
                Volume         = Convert.ToInt32(extrasSplit[3 + extrasOffset]),
                SampleFileName = string.IsNullOrEmpty(extrasSplit[4 + extrasOffset]) ? null : extrasSplit[4 + extrasOffset]
            } : new Extras();

            switch (type)
            {
            case HitObjectType.Circle:
            {
                if (Beatmap.GeneralSection.Mode == Ruleset.Standard)
                {
                    hitObject = new Circle(position, startTime, startTime, hitSound, extras, isNewCombo, comboOffset);
                }
                else if (Beatmap.GeneralSection.Mode == Ruleset.Taiko)
                {
                    hitObject = new TaikoHit(position, startTime, startTime, hitSound, extras, isNewCombo, comboOffset);
                }
                else if (Beatmap.GeneralSection.Mode == Ruleset.Fruits)
                {
                    hitObject = new CatchFruit(position, startTime, startTime, hitSound, extras, isNewCombo, comboOffset);
                }
                else if (Beatmap.GeneralSection.Mode == Ruleset.Mania)
                {
                    hitObject = new ManiaHit(position, startTime, startTime, hitSound, extras, isNewCombo, comboOffset);
                }
            }
            break;

            case HitObjectType.Slider:
            {
                CurveType    curveType    = ParseHelper.GetCurveType(tokens[5].Split('|')[0][0]);
                List <Point> sliderPoints = ParseHelper.GetSliderPoints(tokens[5].Split('|'));

                int    repeats     = Convert.ToInt32(tokens[6]);
                double pixelLength = ParseHelper.ToDouble(tokens[7]);

                int endTime = CalculateEndTime(startTime, repeats, pixelLength);

                List <HitSoundType> edgeHitSounds = new List <HitSoundType>();
                if (tokens.Length > 8 && tokens[8].Length > 0)
                {
                    edgeHitSounds = new List <HitSoundType>();
                    edgeHitSounds = Array.ConvertAll(tokens[8].Split('|'), s => (HitSoundType)Convert.ToInt32(s)).ToList();
                }

                List <Tuple <SampleSet, SampleSet> > edgeAdditions = new List <Tuple <SampleSet, SampleSet> >();
                if (tokens.Length > 9 && tokens[9].Length > 0)
                {
                    edgeAdditions = new List <Tuple <SampleSet, SampleSet> >();
                    foreach (var s in tokens[9].Split('|'))
                    {
                        edgeAdditions.Add(new Tuple <SampleSet, SampleSet>((SampleSet)Convert.ToInt32(s.Split(':').First()), (SampleSet)Convert.ToInt32(s.Split(':').Last())));
                    }
                }

                if (Beatmap.GeneralSection.Mode == Ruleset.Standard)
                {
                    hitObject = new Slider(position, startTime, endTime, hitSound, curveType, sliderPoints, repeats,
                                           pixelLength, edgeHitSounds, edgeAdditions, extras, isNewCombo, comboOffset);
                }
                else if (Beatmap.GeneralSection.Mode == Ruleset.Taiko)
                {
                    hitObject = new TaikoDrumroll(position, startTime, endTime, hitSound, curveType, sliderPoints,
                                                  repeats, pixelLength, edgeHitSounds, edgeAdditions, extras, isNewCombo, comboOffset);
                }
                else if (Beatmap.GeneralSection.Mode == Ruleset.Fruits)
                {
                    hitObject = new CatchDroplets(position, startTime, endTime, hitSound, curveType, sliderPoints,
                                                  repeats, pixelLength, edgeHitSounds, edgeAdditions, extras, isNewCombo, comboOffset);
                }
            }
            break;

            case HitObjectType.Spinner:
            {
                int endTime = Convert.ToInt32(tokens[5].Trim());

                if (Beatmap.GeneralSection.Mode == Ruleset.Standard)
                {
                    hitObject = new Spinner(position, startTime, endTime, hitSound, extras, isNewCombo, comboOffset);
                }
                else if (Beatmap.GeneralSection.Mode == Ruleset.Taiko)
                {
                    hitObject = new TaikoSpinner(position, startTime, endTime, hitSound, extras, isNewCombo, comboOffset);
                }
                else if (Beatmap.GeneralSection.Mode == Ruleset.Fruits)
                {
                    hitObject = new CatchSpinner(position, startTime, endTime, hitSound, extras, isNewCombo, comboOffset);
                }
            }
            break;

            case HitObjectType.Hold:
            {
                string[] additions = tokens[5].Split(':');
                int      endTime   = Convert.ToInt32(additions[0].Trim());
                hitObject = new ManiaHold(position, startTime, endTime, hitSound, extras, isNewCombo, comboOffset);
            }
            break;
            }

            Beatmap.HitObjects.Add(hitObject);
        }
Example #17
0
 // Token: 0x0600176B RID: 5995
 // RVA: 0x0001484E File Offset: 0x00012A4E
 public bool IsType(HitObjectType type)
 {
     return this.Type.IsType(type);
 }
        public void LoadFile()
        {
            spriteManager.ForwardPlayOptimisedAdd = true;

            beatmap.ControlPoints.Clear();

            FileSection currentSection = FileSection.Unknown;

            //Check file just before load -- ensures no modifications have occurred.
            //BeatmapManager.Current.UpdateChecksum();

            List <string> readableFiles = new List <string>();

            readableFiles.Add(beatmap.BeatmapFilename);

            string storyBoardFile = beatmap.StoryboardFilename;

            //if (beatmap.CheckFileExists(storyBoardFile))
            //    readableFiles.Add(storyBoardFile);

            //bool hasCustomColours = false;
            //bool firstColour = true;
            bool hitObjectPreInit = false;
            bool lastAddedSpinner = false;

            //bool verticalFlip = (GameBase.Mode == OsuModes.Play && Player.currentScore != null &&
            //                     ModManager.CheckActive(Player.currentScore.enabledMods, Mods.HardRock));

            int linenumber;

            //The first file will be the actual .osu file.
            //The second file is the .osb for now.
            for (int fn = 0; fn < readableFiles.Count; fn++)
            {
                if (fn > 0)
                {
                    break;
                    //don't handle storyboarding yet.

                    //baseReader = new StreamReader(BeatmapManager.Current.GetFileStream(readableFiles[fn]));
                    //LocatedTextReaderWrapper ltr = new LocatedTextReaderWrapper(baseReader);
                    //osqEngine = new osq.Encoder(ltr);
                }

                //using (TextReader reader = (fn == 0 ? (TextReader)new StreamReader(BeatmapManager.Current.GetFileStream(readableFiles[fn])) : new StringReader(osqEngine.Encode())))
                TextReader reader = new StreamReader(beatmap.GetFileStream(readableFiles[fn]));
                {
                    linenumber = 0;

                    string line = null;

                    bool readNew   = true;
                    int  objnumber = 0;

                    bool headerReadFinished = false;

                    while (true)
                    {
                        if (readNew)
                        {
                            line = reader.ReadLine();
                            if (line == null)
                            {
                                break;
                            }
                            linenumber++;
                        }

                        readNew = true;

                        if (line.Length == 0 || line.StartsWith(" ") || line.StartsWith("_") || line.StartsWith("//"))
                        {
                            continue;
                        }

                        //if (currentSection == FileSection.Events) ParseVariables(ref line);

                        string key = string.Empty;
                        string val = string.Empty;

                        if (!headerReadFinished)
                        {
                            string[] var = line.Split(':');

                            if (var.Length > 1)
                            {
                                key = var[0].Trim();
                                val = var[1].Trim();
                            }
                        }

                        if (line[0] == '[')
                        {
                            try
                            {
                                currentSection =
                                    (FileSection)Enum.Parse(typeof(FileSection), line.Trim('[', ']'));
                                if (currentSection == FileSection.HitObjects)
                                {
                                    headerReadFinished = true;
                                }
                            }
                            catch (Exception)
                            {
                            }

                            continue;
                        }

                        switch (currentSection)
                        {
                        case FileSection.ScoringMultipliers:
                            if (key == "HP")
                            {
                                beatmap.HpStreamAdjustmentMultiplier = double.Parse(val, GameBase.nfi);
                            }
                            else
                            {
                                Difficulty diff = (Difficulty)int.Parse(key);
                                beatmap.DifficultyInfo[diff] = new BeatmapDifficultyInfo(diff)
                                {
                                    ComboMultiplier = double.Parse(val, GameBase.nfi)
                                };
                            }

                            break;

                        case FileSection.General:
                            switch (key)
                            {
                            case "CountdownOffset":
                                if (val.Length > 0)
                                {
                                    beatmap.CountdownOffset = int.Parse(val);
                                }

                                break;
                            }

                            break;

                        case FileSection.TimingPoints:
                        {
                            string[] split = line.Split(',');

                            if (split.Length > 2)
                            {
                                beatmap.ControlPoints.Add(
                                    new ControlPoint(double.Parse(split[0], GameBase.nfi),
                                                     double.Parse(split[1], GameBase.nfi),
                                                     split[2][0] == '0' ? TimeSignatures.SimpleQuadruple : (TimeSignatures)int.Parse(split[2]),
                                                     (SampleSet)int.Parse(split[3]),
                                                     split.Length > 4
                                                ? (CustomSampleSet)int.Parse(split[4])
                                                : CustomSampleSet.Default,
                                                     int.Parse(split[5]),
                                                     split.Length > 6 ? split[6][0] == '1' : true,
                                                     split.Length > 7 ? split[7][0] == '1' : false));
                            }
                            break;
                        }

                        case FileSection.Editor:
                            switch (key)
                            {
                            case "Bookmarks":
                                if (val.Length > 0)
                                {
                                    beatmap.StreamSwitchPoints = new List <int>();
                                    string[] points = val.Split(',');
                                    foreach (string point in points)
                                    {
                                        beatmap.StreamSwitchPoints.Add(int.Parse(point.Trim()));
                                    }
                                }

                                break;
                            }

                            //not relevant
                            continue;

                        case FileSection.Difficulty:
                            switch (key)
                            {
                            case "HPDrainRate":
                                beatmap.DifficultyHpDrainRate = Math.Min((byte)10, Math.Max((byte)0, byte.Parse(val)));
                                break;

                            case "CircleSize":
                                beatmap.DifficultyCircleSize = Math.Min((byte)10, Math.Max((byte)0, byte.Parse(val)));
                                break;

                            case "OverallDifficulty":
                                beatmap.DifficultyOverall = Math.Min((byte)10, Math.Max((byte)0, byte.Parse(val)));
                                //if (!hasApproachRate) DifficultyApproachRate = DifficultyOverall;
                                break;

                            case "SliderMultiplier":
                                beatmap.DifficultySliderMultiplier =
                                    Math.Max(0.4, Math.Min(3.6, double.Parse(val, GameBase.nfi)));
                                break;

                            case "SliderTickRate":
                                beatmap.DifficultySliderTickRate =
                                    Math.Max(0.5, Math.Min(8, double.Parse(val, GameBase.nfi)));
                                break;

                                /*case "ApproachRate":
                                 *  beatmap.DifficultyApproachRate = Math.Min((byte)10, Math.Max((byte)0, byte.Parse(val)));
                                 *  hasApproachRate = true;
                                 *  break;*/
                            }

                            break;

                        case FileSection.HitObjects:
                        {
                            if (fn > 0)
                            {
                                continue;
                            }

                            if (!hitObjectPreInit)
                            {
                                //ComboColoursReset();
                                hitObjectPreInit = true;
                            }

                            string[] split = line.Split(',');

                            int offset = 0;

                            Difficulty difficulty = (Difficulty)int.Parse(split[offset++]);


                            SampleSetInfo ssi = parseSampleSet(split[offset++]);

                            int x    = (int)Math.Max(0, Math.Min(512, decimal.Parse(split[offset++], GameBase.nfi)));
                            int y    = (int)Math.Max(0, Math.Min(512, decimal.Parse(split[offset++], GameBase.nfi)));
                            int time = (int)decimal.Parse(split[offset++], GameBase.nfi);

                            if (objnumber == 0)
                            {
                                CountdownTime = time;
                            }
                            else
                            {
                                CountdownTime = Math.Min(CountdownTime, time);
                            }
                            objnumber++;

                            if (!shouldLoadDifficulty(difficulty))
                            {
                                continue;
                            }

                            HitObjectType      type        = (HitObjectType)int.Parse(split[offset], GameBase.nfi) & ~HitObjectType.ColourHax;
                            int                comboOffset = (Convert.ToInt32(split[offset++], GameBase.nfi) >> 4) & 7; // mask out bits 5-7 for combo offset.
                            HitObjectSoundType soundType   = (HitObjectSoundType)int.Parse(split[offset++], GameBase.nfi);

                            Vector2 pos = new Vector2(x, y);

                            bool newCombo = (type & HitObjectType.NewCombo) > 0 || lastAddedSpinner || StreamHitObjects[(int)difficulty] == null || StreamHitObjects[(int)difficulty].Count == 0;

                            HitObject h = null;

                            //used for new combo forcing after a spinner.
                            lastAddedSpinner = h is Spinner;

                            if ((type & HitObjectType.Circle) > 0)
                            {
                                h = hitFactory.CreateHitCircle(pos, time, newCombo, soundType, newCombo ? comboOffset : 0);
                            }
                            else if ((type & (HitObjectType.Slider | HitObjectType.Hold)) > 0)
                            {
                                CurveTypes                curveType   = CurveTypes.Bezier;
                                int                       repeatCount = 0;
                                double                    length      = 0;
                                List <Vector2>            points      = new List <Vector2>();
                                List <HitObjectSoundType> sounds      = null;

                                string[] pointsplit = split[offset++].Split('|');
                                for (int i = 0; i < pointsplit.Length; i++)
                                {
                                    if (pointsplit[i].Length == 1)
                                    {
                                        switch (pointsplit[i])
                                        {
                                        case "C":
                                            curveType = CurveTypes.Catmull;
                                            break;

                                        case "B":
                                            curveType = CurveTypes.Bezier;
                                            break;

                                        case "L":
                                            curveType = CurveTypes.Linear;
                                            break;

                                        case "P":
                                            curveType = CurveTypes.PerfectCurve;
                                            break;
                                        }

                                        continue;
                                    }

                                    string[] temp = pointsplit[i].Split(':');
                                    Vector2  v    = new Vector2((float)Convert.ToDouble(temp[0], GameBase.nfi),
                                                                (float)Convert.ToDouble(temp[1], GameBase.nfi));
                                    points.Add(v);
                                }

                                repeatCount = Convert.ToInt32(split[offset++], GameBase.nfi);

                                length = Convert.ToDouble(split[offset++], GameBase.nfi);

                                List <SampleSetInfo> listSampleSets = null;

                                //Per-endpoint Sample Additions
                                if (split[offset].Length > 0)
                                {
                                    string[] adds = split[offset++].Split('|');

                                    if (adds.Length > 0)
                                    {
                                        sounds = new List <HitObjectSoundType>(adds.Length);
                                        for (int i = 0; i < adds.Length; i++)
                                        {
                                            int sound;
                                            int.TryParse(adds[i], out sound);
                                            sounds.Add((HitObjectSoundType)sound);
                                        }
                                    }
                                }
                                else
                                {
                                    offset += 1;
                                }

                                if (split.Length > 13)
                                {
                                    string[] samplesets = split[13].Split(':');
                                    listSampleSets = new List <SampleSetInfo>(samplesets.Length);
                                    for (int i = 0; i < samplesets.Length; i++)
                                    {
                                        SampleSetInfo node_ssi = parseSampleSet(samplesets[i]);
                                        listSampleSets.Add(node_ssi);
                                    }
                                }

                                if ((repeatCount > 1 && length < 50) ||
                                    (repeatCount > 4 && length < 100) ||
                                    (type & HitObjectType.Hold) > 0)
                                {
                                    h = hitFactory.CreateHoldCircle(pos, time, newCombo, soundType, repeatCount, length, sounds, newCombo ? comboOffset : 0, Convert.ToDouble(split[offset++], GameBase.nfi), Convert.ToDouble(split[offset++], GameBase.nfi), listSampleSets);
                                }
                                else
                                {
                                    h = hitFactory.CreateSlider(pos, time, newCombo, soundType, curveType, repeatCount, length, points, sounds, newCombo ? comboOffset : 0, Convert.ToDouble(split[offset++], GameBase.nfi), Convert.ToDouble(split[offset++], GameBase.nfi), listSampleSets);
                                }
                            }
                            else if ((type & HitObjectType.Spinner) > 0)
                            {
                                h = hitFactory.CreateSpinner(time, Convert.ToInt32(split[offset++], GameBase.nfi), soundType);
                            }

                            //Make sure we have a valid  hitObject and actually add it to this manager.
                            if (h != null)
                            {
                                h.SampleSet = ssi;
                                Add(h, difficulty);
                            }
                        }
                        break;

                        case FileSection.Unknown:
                            continue;     //todo: readd this?  not sure if we need it anymore.
                        }
                    }
                }
            }

            PostProcessing();
        }
Example #19
0
        protected override IEnumerable <RushHitObject> ConvertHitObject(HitObject original, IBeatmap beatmap)
        {
            Random random = new Random((int)original.StartTime);

            const float  air_position_cutoff    = 180f;
            const float  ground_position_cutoff = 220f;
            const double etna_cutoff            = 200d;
            const double repeat_cutoff          = 100d;
            const double sawblade_cutoff        = 0.9f;
            const double airsawblade_cutoff     = 0.95f;

            var           sampleLane = original.Samples.Any(s => s.Name == HitSampleInfo.HIT_CLAP || s.Name == HitSampleInfo.HIT_WHISTLE) ? LanedHitLane.Air : LanedHitLane.Ground;
            LanedHitLane? positionLane = null, sawbladeLane = null;
            HitObjectType hitObjectType = HitObjectType.Minion;
            bool          bothLanes     = false;

            if (original is IHasPosition hasPosition)
            {
                if (hasPosition.Y < air_position_cutoff)
                {
                    positionLane = LanedHitLane.Air;
                }
                else if (hasPosition.Y > ground_position_cutoff)
                {
                    positionLane = LanedHitLane.Ground;
                }
                else
                {
                    bothLanes = true;
                }
            }

            if (original is IHasEndTime hasEndTime)
            {
                // etna sliders don't convert well, so just make them regular minions
                if (hasEndTime.Duration <= etna_cutoff)
                {
                    hitObjectType = HitObjectType.Minion;
                }
                else if (original is IHasDistance)
                {
                    hitObjectType = HitObjectType.NoteSheet;
                }
                else
                {
                    hitObjectType = HitObjectType.MiniBoss;
                }
            }

            // temporary sawblade selection logic
            // 1) can only convert minions or dual orbs
            // 2) ground sawblades are more common than air sawblades
            // 3) air sawblades can only exist during kiai sections
            // if (hitObjectType == HitObjectType.Minion)
            // {
            //     var rnd = random.NextDouble();
            //     sawbladeLane = LanedHitLane.Ground;
            //     if (rnd >= sawblade_cutoff)
            //         hitObjectType = HitObjectType.Sawblade;
            //     if (original.Kiai && rnd >= airsawblade_cutoff)
            //         sawbladeLane = LanedHitLane.Air;
            // }

            switch (hitObjectType)
            {
            case HitObjectType.Sawblade:
                if (bothLanes)
                {
                    yield return(new Minion
                    {
                        Lane = (sawbladeLane ?? sampleLane).Opposite(),
                        Samples = original.Samples,
                        StartTime = original.StartTime
                    });
                }

                yield return(new Sawblade
                {
                    Lane = sawbladeLane ?? sampleLane,
                    StartTime = original.StartTime
                });

                break;

            case HitObjectType.Minion:
                if (bothLanes)
                {
                    yield return(new DualOrb
                    {
                        Samples = original.Samples,
                        StartTime = original.StartTime,
                    });
                }
                else
                {
                    yield return(new Minion
                    {
                        Lane = positionLane ?? sampleLane,
                        Samples = original.Samples,
                        StartTime = original.StartTime,
                    });
                }

                break;

            case HitObjectType.MiniBoss:
                yield return(new MiniBoss
                {
                    Samples = original.Samples,
                    StartTime = original.StartTime,
                    EndTime = original.GetEndTime()
                });

                break;

            case HitObjectType.NoteSheet:
                var sheetLane = positionLane ?? sampleLane;

                if (bothLanes || sheetLane == LanedHitLane.Ground)
                {
                    yield return(new NoteSheet
                    {
                        Lane = LanedHitLane.Ground,
                        Samples = original.Samples,
                        StartTime = original.StartTime,
                        EndTime = original.GetEndTime()
                    });
                }

                if (bothLanes || sheetLane == LanedHitLane.Air)
                {
                    yield return(new NoteSheet
                    {
                        Lane = LanedHitLane.Air,
                        Samples = bothLanes ? new List <HitSampleInfo>() : original.Samples,
                        StartTime = original.StartTime,
                        EndTime = original.GetEndTime()
                    });
                }

                if (!bothLanes && original is IHasRepeats hasRepeats && hasRepeats.RepeatCount > 0)
                {
                    var duration       = original.GetEndTime() - original.StartTime;
                    var repeatDuration = duration / hasRepeats.SpanCount();
                    var skip           = 1;

                    // Currently an issue where an odd number of repeats (span count) will skip
                    // the final minion if repeats are too short. Not sure what to do here since
                    // it doesn't make rhythmic sense to add an extra hit object.
                    // Examples:
                    //   *-*-*-*-* becomes *---*---* (good)
                    //   *-*-*-*   becomes *---*-- (looks bad) instead of *---*-* (rhythmically worse)
                    while (repeatDuration < repeat_cutoff)
                    {
                        repeatDuration *= 2;
                        skip           *= 2;
                    }

                    var otherLane     = sheetLane.Opposite();
                    var repeatCurrent = original.StartTime;
                    var index         = -1;

                    foreach (var nodeSample in hasRepeats.NodeSamples)
                    {
                        index++;

                        if (index % skip != 0)
                        {
                            continue;
                        }

                        yield return(new Minion
                        {
                            Lane = otherLane,
                            Samples = nodeSample,
                            StartTime = repeatCurrent
                        });

                        repeatCurrent += repeatDuration;
                    }
                }

                break;
            }
        }
Example #20
0
        //automatically returns the correct type
        public static HitObject FromString(string s)
        {
            string[]      split = s.Split(',');
            HitObjectType t     = (HitObjectType)int.Parse(split[3], Constants.NumberFormat);

            HitObject h = null;

            switch (t & (HitObjectType)0b1000_1011)
            {
            case HitObjectType.Normal:
                h = new HitObjectCircle();
                if (split.Length > 5)
                {
                    (h as HitObjectCircle).SoundSampleData = split[5];
                }
                break;

            case HitObjectType.Slider:
                h = new HitObjectSlider();
                (h as HitObjectSlider).ParseSliderSegments(split[5]);
                (h as HitObjectSlider).RepeatCount = int.Parse(split[6], Constants.NumberFormat);
                if (split.Length > 7)
                {
                    (h as HitObjectSlider).Length = double.Parse(split[7], Constants.NumberFormat);
                }
                //if (split.Length > 8)
                //    (h as HitObjectSlider).HitSoundData = split[8];
                //if (split.Length > 9)
                //    (h as HitObjectSlider).SoundSampleData = split[9];
                //if (split.Length > 10)
                //    (h as HitObjectSlider).MoreSoundSampleData = split[10];
                break;

            case HitObjectType.Spinner:
                h = new HitObjectSpinner();
                (h as HitObjectSpinner).EndTime = int.Parse(split[5]);
                if (split.Length > 6)
                {
                    (h as HitObjectSpinner).SoundSampleData = split[6];
                }
                break;

            case HitObjectType.Hold:
                throw new NotImplementedException("Hold notes are not yet parsed.");

            default:
                throw new ArgumentOutOfRangeException(nameof(t), "Bad hitobject type");
            }

            //note: parsed as decimal but cast to int in osu!
            if (h != null)
            {
                h.X        = int.Parse(split[0], Constants.NumberFormat);
                h.Y        = int.Parse(split[1], Constants.NumberFormat);
                h.Time     = int.Parse(split[2], Constants.NumberFormat);
                h.Type     = t;
                h.HitSound = (HitSound)int.Parse(split[4]);
            }
            else
            {
                Debug.Fail("unhandled hitobject type");
            }

            return(h);
        }
Example #21
0
 public HoldCircle(Position position, int starttime, int endtime, bool isNewCombo = false,
                   HitObjectType type = HitObjectType.HoldCircle, HitObjectSoundType soundType = HitObjectSoundType.Normal)
     : base(position, starttime, isNewCombo, type | HitObjectType.HoldCircle, soundType)
 {
     EndTime = endtime;
 }
Example #22
0
        //Gets the property requested from the hitobject, specified by index
        //null is returned if the property is not found
        static public string GetProperty(string hitobject, string property)
        {
            property = property.ToUpper();

            //Divides the hitobject string into an array seperated by commas
            string[] hobject = hitobject.Split(',');

            int tag = -1;

            //TODO: Cleanup the property-selection code

            //Standard tags that all hitobjects have
            if (property == "X")
            {
                tag = 0;
            }
            else if (property == "Y")
            {
                tag = 1;
            }
            else if (property == "TIME")
            {
                tag = 2;
            }
            else if (property == "TYPE")
            {
                tag = 3;
            }
            else if (property == "HITSOUND")
            {
                tag = 4;
            }

            else
            {
                //If it's not one of the previous tags, then the location of the tag depends on the hitobject type
                //Be careful, GetHitObjectType calls this method, so make sure to avoid infinite recursion
                HitObjectType objecttype = GetHitObjectType(hitobject);

                if (objecttype == HitObjectType.Circle)
                {
                    if (property == "ADDITION")
                    {
                        tag = 5;
                    }
                }
                else if (objecttype == HitObjectType.Slider)
                {
                    //Special case: Slidertype contains info about the slidertype and its control points
                    //so I have separated it into two tags
                    //Ex. B|380:120|332:96|332:96|304:124

                    //The slidertype tag is the first char in the entire tag
                    if (property == "SLIDERTYPE")
                    {
                        return(hobject[5][0].ToString());
                    }
                    //Custom tag: represents the control points within a slider
                    //is everything after the slidertype char
                    else if (property == "CONTROLPOINTS")
                    {
                        return(hobject[5].Substring(2));
                    }

                    else if (property == "REPEAT")
                    {
                        tag = 6;
                    }
                    else if (property == "PIXELLENGTH")
                    {
                        tag = 7;
                    }
                    else if (property == "EDGEHITSOUND")
                    {
                        tag = 8;
                    }
                    else if (property == "EDGEADDITION")
                    {
                        tag = 9;
                    }
                    else if (property == "ADDITION")
                    {
                        tag = 10;
                    }
                }
                else if (objecttype == HitObjectType.Spinner)
                {
                    if (property == "ENDTIME")
                    {
                        tag = 5;
                    }
                    else if (property == "ADDITION")
                    {
                        tag = 6;
                    }
                }
            }

            //Protects against accessing a tag that's out of bounds
            //Not an exception since this method returns null if the tag wasn't found
            if (tag == -1 || tag >= hobject.Length)
            {
                return(null);
            }

            return(hobject[tag]);
        }
Example #23
0
 public static bool IsType(this HitObjectType Type, HitObjectType type)
 {
     return((Type & type) > 0);
 }
Example #24
0
        private bool typeForObject(HitObject hitObject, out HitObjectType hitObjectType, out LanedHitLane lane, out MinionSize minionSize)
        {
            const float vertical_left     = 170f;
            const float vertical_right    = 340f;
            const float horizontal_top    = 160f;
            const float horizontal_middle = 192f;
            const float horizontal_bottom = 224f;

            bool hasClap() => hitObject.Samples.Any(s => s.Name == HitSampleInfo.HIT_CLAP);
            bool hasFinish() => hitObject.Samples.Any(s => s.Name == HitSampleInfo.HIT_FINISH);
            bool hasWhistle() => hitObject.Samples.Any(s => s.Name == HitSampleInfo.HIT_WHISTLE);

            hitObjectType = HitObjectType.Minion;
            lane          = LanedHitLane.Air;
            minionSize    = MinionSize.Small;

            // this should never happen, honestly
            if (!(hitObject is IHasPosition position))
            {
                return(false);
            }

            if (hitObject is IHasDuration && !(hitObject is IHasDistance))
            {
                hitObjectType = HitObjectType.MiniBoss;
                return(true);
            }

            if (position.X < vertical_left)
            {
                if (position.Y >= horizontal_top && position.Y < horizontal_bottom)
                {
                    hitObjectType = hitObject is IHasDuration ? HitObjectType.DualStarSheet : HitObjectType.DualHit;
                    return(true);
                }

                lane = position.Y < horizontal_top ? LanedHitLane.Air : LanedHitLane.Ground;

                if (hitObject is IHasDuration)
                {
                    hitObjectType = HitObjectType.StarSheet;
                }
                else
                {
                    hitObjectType = HitObjectType.Minion;

                    if (hasWhistle())
                    {
                        minionSize = MinionSize.Medium;
                    }
                    else if (hasClap())
                    {
                        minionSize = MinionSize.Large;
                    }
                }

                return(true);
            }

            lane = position.Y < horizontal_middle ? LanedHitLane.Air : LanedHitLane.Ground;

            if (position.X >= vertical_right)
            {
                hitObjectType = HitObjectType.Hammer;
                return(true);
            }

            hitObjectType = hasFinish() ? HitObjectType.Heart : HitObjectType.Sawblade;

            return(true);
        }
Example #25
0
        public void CreateRandomBeatmap(AudioAnalyzer analyzer)
        {
            if (!File.Exists(this.filePath))
            {
                Console.WriteLine("Error: File not found.(" + this.filePath + ")");
                return;
            }

            if (beatmapOccupied)
            {
                Console.WriteLine("Error: Beatmap already occupied with HitObjects, Clear all objects before continuing");
                return;
            }

            Console.WriteLine("Generating Random Beatmap. Appending to file..." + this.filePath);

            using (var osuFile = new StreamWriter(this.filePath, true))
            {
                int numCircles = 0;

                // Basic Beatmap Creation
                var prevPoint = PlayField.GetRandomPointInside();
                currentTimingPoint = (timingPoints.Count > 0) ? timingPoints[0] : null;
                float timestamp = (float)offset;

                // for (float timestamp = (float)offset; timestamp < songLength; timestamp += mpb)
                while (timestamp < songLength)
                {
                    Vector2 pos      = Vector2.Zero;
                    float   x        = RandomHelper.Range(Beatmap.PlayField.Left, Beatmap.PlayField.Right + 1);
                    float   y        = RandomHelper.Range(Beatmap.PlayField.Top, Beatmap.PlayField.Bottom + 1);
                    bool    newCombo = false;

                    if (currentTimingPoint != null)
                    {
                        currentTimingPoint = TimingPoint.UpdateCurrentTimingPoint((int)timestamp, timingPoints, currentTimingPoint);
                    }

                    //Gets a point on a circle whose center lies at the previous point.
                    do
                    {
                        float radius = RandomHelper.Range(30f, maxNoteDistance);                        //<---- This could be a function of bpm, i.e. time-distance relation between beats

                        pos = prevPoint + RandomHelper.OnCircle(prevPoint, radius);
                    } while (!PlayField.Contains(pos));


                    ////EXAMPLE USE CASE
                    double threshold = Double.Parse("-10");
                    var    peakData  = analyzer.CreatePeakDataAt((int)timestamp, 10000);
                    Console.WriteLine(peakData.ToString());
                    if (peakData.value < threshold)
                    {
                        //Continue without adding a beat here if no sound was detected.
                        timestamp += AddTime(NoteDuration.Half);
                        continue;
                    }


                    ////END EXAMPLE
                    // Determine if new Combo is needed
                    if (currentComboLength > comboChangeFlag)
                    {
                        newCombo           = true;
                        currentComboLength = currentComboLength % comboChangeFlag;
                    }

                    if (currentBeat % beatsPerMeasure == 0)
                    {
                        // Generate a random slider.
                        var    sliderType     = EnumHelper.GetRandom <SliderCurveType>();                 //sliderTypes[rnd.Next(0, 3)];
                        float  sliderTimespan = (RandomHelper.NextFloat < 0.5f) ? difficulty.sliderTimestamp1 : difficulty.sliderTimestamp2;
                        string sliderData     = GetSliderData(pos, (int)timestamp, HitObjectType.Slider,
                                                              HitObjectSoundType.None, sliderType, 1, sliderVelocity * currentTimingPoint.SliderVelocityMultiplier, RandomHelper.Range(minSliderCurves, maxSliderCurves + 1), sliderTimespan);

                        osuFile.WriteLine(sliderData);

                        numCircles++;

                        timestamp          += AddTime(sliderTimespan * 2);
                        currentBeat        += sliderTimespan * 2;
                        currentComboLength += sliderTimespan * 2;
                    }
                    else
                    {
                        HitObjectType hitType = (newCombo) ? HitObjectType.NormalNewCombo : HitObjectType.Normal;

                        // Test patterns!
                        if (RandomHelper.NextFloat < 0.12)
                        {
                            Triple triple = new Triple(PlayField.Center, (int)timestamp, HitObjectSoundType.None, prevPoint, mpb, difficulty);
                            osuFile.WriteLine(triple.SerializeForOsu());

                            currentComboLength += triple.totalLength;
                            timestamp          += AddTime(triple.totalLength);
                            currentBeat        += triple.totalLength;

                            prevPoint = PlayField.Center;
                        }

                        else
                        {
                            string circleData = GetHitCircleData(new Vector2(x, y), (int)timestamp, hitType,
                                                                 HitObjectSoundType.None, prevPoint);

                            osuFile.WriteLine(circleData);

                            numCircles++;

                            currentComboLength += difficulty.baseCircleTimestamp;
                            timestamp          += AddTime(difficulty.baseCircleTimestamp);
                            currentBeat        += difficulty.baseCircleTimestamp;

                            prevPoint = new Vector2(x, y);
                        }
                    }
                }

                Console.WriteLine("Number of circles " + numCircles);
            }
        }
Example #26
0
 public static bool IsType(this HitObjectType Type, HitObjectType type)
 {
     return (Type & type) > 0;
 }
Example #27
0
        public Parser(Beatmap bm, StreamReader reader = null)
        {
            if (reader == null)
            {
                Console.WriteLine(bm.Title);

                List <HitObject> _hitObjects = bm.HitObjects;

                for (int i = 0; i < bm.ObjectsCount; i++)
                {
                    bm.HitObjects[i].offset = (int)(bm.HitObjects[i].offset / speedMtpr);
                }

                bm.CS *= CSMtpr;
                bm.AR *= statMtpr;
                bm.OD *= statMtpr;
                bm.HP *= statMtpr;

                bm.CS = Math.Min(10, bm.CS);
                bm.AR = Math.Min(10, bm.AR);
                bm.OD = Math.Min(10, bm.OD);
                bm.HP = Math.Min(10, bm.HP);

                return;
            }

            string line, section = null;

            while ((line = reader.ReadLine()?.Trim()) != null)
            {
                if (line.StartsWith("[") && line.Contains("]"))
                {
                    section = line.Substring(1, line.Length - 2);
                    continue;
                }

                if (line.Length <= 0)
                {
                    continue;
                }

                switch (section)
                {
                case "Metadata":
                    String key   = line.Split(':')[0];
                    String value = line.Split(':')[1];
                    switch (key)
                    {
                    case "Title":
                        bm.Title = value;
                        break;

                    case "TitleUnicode":
                        bm.TitleUnicode = value;
                        break;

                    case "Artist":
                        bm.Artist = value;
                        break;

                    case "ArtistUnicode":
                        bm.ArtistUnicode = value;
                        break;

                    case "Version":
                        bm.Version = value;
                        break;

                    case "Creator":
                        bm.Creator = value;
                        break;
                    }
                    break;

                case "General":
                    String key_gen   = line.Split(':')[0];
                    String value_gen = line.Split(new string[] { ": " }, StringSplitOptions.None)[1];
                    switch (key_gen)
                    {
                    case "AudioFilename":
                        bm.AudioFileName = value_gen;
                        break;

                    case "AudioLeadIn":
                        bm.AudioLeadIn = value_gen;
                        break;

                    case "PreviewTime":
                        bm.PreviewTime = value_gen;
                        break;

                    case "Countdown":
                        bm.Countdown = value_gen;
                        break;

                    case "SampleSet":
                        bm.SampleSet = value_gen;
                        break;

                    case "StackLeniency":
                        bm.StackLeniency = value_gen;
                        break;

                    case "Mode":
                        bm.Mode = value_gen;
                        break;

                    case "LetterboxInBreaks":
                        bm.LetterboxInBreaks = value_gen;
                        break;

                    case "WidescreenStoryboard":
                        bm.WidescreenStoryboard = value_gen;
                        break;
                    }
                    break;

                case "Editor":
                    bm.isEditorExist = true;
                    String key_edit   = line.Split(':')[0];
                    String value_edit = line.Split(new string[] { ": " }, StringSplitOptions.None)[1];
                    switch (key_edit)
                    {
                    case "Bookmarks":
                        int count = value_edit.Split(',').Length;
                        for (int i = 0; i < count; i++)
                        {
                            bm.Bookmarks.Add(int.Parse(value_edit.Split(',')[i]));
                        }
                        break;

                    case "DistanceSpacing":
                        bm.DistanceSpacing = value_edit;
                        break;

                    case "BeatDivisor":
                        bm.BeatDivisor = value_edit;
                        break;

                    case "GridSize":
                        bm.GridSize = value_edit;
                        break;

                    case "TimelineZoom":
                        bm.TimelineZoom = value_edit;
                        break;
                    }
                    break;

                case "Difficulty":
                    String key_diff = line.Split(':')[0];
                    float  val_diff = float.Parse(line.Split(':')[1]);
                    switch (key_diff)
                    {
                    case "CircleSize":
                        bm.CS = val_diff;
                        break;

                    case "OverallDifficulty":
                        bm.OD = val_diff;
                        break;

                    case "ApproachRate":
                        isARExists = true;
                        bm.AR      = val_diff;
                        break;

                    case "HPDrainRate":
                        bm.HP = val_diff;
                        break;

                    case "SliderMultiplier":
                        bm.SV = val_diff;
                        break;

                    case "SliderTickRate":
                        bm.ST = val_diff;
                        break;
                    }
                    break;

                case "Events":
                    if (line.Contains(".png") || line.Contains(".jpg"))
                    {
                        if (isBGfound)
                        {
                            continue;
                        }
                        isBGfound    = true;
                        bm.Events_bg = line;
                        break;
                    }
                    if (line.StartsWith("2,"))
                    {
                        int[] breaks = new int[2];
                        breaks[0] = int.Parse(line.Split(',')[1]);
                        breaks[1] = int.Parse(line.Split(',')[2]);

                        bm.Events_break.Add(breaks);
                    }
                    break;

                case "TimingPoints":
                    double[] tp = new double[line.Split(',').Length];
                    for (int i = 0; i < line.Split(',').Length; i++)
                    {
                        tp[i] = double.Parse(line.Split(',')[i]);
                        if (i == 2)
                        {
                            tp[i] = double.Parse(line.Split(',')[i]) / speedMtpr;
                        }
                    }

                    bm.TimingPoints.Add(tp);
                    break;

                case "HitObjects":
                    if (bm.ObjectsCount == 0)
                    {
                        firstnoteOffset = int.Parse(line.Split(',')[2]);
                    }
                    bm.ObjectsCount++;
                    String[]      str     = line.Split(',');
                    HitObjectType objType = (HitObjectType)int.Parse(str[3]);
                    HitObject     obj     = new HitObject(int.Parse(str[0]), int.Parse(str[1]), (int)(int.Parse(str[2]) / speedMtpr), objType, line.Split(new string[] { str[2] }, StringSplitOptions.None)[1], line);
                    bm.HitObjects.Add(obj);
                    break;
                }
            }

            lastnoteOffset = bm.HitObjects[bm.ObjectsCount - 1].offset;

            double  mainBPM = 0;
            double  prevBPM = 0;
            int     prevOffset = 0, offsetGap = 0;
            Boolean isSingleBPM = true;
            double  currBPM     = 0;
            int     currOffset  = 0;

            foreach (double[] tmp in bm.TimingPoints)
            {
                if (tmp[1] < 0)
                {
                    continue;
                }
                currBPM    = tmp[1];
                currOffset = (int)tmp[0];

                if (offsetGap < currOffset - prevOffset)
                {
                    if (offsetGap != 0)
                    {
                        isSingleBPM = false;
                    }
                    offsetGap = currOffset - prevOffset;

                    mainBPM = prevBPM;
                }
                prevOffset = currOffset;
                prevBPM    = currBPM;
            }

            if (lastnoteOffset - currOffset > offsetGap)
            {
                mainBPM = prevBPM;
            }

            if (isSingleBPM)
            {
                mainBPM = prevBPM;
            }
            bm.mainBPM = (float)Math.Round((1000d / mainBPM) * 60d);

            if (!isARExists)
            {
                bm.AR = bm.OD;
            }

            bm.CS *= CSMtpr;
            bm.AR *= statMtpr;
            bm.OD *= statMtpr;
            bm.HP *= statMtpr;

            bm.CS = Math.Min(10, bm.CS);
            bm.AR = Math.Min(10, bm.AR);
            bm.OD = Math.Min(10, bm.OD);
            bm.HP = Math.Min(10, bm.HP);

            bm.ARms = bm.AR < 5.0f ?
                      AR0Ms - ARMsStep1 * bm.AR
                    : AR5Ms - ARMsStep2 * (bm.AR - 5.0f);

            bm.ARms  = Math.Min(AR0Ms, Math.Max(AR10Ms, bm.ARms));
            bm.ARms /= speedMtpr;

            bm.AR = (float)(
                bm.ARms > AR5Ms
                ? (AR0Ms - bm.ARms) / ARMsStep1
                : 5.0 + (AR5Ms - bm.ARms) / ARMsStep2
                );

            bm.ODms  = OD0Ms - Math.Ceiling(ODMsStep * bm.OD);
            bm.ODms  = Math.Min(OD0Ms, Math.Max(OD10Ms, bm.ODms));
            bm.ODms /= speedMtpr;
            bm.OD    = (float)((OD0Ms - bm.ODms) / ODMsStep);
        }
Example #28
0
 public Circle(HitObjectType Type, Vector2 Position, double Time, Color Color) : base(Type, Position, Time, Color)
 {
 }
Example #29
0
        // Creates a random beatmap. This APPENDS to the current file.
        // TODO: Need to make sure we are not overwriting other data, and starting from the correct location.
        public void CreateRandomBeatmap()
        {
            if (!File.Exists(this.filePath))
            {
                Console.WriteLine("Error: File not found.(" + this.filePath + ")");
                return;
            }

            Console.WriteLine("Generating Random Beatmap. Appending to file..." + this.filePath);

            using (var osuFile = new StreamWriter(this.filePath, true))
            {
                int numCircles = 0;

                // Basic Beatmap Creation
                var prevPoint = Vector2.NegativeOne;

                float timestamp = (float)offset;
                // for (float timestamp = (float)offset; timestamp < songLength; timestamp += mpb)
                while (timestamp < songLength)
                {
                    float x        = RandomHelper.Range(Beatmap.PlayField.Left, Beatmap.PlayField.Right + 1);
                    float y        = RandomHelper.Range(Beatmap.PlayField.Top, Beatmap.PlayField.Bottom + 1);
                    bool  newCombo = false;

                    // Determine if new Combo is needed
                    if (currentComboLength > comboChangeFlag)
                    {
                        newCombo           = true;
                        currentComboLength = currentComboLength % comboChangeFlag;
                    }
                    Console.WriteLine("currentBeat" + currentBeat);

                    /*
                     * float getBeatType = RandomHelper.NextFloat;
                     * if (getBeatType < 0.05f)
                     * {
                     *  timestamp += AddTime(NoteDuration.Quarter);
                     *  currentBeat += NoteDuration.Quarter;
                     *  continue;
                     * }
                     */

                    if (currentBeat % beatsPerMeasure == 0)
                    {
                        // Generate a random slider. // Test Random Slider Durations
                        var           sliderType = EnumHelper.GetRandom <SliderCurveType>();
                        HitObjectType hitType    = (newCombo) ? HitObjectType.SliderNewCombo : HitObjectType.Slider;

                        float  sliderTimespan = (RandomHelper.NextFloat < 0.5f) ? difficulty.sliderTimestamp1 : difficulty.sliderTimestamp2;
                        string sliderData     = GetSliderData(new Vector2(x, y), (int)timestamp, hitType,
                                                              HitObjectSoundType.None, sliderType, 1, sliderVelocity, RandomHelper.Range(minSliderCurves, maxSliderCurves + 1), sliderTimespan);

                        osuFile.WriteLine(sliderData);

                        numCircles++;

                        timestamp          += AddTime(sliderTimespan * 2);
                        currentBeat        += sliderTimespan * 2;
                        currentComboLength += sliderTimespan * 2;
                    }
                    else
                    {
                        HitObjectType hitType = (newCombo) ? HitObjectType.NormalNewCombo : HitObjectType.Normal;

                        // Test patterns!
                        if (RandomHelper.NextFloat < 0.12)
                        {
                            Triple triple = new Triple(PlayField.Center, (int)timestamp, HitObjectSoundType.None, prevPoint, mpb, difficulty);
                            osuFile.WriteLine(triple.SerializeForOsu());

                            currentComboLength += triple.totalLength;
                            timestamp          += AddTime(triple.totalLength);
                            currentBeat        += triple.totalLength;

                            prevPoint = PlayField.Center;
                        }

                        else
                        {
                            string circleData = GetHitCircleData(new Vector2(x, y), (int)timestamp, hitType,
                                                                 HitObjectSoundType.None, prevPoint);

                            osuFile.WriteLine(circleData);

                            numCircles++;

                            currentComboLength += difficulty.baseCircleTimestamp;
                            timestamp          += AddTime(difficulty.baseCircleTimestamp);
                            currentBeat        += difficulty.baseCircleTimestamp;

                            prevPoint = new Vector2(x, y);
                        }
                    }

                    // New Combo
                }

                Console.WriteLine("Number of circles " + numCircles);
            }
        }
Example #30
0
 public HitCircle(Position position, int startTime, bool isNewCombo = false, HitObjectType type = HitObjectType.HitCircle, HitObjectSoundType soundType = HitObjectSoundType.Normal)
     : base(startTime, position, isNewCombo, type | HitObjectType.HitCircle, soundType)
 {
 }
Example #31
0
 /// <summary>
 /// Constructs a new <see cref="HitObjectTypeAttribute"/> with the given unique type.
 /// </summary>
 /// <param name="type">The type to uniquely identify the annotated <see cref="IHitObject"/>-implementing class.</param>
 public HitObjectTypeAttribute(HitObjectType type)
 {
     Type = type;
 }
        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);
        }
Example #33
0
        private void Parse(string beatmapFile)
        {
            StreamReader sr = new StreamReader(beatmapFile);
            string       line, currentSection = "";

            while ((line = sr.ReadLine()) != null)
            {
                //Skip commented or blank lines
                if (line.StartsWith("//") || line.Length == 0)
                {
                    continue;
                }
                //Get section tag if line matches "[Section Name"]
                if (line.StartsWith("["))
                {
                    currentSection = line;
                    continue;
                }

                //[General], [Metadata], [Difficulty] sections
                if ((currentSection == "[General]") || (currentSection == "[Metadata]") || (currentSection == "[Difficulty]") || (currentSection == "[Editor]"))
                {
                    //Split line into values
                    string[] lineSplit = line.Split(':');
                    string   property  = lineSplit[0].TrimEnd();
                    string   value     = lineSplit[1].Trim();

                    //Assign values to fields
                    FieldInfo fi = this.GetType().GetField(property);
                    if (fi != null)
                    {
                        if (fi.FieldType == typeof(float?))
                        {
                            fi.SetValue(this, (float?)Convert.ToDouble(value));
                        }
                        if (fi.FieldType == typeof(float))
                        {
                            fi.SetValue(this, (float)Convert.ToDouble(value));
                        }
                        else if ((fi.FieldType == typeof(int?)) || (fi.FieldType == typeof(int)))
                        {
                            fi.SetValue(this, Convert.ToInt32(value));
                        }
                        else if (fi.FieldType == typeof(string))
                        {
                            fi.SetValue(this, value);
                        }
                    }
                    //[TimingPoints] section
                }
                else if (currentSection == "[TimingPoints]")
                {
                    //Split line into values
                    string[] values = line.Split(',');
                    //Create new timing point (time, time per beat, time signature, frenzy mode)
                    this.TimingPoints.Add(new TimingPoint((float)Convert.ToDouble(values[0]), (float)Convert.ToDouble(values[1]), Convert.ToInt32(values[2]), Convert.ToBoolean(Convert.ToDouble(values[7]))));
                    //[HitObjects] section
                }
                else if (currentSection == "[HitObjects]")
                {
                    //Split line into values
                    string[] values = line.Split(',');
                    //Get hit object type
                    HitObjectType type = (HitObjectType)Convert.ToInt32(values[3]);
                    //[Circle]
                    if ((type & HitObjectType.Circle) > 0)
                    {
                        //Add new circle hit object
                        HitObjects.Add(new CircleObject(Convert.ToInt32(values[0]), Convert.ToInt32(values[1]), (float)Convert.ToDouble(values[2])));
                    }
                    //[Slider]
                    else if ((type & HitObjectType.Slider) > 0)
                    {
                        //Add new slider hit object
                        HitObjects.Add(new SliderObject(Convert.ToInt32(values[0]), Convert.ToInt32(values[1]), (float)Convert.ToDouble(values[2]), (float)Convert.ToDouble(Convert.ToInt32(values[7]))));
                    }
                    //[Spinner]
                    else if ((type & HitObjectType.Spinner) > 0)
                    {
                        //Add new spinner hit object
                        HitObjects.Add(new SpinnerObject(Convert.ToInt32(values[0]), Convert.ToInt32(values[1]), (float)Convert.ToDouble(values[2]), (float)Convert.ToDouble(values[5])));
                    }
                }
            }
        }
        /// <summary>
        /// Updates the visible (combined) score and triggers any replay alterations required.
        /// </summary>
        /// <param name="trigger">The player that triggered this update.</param>
        private void UpdateVisibleScore(ScoreboardEntryExtended trigger)
        {
            int count300   = combinedScore.Count300;
            int count100   = combinedScore.Count100;
            int count50    = combinedScore.Count50;
            int countMiss  = combinedScore.CountMiss;
            int totalScore = combinedScore.TotalScore;

            combinedScore.HpGraph = Player.currentScore.HpGraph;

            combinedScore.Reset();

            foreach (int i in usedPlayerSlots)
            {
                Score thisScore = player.ScoreEntries[i].Score;

                if (thisScore == null)
                {
                    continue;
                }

                combinedScore.TotalScore += thisScore.TotalScore;

                combinedScore.Count50   += thisScore.Count50;
                combinedScore.Count100  += thisScore.Count100;
                combinedScore.Count300  += thisScore.Count300;
                combinedScore.CountMiss += thisScore.CountMiss;
                combinedScore.CountGeki += thisScore.CountGeki;
                combinedScore.CountKatu += thisScore.CountKatu;

                combinedScore.CurrentHp = Math.Max(combinedScore.CurrentHp, thisScore.CurrentHp);
                combinedScore.MaxCombo  = Math.Max(combinedScore.MaxCombo, thisScore.MaxCombo);
            }

            if (trigger != player.scoreEntry)
            {
                HitObjectType type = (HitObjectType)trigger.Frame.tagByte;

                if (type.IsType(HitObjectType.Normal)) //HitCircle
                {
                    //Wasn't a result of the active player.
                    if (combinedScore.Count50 > count50)
                    {
                        AlterReplay(IncreaseScoreType.Hit50);
                    }
                    else if (combinedScore.Count100 > count100)
                    {
                        AlterReplay(IncreaseScoreType.Hit100);
                    }
                    else if (combinedScore.CountMiss > countMiss)
                    {
                        AlterReplay(IncreaseScoreType.Miss);
                    }
                }
                else if (type.IsType(HitObjectType.Slider))
                {
                    if (combinedScore.Count50 > count50)
                    {
                        AlterReplaySlider(IncreaseScoreType.Hit50);
                    }
                    else if (combinedScore.Count100 > count100)
                    {
                        AlterReplaySlider(IncreaseScoreType.Hit100);
                    }
                    else if (combinedScore.Count300 > count300)
                    {
                        AlterReplaySlider(IncreaseScoreType.Hit300);
                    }
                    else if (combinedScore.CountMiss > countMiss)
                    {
                        AlterReplaySlider(IncreaseScoreType.Miss);
                    }
                }
            }

            player.Ruleset.ScoreDisplay.Update(combinedScore.TotalScore);
        }