1
0
mirror of https://github.com/ppy/osu.git synced 2025-02-28 20:53:18 +08:00

Initial support code for beatmap loading

This commit is contained in:
Drew DeVault 2016-10-04 16:29:08 -04:00
parent 416ca3c71b
commit 5dd57e4be2
11 changed files with 274 additions and 6 deletions

View File

@ -0,0 +1,51 @@
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using osu.Game.Beatmaps.Formats;
using osu.Game.Beatmaps.IO;
using osu.Game.Beatmaps;
namespace osu.Desktop.Beatmaps.IO
{
/// <summary>
/// Reads an extracted legacy beatmap from disk.
/// </summary>
public class LegacyFilesystemReader : ArchiveReader
{
static LegacyFilesystemReader()
{
AddReader<LegacyFilesystemReader>((storage, path) => Directory.Exists(path));
}
private string BasePath { get; set; }
private Beatmap FirstMap { get; set; }
public LegacyFilesystemReader(string path)
{
BasePath = path;
var maps = ReadBeatmaps();
if (maps.Length == 0)
throw new FileNotFoundException("This directory contains no beatmaps");
using (var stream = new StreamReader(ReadFile(maps[0])))
{
var decoder = BeatmapDecoder.GetDecoder(stream);
FirstMap = decoder.Decode(stream);
}
}
public override string[] ReadBeatmaps()
{
return Directory.GetFiles(BasePath, "*.osu").Select(f => Path.GetFileName(f)).ToArray();
}
public override Stream ReadFile(string name)
{
return File.OpenRead(Path.Combine(BasePath, name));
}
public override Metadata ReadMetadata()
{
return FirstMap.Metadata;
} }
}

View File

@ -135,8 +135,13 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Program.cs" /> <Compile Include="Program.cs" />
<Compile Include="Beatmaps\IO\LegacyFilesystemReader.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup /> <ItemGroup />
<ItemGroup>
<Folder Include="Beatmaps\" />
<Folder Include="Beatmaps\IO\" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. Other similar extension points exist, see Microsoft.Common.targets.

View File

@ -10,11 +10,12 @@ namespace osu.Game.Beatmaps
{ {
public class Beatmap public class Beatmap
{ {
public List<HitObject> HitObjects; public int BeatmapID;
public List<HitObject> HitObjects;
public List<ControlPoint> ControlPoints; public List<ControlPoint> ControlPoints;
public string Difficulty; public string Version;
public User Creator; public Metadata Metadata;
} }
} }

View File

