Skip to content

Commit

Permalink
Implement event parsing
Browse files Browse the repository at this point in the history
This needs more test coverage before proper release. Color is not yet implemented.
  • Loading branch information
holly-hacker committed May 19, 2021
1 parent 6562b06 commit db3f440
Show file tree
Hide file tree
Showing 10 changed files with 262 additions and 6 deletions.
18 changes: 17 additions & 1 deletion UnitTestProject/TestsText.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Reflection;
using FluentAssertions;
using osu.Shared;
using osu_database_reader.Components.Events;
using osu_database_reader.Components.HitObjects;
using osu_database_reader.TextFiles;
using Xunit;
Expand Down Expand Up @@ -56,8 +57,22 @@ public void CheckBeatmapV14()
bm.SliderMultiplier.Should().Be(1.8);
bm.SliderTickRate.Should().Be(1);

// TODO: events
// events
bm.Events.Should().HaveCount(4);

bm.Events[0].Should().BeOfType<BackgroundEvent>();
((BackgroundEvent) bm.Events[0]).Path.Should().Be("usedtobe.jpg");
bm.Events[1].Should().BeOfType<VideoEvent>();
((VideoEvent) bm.Events[1]).Path.Should().Be("Cytus II Opening - The Whole Rest.mp4");
((VideoEvent) bm.Events[1]).Offset.Should().Be(0);
bm.Events[2].Should().BeOfType<BreakEvent>();
((BreakEvent) bm.Events[2]).StartTime.Should().Be(13929);
((BreakEvent) bm.Events[2]).EndTime.Should().Be(22301);
bm.Events[3].Should().BeOfType<BreakEvent>();
((BreakEvent) bm.Events[3]).StartTime.Should().Be(47559);
((BreakEvent) bm.Events[3]).EndTime.Should().Be(52874);

// timing points
bm.TimingPoints.Should().HaveCount(7);
bm.TimingPoints[0].Time.Should().Be(1500);
bm.TimingPoints[0].Kiai.Should().BeFalse();
Expand All @@ -70,6 +85,7 @@ public void CheckBeatmapV14()

bm.TimingPoints[1].MsPerQuarter.Should().Be(-133.333333333333);

// hit objects
bm.HitObjects.Should().HaveCount(335);
bm.HitObjects.Where(x => (x.Type & HitObjectType.Normal) != 0).Should().HaveCount(252);
bm.HitObjects.Where(x => (x.Type & HitObjectType.Slider) != 0).Should().HaveCount(83);
Expand Down
18 changes: 18 additions & 0 deletions osu-database-reader/Components/Events/AnimationEvent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
namespace osu_database_reader.Components.Events
{
public class AnimationEvent : EventBase
{
internal AnimationEvent()
{
}

public string Layer { get; internal set; }
public string Origin { get; internal set; }
public string Path { get; internal set; }
public float X { get; internal set; }
public float Y { get; internal set; }
public int FrameCount { get; internal set; }
public double FrameDelay { get; internal set; }
public string LoopType { get; internal set; }
}
}
11 changes: 11 additions & 0 deletions osu-database-reader/Components/Events/BackgroundEvent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace osu_database_reader.Components.Events
{
public class BackgroundEvent : EventBase
{
internal BackgroundEvent()
{
}

public string Path { get; internal set; }
}
}
14 changes: 14 additions & 0 deletions osu-database-reader/Components/Events/BreakEvent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace osu_database_reader.Components.Events
{
public class BreakEvent : EventBase
{
internal BreakEvent()
{
}

public double StartTime { get; internal set; }
public double EndTime { get; internal set; }

public double BreakTime => EndTime - StartTime;
}
}
152 changes: 152 additions & 0 deletions osu-database-reader/Components/Events/EventBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
using System;

