//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // * New Method: Discover Coloured Areas //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ private void DiscoverColouredAreas(string a_sText) { const int BEGIN_COLOUR_TAG_LENGTH = 15; // => "<color=#FFFFFF>".Length; const int COLOUR_DECLARATION_LENGTH = 8; // => "<color=#".Length const int END_COLOUR_TAG_LENGTH = 8; // => "</color>".Length; m_lColouredAreas.Clear(); int iFinalTextIndexOffset = 0; for (int i = 0; i < a_sText.Length; ++i) { if (a_sText[i] == '<') { int iRemainingLength = (a_sText.Length - i); if (iRemainingLength >= BEGIN_COLOUR_TAG_LENGTH && a_sText.Substring(i, COLOUR_DECLARATION_LENGTH) == "<color=#") { Match match = Regex.Match(a_sText.Substring(i, iRemainingLength), @"<color=#([0-9a-zA-Z]{6})[0-9a-zA-Z]?[0-9a-zA-Z]?>", RegexOptions.IgnoreCase); if (match.Success) { string sColourCode = match.Groups[1].Value; int iColourTagLength = match.Groups[0].Value.Length; for (int j = (i + iColourTagLength); j < a_sText.Length; ++j) { if (a_sText[j] == '<') { iRemainingLength = (a_sText.Length - j); if (iRemainingLength >= END_COLOUR_TAG_LENGTH) { match = Regex.Match(a_sText.Substring(j, iRemainingLength), @"</color>", RegexOptions.IgnoreCase); if (match.Success) { ColourPoints newColourPoint = new ColourPoints(); newColourPoint.from = (i - iFinalTextIndexOffset); iFinalTextIndexOffset += iColourTagLength; newColourPoint.to = (j - iFinalTextIndexOffset); newColourPoint.colourCode = sColourCode; m_lColouredAreas.AddLast(newColourPoint); iFinalTextIndexOffset += END_COLOUR_TAG_LENGTH; break; } } } } // 'for' loop } } } } }
public void ImportColourHaxFromBeatmap(string importPath) { try { var editor = new BeatmapEditor(importPath); var beatmap = editor.Beatmap; // Add default colours if there are no colours if (beatmap.ComboColours.Count == 0) { beatmap.ComboColours.AddRange(ComboColour.GetDefaultComboColours()); } ComboColours.Clear(); for (int i = 0; i < beatmap.ComboColours.Count; i++) { ComboColours.Add(new SpecialColour(beatmap.ComboColours[i].Color, $"Combo{i + 1}")); } // Remove all colour points since those are getting replaced ColourPoints.Clear(); // Get all the hit objects which can colorhax. AKA new combos and not spinners var colorHaxObjects = beatmap.HitObjects.Where(o => o.ActualNewCombo && !o.IsSpinner).ToArray(); // Get the array with all the lengths of sequences that are going to be checked var sequenceLengthChecks = Enumerable.Range(1, ComboColours.Count * 2 + 2).ToArray(); int sequenceStartIndex = 0; int[] lastNormalSequence = null; bool lastBurst = false; while (sequenceStartIndex < colorHaxObjects.Length) { var firstComboHitObject = colorHaxObjects[sequenceStartIndex]; var bestSequence = GetBestSequenceAtIndex( sequenceStartIndex, 3, colorHaxObjects, beatmap, sequenceLengthChecks, lastBurst, lastNormalSequence )?.Item1; if (bestSequence == null) { lastBurst = false; sequenceStartIndex += 1; continue; } var bestContribution = GetSequenceContribution(colorHaxObjects, sequenceStartIndex, bestSequence); // Get the colours for every colour index. Using modulo to make sure the index is always in range. var colourSequence = bestSequence.Select(o => ComboColours[MathHelper.Mod(o, ComboColours.Count)]); // Add a new colour point var mode = bestContribution == 1 && GetComboLength(beatmap.HitObjects, firstComboHitObject) <= MaxBurstLength ? ColourPointMode.Burst : ColourPointMode.Normal; // To optimize on colour points, we dont add a new colour point if the previous point was a burst and // the sequence before the burst is equivalent to this sequence if (!(lastBurst && lastNormalSequence != null && IsSubSequence(bestSequence, lastNormalSequence) && (bestSequence.Length == lastNormalSequence.Length || bestContribution <= bestSequence.Length))) { ColourPoints.Add(GenerateNewColourPoint(firstComboHitObject.Time, colourSequence, mode)); } lastBurst = mode == ColourPointMode.Burst; sequenceStartIndex += bestContribution; lastNormalSequence = mode == ColourPointMode.Burst ? lastNormalSequence : bestSequence; } } catch (Exception ex) { MessageBox.Show($"{ex.Message}{Environment.NewLine}{ex.StackTrace}", "Error"); } }