Skip to content

Commit

Permalink
Merge pull request #125 from OliBomby/dev
Browse files Browse the repository at this point in the history
Dev update 1.7.1.0
  • Loading branch information
OliBomby authored Oct 13, 2020
2 parents 050f112 + 874a92f commit 888a2ad
Show file tree
Hide file tree
Showing 66 changed files with 2,191 additions and 770 deletions.
118 changes: 97 additions & 21 deletions Mapping Tools/Classes/BeatmapHelper/Beatmap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Text.RegularExpressions;
using Mapping_Tools.Classes.BeatmapHelper.Events;
using Mapping_Tools.Classes.MathUtil;
using Mapping_Tools.Classes.SystemTools;

namespace Mapping_Tools.Classes.BeatmapHelper {

Expand Down Expand Up @@ -158,6 +159,46 @@ public class Beatmap : ITextFile {
/// </summary>
public bool SaveWithFloatPrecision { get; set; }

/// <summary>
/// Initializes a new Beatmap.
/// </summary>
public Beatmap() {
Initialize();
}

/// <summary>
/// Initializes a beatmap with the provided hit objects and timing points.
/// </summary>
/// <param name="hitObjects"></param>
/// <param name="timingPoints"></param>
/// <param name="firstUnInheritedTimingPoint"></param>
/// <param name="globalSv"></param>
/// <param name="gameMode"></param>
public Beatmap(List<HitObject> hitObjects, List<TimingPoint> timingPoints,
TimingPoint firstUnInheritedTimingPoint = null, double globalSv = 1.4, GameMode gameMode = GameMode.Standard) {
Initialize();

// Set the hit objects
HitObjects = hitObjects;

// Set the timing stuff
BeatmapTiming.SetTimingPoints(timingPoints);
BeatmapTiming.SliderMultiplier = globalSv;

if (!BeatmapTiming.Contains(firstUnInheritedTimingPoint)) {
BeatmapTiming.Add(firstUnInheritedTimingPoint);
}

// Set the global SV here too because thats absolutely necessary
Difficulty["SliderMultiplier"] = new TValue(globalSv.ToInvariant());
General["Mode"] = new TValue(((int) gameMode).ToInvariant());

SortHitObjects();
CalculateSliderEndTimes();
GiveObjectsGreenlines();
CalculateHitObjectComboStuff();
}

/// <summary>
/// Initializes the Beatmap file format.
/// </summary>
Expand All @@ -166,11 +207,64 @@ public Beatmap(List<string> lines) {
SetLines(lines);
}

private void Initialize() {
General = new Dictionary<string, TValue>();
Editor = new Dictionary<string, TValue>();
Metadata = new Dictionary<string, TValue>();
Difficulty = new Dictionary<string, TValue>();
ComboColours = new List<ComboColour>();
SpecialColours = new Dictionary<string, ComboColour>();
BackgroundAndVideoEvents = new List<Event>();
BreakPeriods = new List<Break>();
StoryboardLayerBackground = new List<Event>();
StoryboardLayerPass = new List<Event>();
StoryboardLayerFail = new List<Event>();
StoryboardLayerForeground = new List<Event>();
StoryboardLayerOverlay = new List<Event>();
StoryboardSoundSamples = new List<StoryboardSoundSample>();
HitObjects = new List<HitObject>();
BeatmapTiming = new Timing(1.4);

FillBasicMetadata();
}

public void FillBasicMetadata() {
General["AudioFilename"] = new TValue(string.Empty);
General["AudioLeadIn"] = new TValue("0");
General["PreviewTime"] = new TValue("-1");
General["Countdown"] = new TValue("0");
General["SampleSet"] = new TValue("Soft");
General["StackLeniency"] = new TValue("0.2");
General["Mode"] = new TValue("0");
General["LetterboxInBreaks"] = new TValue("0");
General["WidescreenStoryboard"] = new TValue("0");

Metadata["Title"] = new TValue(string.Empty);
Metadata["TitleUnicode"] = new TValue(string.Empty);
Metadata["Artist"] = new TValue(string.Empty);
Metadata["ArtistUnicode"] = new TValue(string.Empty);
Metadata["Creator"] = new TValue(string.Empty);
Metadata["Version"] = new TValue(string.Empty);
Metadata["Source"] = new TValue(string.Empty);
Metadata["Tags"] = new TValue(string.Empty);
Metadata["BeatmapID"] = new TValue("0");
Metadata["BeatmapSetID"] = new TValue("-1");

Difficulty["HPDrainRate"] = new TValue("5");
Difficulty["CircleSize"] = new TValue("5");
Difficulty["OverallDifficulty"] = new TValue("5");
Difficulty["ApproachRate"] = new TValue("5");
Difficulty["SliderMultiplier"] = new TValue("1.4");
Difficulty["SliderTickRate"] = new TValue("1");
}

/// <summary>
/// Deserializes an entire .osu file and stores the data to this object.
/// </summary>
/// <param name="lines">List of strings where each string is another line in the .osu file.</param>
public void SetLines(List<string> lines) {
Initialize();

// Load up all the shit
List<string> generalLines = GetCategoryLines(lines, "[General]");
List<string> editorLines = GetCategoryLines(lines, "[Editor]");
Expand All @@ -188,22 +282,6 @@ public void SetLines(List<string> lines) {
List<string> colourLines = GetCategoryLines(lines, "[Colours]");
List<string> hitobjectLines = GetCategoryLines(lines, "[HitObjects]");

General = new Dictionary<string, TValue>();
Editor = new Dictionary<string, TValue>();
Metadata = new Dictionary<string, TValue>();
Difficulty = new Dictionary<string, TValue>();
ComboColours = new List<ComboColour>();
SpecialColours = new Dictionary<string, ComboColour>();
BackgroundAndVideoEvents = new List<Event>();
BreakPeriods = new List<Break>();
StoryboardLayerBackground = new List<Event>();
StoryboardLayerPass = new List<Event>();
StoryboardLayerFail = new List<Event>();
StoryboardLayerForeground = new List<Event>();
StoryboardLayerOverlay = new List<Event>();
StoryboardSoundSamples = new List<StoryboardSoundSample>();
HitObjects = new List<HitObject>();

FillDictionary(General, generalLines);
FillDictionary(Editor, editorLines);
FillDictionary(Metadata, metadataLines);
Expand Down Expand Up @@ -317,7 +395,7 @@ public void GiveObjectsGreenlines() {
ho.TimingPoint = BeatmapTiming.GetTimingPointAtTime(ho.Time);
ho.HitsoundTimingPoint = BeatmapTiming.GetTimingPointAtTime(ho.Time + 5);
ho.UnInheritedTimingPoint = BeatmapTiming.GetRedlineAtTime(ho.Time);
ho.BodyHitsounds = BeatmapTiming.GetTimingPointsInTimeRange(ho.Time, ho.EndTime);
ho.BodyHitsounds = BeatmapTiming.GetTimingPointsInRange(ho.Time, ho.EndTime, false);
foreach (var time in ho.GetAllTloTimes(BeatmapTiming)) {
ho.BodyHitsounds.RemoveAll(o => Math.Abs(time - o.Offset) <= 5);
}
Expand Down Expand Up @@ -470,7 +548,7 @@ public double GetHitObjectEndTime() {
}

public void OffsetTime(double offset) {
BeatmapTiming.TimingPoints?.ForEach(tp => tp.Offset += offset);
BeatmapTiming.Offset(offset);
HitObjects?.ForEach(h => h.MoveTime(offset));
}

Expand Down Expand Up @@ -545,9 +623,7 @@ public IEnumerable<HitObject> QueryTimeCode(string code) {
}

// Parse the time span in the code
var time = TimeSpan.ParseExact(
code.Substring(0, startBracketIndex == -1 ? code.Length : startBracketIndex - 1).Trim(),
@"mm\:ss\:fff", CultureInfo.InvariantCulture, TimeSpanStyles.None).TotalMilliseconds;
var time = TypeConverters.ParseOsuTimestamp(code).TotalMilliseconds;

// Enumerate through the hit objects from the first object at the time
int objectIndex = HitObjects.FindIndex(h => h.Time >= time);
Expand Down
6 changes: 1 addition & 5 deletions Mapping Tools/Classes/BeatmapHelper/Events/Background.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,7 @@ public Vector2 GetOffset() {
}

public override string GetLine() {
// Dont write the offset if its 0,0
if (XOffset == 0 && YOffset == 0) {
return $"{EventType},{StartTime.ToInvariant()},\"{Filename}\"";
}

// Writing the offset is optional if its 0,0 but we add it anyways because that is what osu! does.
return $"{EventType},{StartTime.ToInvariant()},\"{Filename}\",{XOffset.ToInvariant()},{YOffset.ToInvariant()}";
}

Expand Down
31 changes: 11 additions & 20 deletions Mapping Tools/Classes/BeatmapHelper/HitObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -521,25 +521,25 @@ public void Move(Vector2 delta) {
for (var i = 0; i < CurvePoints.Count; i++) CurvePoints[i] = CurvePoints[i] + delta;
}

public bool ResnapSelf(Timing timing, int snap1, int snap2, bool floor = true, TimingPoint tp = null,
public bool ResnapSelf(Timing timing, IEnumerable<IBeatDivisor> beatDivisors, bool floor = true, TimingPoint tp = null,
TimingPoint firstTp = null) {
var newTime = GetResnappedTime(timing, snap1, snap2, floor, tp, firstTp);
var newTime = GetResnappedTime(timing, beatDivisors, floor, tp, firstTp);
var deltaTime = newTime - Time;
MoveTime(deltaTime);
return Math.Abs(deltaTime) > Precision.DOUBLE_EPSILON;
}

public bool ResnapEnd(Timing timing, int snap1, int snap2, bool floor = true, TimingPoint tp = null,
public bool ResnapEnd(Timing timing, IEnumerable<IBeatDivisor> beatDivisors, bool floor = true, TimingPoint tp = null,
TimingPoint firstTp = null) {
// If there is a redline in the sliderbody then the sliderend gets snapped to a tick of the latest redline
if (!IsSlider || timing.TimingPoints.Any(o => o.Uninherited && o.Offset <= EndTime + 20 && o.Offset > Time))
return ResnapEndTime(timing, snap1, snap2, floor, tp, firstTp);
return ResnapEndClassic(timing, snap1, snap2, firstTp);
return ResnapEndTime(timing, beatDivisors, floor, tp, firstTp);
return ResnapEndClassic(timing, beatDivisors, firstTp);
}

public bool ResnapEndTime(Timing timing, int snap1, int snap2, bool floor = true, TimingPoint tp = null,
public bool ResnapEndTime(Timing timing, IEnumerable<IBeatDivisor> beatDivisors, bool floor = true, TimingPoint tp = null,
TimingPoint firstTp = null) {
var newTime = timing.Resnap(EndTime, snap1, snap2, floor, tp, firstTp);
var newTime = timing.Resnap(EndTime, beatDivisors, floor, tp: tp, firstTp: firstTp);
var deltaTime = newTime - EndTime;
MoveEndTime(timing, deltaTime);

Expand All @@ -559,27 +559,18 @@ public bool ResnapPosition(GameMode mode, double circleSize) {
return Math.Abs(dX) > Precision.DOUBLE_EPSILON || Math.Abs(dY) > Precision.DOUBLE_EPSILON;
}

public bool ResnapEndClassic(Timing timing, int snap1, int snap2, TimingPoint firstTp = null) {
// Temporal length is n times a snap divisor length
var tp = timing.GetRedlineAtTime(Time, firstTp);

var newTemporalLength1 = Timing.GetNearestMultiple(TemporalLength, tp.MpB / snap1);
var snapDistance1 = Math.Abs(TemporalLength - newTemporalLength1);

var newTemporalLength2 = Timing.GetNearestMultiple(TemporalLength, tp.MpB / snap2);
var snapDistance2 = Math.Abs(TemporalLength - newTemporalLength2);

var newTemporalLength = snapDistance1 < snapDistance2 ? newTemporalLength1 : newTemporalLength2;
public bool ResnapEndClassic(Timing timing, IEnumerable<IBeatDivisor> beatDivisors, TimingPoint firstTp = null) {
var newTemporalLength = timing.ResnapDuration(Time, TemporalLength, beatDivisors, false, firstTp: firstTp);

var deltaTime = newTemporalLength - TemporalLength;
ChangeTemporalTime(timing, deltaTime);

return Math.Abs(deltaTime) > Precision.DOUBLE_EPSILON;
}

public double GetResnappedTime(Timing timing, int snap1, int snap2, bool floor = true, TimingPoint tp = null,
public double GetResnappedTime(Timing timing, IEnumerable<IBeatDivisor> beatDivisors, bool floor = true, TimingPoint tp = null,
TimingPoint firstTp = null) {
return timing.Resnap(Time, snap1, snap2, floor, tp, firstTp);
return timing.Resnap(Time, beatDivisors, floor, tp: tp, firstTp: firstTp);
}

private bool GetSliderExtras() {
Expand Down
7 changes: 7 additions & 0 deletions Mapping Tools/Classes/BeatmapHelper/IBeatDivisor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
using System;

namespace Mapping_Tools.Classes.BeatmapHelper {
public interface IBeatDivisor : IEquatable<IBeatDivisor> {
double GetValue();
}
}
38 changes: 38 additions & 0 deletions Mapping Tools/Classes/BeatmapHelper/IrrationalBeatDivisor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
namespace Mapping_Tools.Classes.BeatmapHelper {
public class IrrationalBeatDivisor : IBeatDivisor {
public readonly double Value;

public IrrationalBeatDivisor(double value) {
Value = value;
}

public static implicit operator IrrationalBeatDivisor(double value) {
return new IrrationalBeatDivisor(value);
}

public double GetValue() {
return Value;
}

protected bool Equals(IrrationalBeatDivisor other) {
return Value.Equals(other.Value);
}

public bool Equals(IBeatDivisor other) {
if (other is null) return false;
if (ReferenceEquals(this, other)) return true;
if (other is IrrationalBeatDivisor otherIrrational) return Equals(otherIrrational);
return false;
}

public override bool Equals(object obj) {
if (obj is null) return false;
if (ReferenceEquals(this, obj)) return true;
return obj.GetType() == GetType() && Equals((IrrationalBeatDivisor) obj);
}

public override int GetHashCode() {
return Value.GetHashCode();
}
}
}
62 changes: 62 additions & 0 deletions Mapping Tools/Classes/BeatmapHelper/RationalBeatDivisor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@

using Newtonsoft.Json;

namespace Mapping_Tools.Classes.BeatmapHelper {
public class RationalBeatDivisor : IBeatDivisor {
/// <summary>
/// The number above the line in a vulgar fraction showing how many of the parts indicated by the denominator are taken, for example, 2 in 2/3.
/// </summary>
public readonly int Numerator;

/// <summary>
/// The number below the line in a vulgar fraction; a divisor.
/// </summary>
public readonly int Denominator;

public RationalBeatDivisor(int denominator) {
Numerator = 1;
Denominator = denominator;
}

[JsonConstructor]
public RationalBeatDivisor(int numerator, int denominator) {
Numerator = numerator;
Denominator = denominator;
}

public static implicit operator RationalBeatDivisor(int denominator) {
return new RationalBeatDivisor(denominator);
}

public double GetValue() {
return (double) Numerator / Denominator;
}

protected bool Equals(RationalBeatDivisor other) {
return Numerator == other.Numerator && Denominator == other.Denominator;
}

public bool Equals(IBeatDivisor other) {
if (other is null) return false;
if (ReferenceEquals(this, other)) return true;
if (other is RationalBeatDivisor otherRational) return Equals(otherRational);
return false;
}

public override bool Equals(object obj) {
if (obj is null) return false;
if (ReferenceEquals(this, obj)) return true;
return obj.GetType() == GetType() && Equals((RationalBeatDivisor) obj);
}

public override int GetHashCode() {
unchecked {
return (Numerator * 397) ^ Denominator;
}
}

public static IBeatDivisor[] GetDefaultBeatDivisors() {
return new IBeatDivisor[] {new RationalBeatDivisor(16), new RationalBeatDivisor(12)};
}
}
}
Loading

0 comments on commit 888a2ad

Please sign in to comment.