namespace osu_database_reader.Components.Events
{
public abstract class EventBase
{
public string Line { get; internal set; }

public static EventBase FromString(string line)
{
if (string.IsNullOrEmpty(line))
throw new ArgumentException(line);

try
{
var split = line.Split(',');

// https://github.com/ppy/osu/blob/7654df94f6f37b8382be7dfcb4f674e03bd35427/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs#L103
// https://github.com/ppy/osu/blob/7654df94f6f37b8382be7dfcb4f674e03bd35427/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs#L301
switch (split[0])
{
case "0":
case "Background":
{
// fields 1, 3 and 4 are unknown
var path = split[2].Trim('"');

return new BackgroundEvent
{
Path = path,
Line = line,
};
}
case "1":
case "Video":
{
var offset = int.Parse(split[1], Constants.NumberFormat);
var path = split[2].Trim('"');

return new VideoEvent
{
Offset = offset,
Path = path,
Line = line,
};
}
case "2":
case "Break":
{
var start = double.Parse(split[1], Constants.NumberFormat);
var end = double.Parse(split[2], Constants.NumberFormat);

return new BreakEvent
{
StartTime = start,
EndTime = end,
Line = line,
};
}
/*
case "3":
case "Colour":
{
// TODO
}
*/
case "4":
case "Sprite":
{
var layer = split[1];
var origin = split[2];
var path = split[3].Trim('"');
var x = float.Parse(split[4], Constants.NumberFormat);
var y = float.Parse(split[5], Constants.NumberFormat);

return new SpriteEvent
{
Layer = layer,
Origin = origin,
Path = path,
X = x,
Y = y,
Line = line,
};
}
case "5":
case "Sample":
{
var time = double.Parse(split[1], Constants.NumberFormat);
var layer = split[2];
var path = split[3];

var volume = split.Length > 3 ? float.Parse(split[4], Constants.NumberFormat) : (float?) null;

return new SampleEvent
{
Time = time,
Layer = layer,
Path = path,
Volume = volume,
Line = line,
};
}
case "6":
case "Animation":
{
var layer = split[1];
var origin = split[2];
var path = split[3].Trim('"');
var x = float.Parse(split[4], Constants.NumberFormat);
var y = float.Parse(split[5], Constants.NumberFormat);
var frameCount = int.Parse(split[6], Constants.NumberFormat);
var frameDelay = double.Parse(split[7], Constants.NumberFormat);

var loopType = split.Length > 8 ? split[8] : null;

return new AnimationEvent
{
Layer = layer,
Origin = origin,
Path = path,
X = x,
Y = y,
FrameCount = frameCount,
FrameDelay = frameDelay,
LoopType = loopType,
Line = line,
};
}
default:
{
return new FallbackEvent
{
Line = line,
};
}
}
}
catch
{
return new FallbackEvent
{
Line = line,
};
}
}

private class FallbackEvent : EventBase
{
}
}
}
14 changes: 14 additions & 0 deletions osu-database-reader/Components/Events/SampleEvent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace osu_database_reader.Components.Events
{
public class SampleEvent : EventBase
{
internal SampleEvent()
{
}

public double Time { get; internal set; }
public string Layer { get; internal set; }
public string Path { get; internal set; }
public float? Volume { get; internal set; }
}
}
15 changes: 15 additions & 0 deletions osu-database-reader/Components/Events/SpriteEvent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace osu_database_reader.Components.Events
{
public class SpriteEvent : EventBase
{
internal SpriteEvent()
{
}

public string Layer { get; internal set; }
public string Origin { get; internal set; }
public string Path { get; internal set; }
public float X { get; internal set; }
public float Y { get; internal set; }
}
}
12 changes: 12 additions & 0 deletions osu-database-reader/Components/Events/VideoEvent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace osu_database_reader.Components.Events
{
public class VideoEvent : EventBase
{
internal VideoEvent()
{
}

public int Offset { get; internal set; }
public string Path { get; internal set; }
}
}
9 changes: 6 additions & 3 deletions osu-database-reader/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.IO;
using System.Linq;
using osu_database_reader.Components.Beatmaps;
using osu_database_reader.Components.Events;
using osu_database_reader.Components.HitObjects;

namespace osu_database_reader
Expand Down Expand Up @@ -75,10 +76,12 @@ public static IEnumerable<TimingPoint> ReadTimingPoints(this StreamReader sr)
yield return TimingPoint.FromString(line);
}

[Obsolete("This method should never be used; all sections must be parsed.")]
public static void SkipSection(this StreamReader sr)
public static IEnumerable<EventBase> ReadEvents(this StreamReader sr)
{
while (!string.IsNullOrWhiteSpace(sr.ReadLine())) { }
string line;
while (!string.IsNullOrEmpty(line = sr.ReadLine()))
if (!line.StartsWith("//"))
yield return EventBase.FromString(line);
}
}
}
5 changes: 3 additions & 2 deletions osu-database-reader/TextFiles/BeatmapFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.IO;
using osu_database_reader.Components.Beatmaps;
using osu_database_reader.Components.Events;
using osu_database_reader.Components.HitObjects;

namespace osu_database_reader.TextFiles
Expand All @@ -16,6 +17,7 @@ public partial class BeatmapFile
public Dictionary<string, string> SectionDifficulty;
public Dictionary<string, string> SectionColours;

public readonly List<EventBase> Events = new();
public readonly List<TimingPoint> TimingPoints = new();
public readonly List<HitObject> HitObjects = new();

Expand Down Expand Up @@ -49,8 +51,7 @@ public static BeatmapFile Read(Stream stream)
file.SectionDifficulty = r.ReadBasicSection(false);
break;
case BeatmapSection.Events:
//TODO
r.SkipSection();
file.Events.AddRange(r.ReadEvents());
break;
case BeatmapSection.TimingPoints:
file.TimingPoints.AddRange(r.ReadTimingPoints());
Expand Down

0 comments on commit db3f440

Please sign in to comment.