@ -11,6 +11,8 @@ namespace osu.Game.Beatmaps
/// </summary> /// </summary>
public class BeatmapSet public class BeatmapSet
{ {
public int BeatmapSetID;
public List<Beatmap> Beatmaps { get; protected set; } public List<Beatmap> Beatmaps { get; protected set; }
public Metadata Metadata; public Metadata Metadata;

View File

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.IO;
namespace osu.Game.Beatmaps.Formats
{
public abstract class BeatmapDecoder
{
private static Dictionary<string, Type> Decoders { get; set; } = new Dictionary<string, Type>();
public static BeatmapDecoder GetDecoder(TextReader stream)
{
var line = stream.ReadLine().Trim();
if (!Decoders.ContainsKey(line))
throw new IOException("Unknown file format");
return (BeatmapDecoder)Activator.CreateInstance(Decoders[line]);
}
protected static void AddDecoder<T>(string magic) where T : BeatmapDecoder
{
Decoders[magic] = typeof(T);
}
public abstract Beatmap Decode(TextReader stream);
}
}

View File

@ -0,0 +1,34 @@
using System;
using System.IO;
namespace osu.Game.Beatmaps.Formats
{
public class OsuLegacyDecoder : BeatmapDecoder
{
static OsuLegacyDecoder()
{
AddDecoder<OsuLegacyDecoder>("osu file format v14");
AddDecoder<OsuLegacyDecoder>("osu file format v13");
AddDecoder<OsuLegacyDecoder>("osu file format v12");
AddDecoder<OsuLegacyDecoder>("osu file format v11");
AddDecoder<OsuLegacyDecoder>("osu file format v10");
// TODO: Not sure how far back to go, or differences between versions
}
private enum Section
{
General,
Editor,
Metadata,
Difficulty,
Events,
TimingPoints,
Colours,
HitObjects,
}
public override Beatmap Decode(TextReader stream)
{
throw new NotImplementedException();
}
}
}

View File

@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using System.IO;
using osu.Framework.OS;
namespace osu.Game.Beatmaps.IO
{
public abstract class ArchiveReader
{
private class Reader
{
public Func<BasicStorage, string, bool> Test { get; set; }
public Type Type { get; set; }
}
private static List<Reader> Readers { get; set; } = new List<Reader>();
public static ArchiveReader GetReader(BasicStorage storage, string path)
{
foreach (var reader in Readers)
{
if (reader.Test(storage, path))
return (ArchiveReader)Activator.CreateInstance(reader.Type);
}
throw new IOException("Unknown file format");
}
protected static void AddReader<T>(Func<BasicStorage, string, bool> test) where T : ArchiveReader
{
Readers.Add(new Reader { Test = test, Type = typeof(T) });
}
/// <summary>
/// Reads the beatmap metadata from this archive.
/// </summary>
public abstract Metadata ReadMetadata();
/// <summary>
/// Gets a list of beatmap file names.
/// </summary>
public abstract string[] ReadBeatmaps();
/// <summary>
/// Opens a stream for reading a specific file from this archive.
/// </summary>
public abstract Stream ReadFile(string name);
}
}

View File

@ -0,0 +1,42 @@
using System;
using System.IO;
namespace osu.Game.Beatmaps.IO
{
public class OszArchiveReader : ArchiveReader
{
static OszArchiveReader()
{
AddReader<OszArchiveReader>((storage, path) =>
{
using (var stream = storage.GetStream(path))
{
// TODO: detect if osz
return false;
}
});
}
private Stream Archive { get; set; }
public OszArchiveReader(Stream archive)
{
Archive = archive;
}
public override string[] ReadBeatmaps()
{
throw new NotImplementedException();
}
public override Stream ReadFile(string name)
{
throw new NotImplementedException();
}
public override Metadata ReadMetadata()
{
throw new NotImplementedException();
}
}
}

View File

@ -1,11 +1,23 @@
//Copyright (c) 2007-2016 ppy Pty Ltd <contact@ppy.sh>. //Copyright (c) 2007-2016 ppy Pty Ltd <contact@ppy.sh>.
//Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE //Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.GameModes.Play;
namespace osu.Game.Beatmaps namespace osu.Game.Beatmaps
{ {
public class Metadata public class Metadata
{ {
public string Artist; public int BeatmapSetID { get; set; }
public string Title; public string Title { get; set; }
public string TitleUnicode { get; set; }
public string Artist { get; set; }
public string ArtistUnicode { get; set; }
public string Author { get; set; }
public string Source { get; set; }
public string Tags { get; set; }
public PlayMode Mode { get; set; }
public int PreviewTime { get; set; }
public string AudioFile { get; set; }
public string BackgroundFile { get; set; }
} }
} }

View File

@ -1,5 +1,9 @@
using System; using System;
using System.Collections.Generic;
using System.IO;
using osu.Framework.OS; using osu.Framework.OS;
using osu.Game.Beatmaps.Formats;
using osu.Game.Beatmaps.IO;
using SQLite; using SQLite;
namespace osu.Game.Database namespace osu.Game.Database
@ -18,5 +22,45 @@ namespace osu.Game.Database
Connection.CreateTable<Beatmap>(); Connection.CreateTable<Beatmap>();
} }
} }
public void AddBeatmap(ArchiveReader input)
{
var metadata = input.ReadMetadata();
if (Connection.Table<BeatmapSet>().Count(b => b.BeatmapSetID == metadata.BeatmapSetID) != 0)
return;
string[] mapNames = input.ReadBeatmaps();
var beatmapSet = new BeatmapSet { BeatmapSetID = metadata.BeatmapSetID };
var beatmapMetadata = new BeatmapMetadata
{
Title = metadata.Title,
TitleUnicode = metadata.TitleUnicode,
Artist = metadata.Artist,
ArtistUnicode = metadata.ArtistUnicode,
Author = metadata.Author,
Source = metadata.Source,
Tags = metadata.Tags,
Mode = metadata.Mode,
PreviewTime = metadata.PreviewTime,
AudioFile = metadata.AudioFile,
BackgroundFile = metadata.BackgroundFile,
};
var maps = new List<Beatmap>();
foreach (var name in mapNames)
{
using (var stream = new StreamReader(input.ReadFile(name)))
{
var decoder = BeatmapDecoder.GetDecoder(stream);
var beatmap = decoder.Decode(stream);
maps.Add(new Beatmap
{
ID = beatmap.BeatmapID,
BeatmapSetID = metadata.BeatmapSetID,
// TODO: Import more things
});
}
}
beatmapSet.BeatmapMetadataID = Connection.Insert(beatmapMetadata);
Connection.Insert(beatmapSet);
Connection.InsertAll(maps);
}
} }
} }

View File

@ -149,6 +149,10 @@
<Compile Include="Database\BeatmapSet.cs" /> <Compile Include="Database\BeatmapSet.cs" />
<Compile Include="Database\BeatmapMetadata.cs" /> <Compile Include="Database\BeatmapMetadata.cs" />
<Compile Include="Database\Beatmap.cs" /> <Compile Include="Database\Beatmap.cs" />
<Compile Include="Beatmaps\IO\ArchiveReader.cs" />
<Compile Include="Beatmaps\Formats\BeatmapDecoder.cs" />
<Compile Include="Beatmaps\Formats\OsuLegacyDecoder.cs" />
<Compile Include="Beatmaps\IO\OszArchiveReader.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\osu-framework\osu.Framework\osu.Framework.csproj"> <ProjectReference Include="..\osu-framework\osu.Framework\osu.Framework.csproj">
@ -169,6 +173,8 @@
<ItemGroup /> <ItemGroup />
<ItemGroup> <ItemGroup>
<Folder Include="Database\" /> <Folder Include="Database\" />
<Folder Include="Beatmaps\Formats\" />
<Folder Include="Beatmaps\IO\" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.