155 lines
5.8 KiB
C#
155 lines
5.8 KiB
C#
using Cryville.Crtr.Browsing;
|
|
using Quaver.API.Maps;
|
|
using Quaver.API.Maps.Structures;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.IO;
|
|
|
|
namespace Cryville.Crtr.Extensions.Quaver {
|
|
public class QuaverChartConverter : ResourceConverter {
|
|
static readonly string[] SUPPORTED_FORMATS = { ".qua" };
|
|
const double OFFSET = 0.05;
|
|
|
|
public override string[] GetSupportedFormats() {
|
|
return SUPPORTED_FORMATS;
|
|
}
|
|
|
|
public override IEnumerable<Resource> ConvertFrom(FileInfo file) {
|
|
List<Resource> result = new List<Resource>();
|
|
var src = Qua.Parse(file.FullName);
|
|
var ruleset = "quaver!" + src.Mode.ToString().ToLower();
|
|
var meta = new ChartMeta {
|
|
name = src.DifficultyName,
|
|
author = src.Creator,
|
|
song = new SongMetaInfo {
|
|
name = src.Title,
|
|
author = src.Artist,
|
|
},
|
|
ruleset = ruleset,
|
|
cover = src.BackgroundFile,
|
|
note_count = src.HitObjects.Count,
|
|
};
|
|
var chart = new Chart {
|
|
format = 2,
|
|
time = new BeatTime(-4, 0, 1),
|
|
ruleset = ruleset,
|
|
sigs = new List<Chart.Signature>(),
|
|
sounds = new List<Chart.Sound> {
|
|
new Chart.Sound { time = new BeatTime(0, 0, 1), id = src.Title, offset = (float)(src.TimingPoints[0].StartTime / 1e3 + OFFSET) }
|
|
},
|
|
motions = new List<Chart.Motion>(),
|
|
groups = new List<Chart.Group>(),
|
|
};
|
|
var group = new Chart.Group() {
|
|
tracks = new List<Chart.Track>(),
|
|
notes = new List<Chart.Note>(),
|
|
motions = new List<Chart.Motion>(),
|
|
};
|
|
chart.groups.Add(group);
|
|
result.Add(new RawChartResource(string.Format("{0} - {1}", meta.song.name, meta.name), chart, meta));
|
|
result.Add(new SongResource(meta.song.name, new FileInfo(Path.Combine(file.DirectoryName, src.AudioFile))));
|
|
|
|
var evs = new List<EventWrapper>();
|
|
foreach (var e in src.HitObjects) evs.Add(new EventWrapper.HitObject(e));
|
|
foreach (var e in src.SliderVelocities) evs.Add(new EventWrapper.SliderVelocity(e));
|
|
foreach (var e in src.SoundEffects) evs.Add(new EventWrapper.SoundEffect(e));
|
|
foreach (var e in src.TimingPoints) evs.Add(new EventWrapper.TimingPoint(e));
|
|
var evc = evs.Count;
|
|
for (int i = 0; i < evc; i++) if (evs[i].IsLong) evs.Add(new EventWrapper.EndEvent(evs[i]));
|
|
evs.Sort();
|
|
|
|
var longevs = new Dictionary<EventWrapper, ChartEvent>();
|
|
var tm = new TimeTimingModel(src.TimingPoints[0].StartTime / 1e3, 2e-3);
|
|
foreach (var ev in evs) {
|
|
tm.ForwardTo(ev.StartTime / 1e3);
|
|
if (ev is EventWrapper.HitObject) {
|
|
var tev = (EventWrapper.HitObject)ev;
|
|
var rn = new Chart.Note {
|
|
time = tm.FractionalBeatTime,
|
|
motions = new List<Chart.Motion> {
|
|
new Chart.Motion { motion = string.Format(CultureInfo.InvariantCulture, "track:{0}", tev.Event.Lane - 1) }
|
|
},
|
|
};
|
|
if (ev.IsLong) longevs.Add(ev, rn);
|
|
group.notes.Add(rn);
|
|
}
|
|
else if (ev is EventWrapper.SliderVelocity) {
|
|
var tev = (EventWrapper.SliderVelocity)ev;
|
|
group.motions.Add(new Chart.Motion {
|
|
time = tm.FractionalBeatTime,
|
|
motion = string.Format(CultureInfo.InvariantCulture, "svm:{0}", tev.Event.Multiplier),
|
|
});
|
|
}
|
|
else if (ev is EventWrapper.TimingPoint) {
|
|
var tev = (EventWrapper.TimingPoint)ev;
|
|
tm.BPM = tev.Event.Bpm;
|
|
tm.ForceSnap();
|
|
chart.sigs.Add(new Chart.Signature {
|
|
time = tm.FractionalBeatTime,
|
|
tempo = tev.Event.Bpm,
|
|
});
|
|
}
|
|
else if (ev is EventWrapper.EndEvent) {
|
|
var tev = (EventWrapper.EndEvent)ev;
|
|
var oev = tev.Original;
|
|
longevs[oev].endtime = tm.FractionalBeatTime;
|
|
}
|
|
else throw new NotSupportedException("Sound effects are not supported yet");
|
|
}
|
|
var endbeat = tm.FractionalBeatTime;
|
|
endbeat.b += 4;
|
|
chart.endtime = endbeat;
|
|
meta.length = (float)tm.Time;
|
|
return result;
|
|
}
|
|
|
|
abstract class EventWrapper : IComparable<EventWrapper> {
|
|
public abstract int StartTime { get; }
|
|
public abstract int EndTime { get; }
|
|
public bool IsLong { get { return EndTime > 0; } }
|
|
public abstract int Priority { get; }
|
|
public int CompareTo(EventWrapper other) {
|
|
var c = StartTime.CompareTo(other.StartTime);
|
|
if (c != 0) return c;
|
|
return Priority.CompareTo(other.Priority);
|
|
}
|
|
public class HitObject : EventWrapper {
|
|
public HitObjectInfo Event;
|
|
public HitObject(HitObjectInfo ev) { Event = ev; }
|
|
public override int StartTime { get { return Event.StartTime; } }
|
|
public override int EndTime { get { return Event.EndTime; } }
|
|
public override int Priority { get { return 0; } }
|
|
}
|
|
public class SliderVelocity : EventWrapper {
|
|
public SliderVelocityInfo Event;
|
|
public SliderVelocity(SliderVelocityInfo ev) { Event = ev; }
|
|
public override int StartTime { get { return (int)Event.StartTime; } }
|
|
public override int EndTime { get { return 0; } }
|
|
public override int Priority { get { return 0; } }
|
|
}
|
|
public class SoundEffect : EventWrapper {
|
|
public SoundEffectInfo Event;
|
|
public SoundEffect(SoundEffectInfo ev) { Event = ev; }
|
|
public override int StartTime { get { return (int)Event.StartTime; } }
|
|
public override int EndTime { get { return 0; } }
|
|
public override int Priority { get { return 0; } }
|
|
}
|
|
public class TimingPoint : EventWrapper {
|
|
public TimingPointInfo Event;
|
|
public TimingPoint(TimingPointInfo ev) { Event = ev; }
|
|
public override int StartTime { get { return (int)Event.StartTime; } }
|
|
public override int EndTime { get { return 0; } }
|
|
public override int Priority { get { return -2; } }
|
|
}
|
|
public class EndEvent : EventWrapper {
|
|
public EventWrapper Original;
|
|
public EndEvent(EventWrapper ev) { if (!ev.IsLong) throw new ArgumentException("Event is not long"); Original = ev; }
|
|
public override int StartTime { get { return Original.EndTime; } }
|
|
public override int EndTime { get { return 0; } }
|
|
public override int Priority { get { return Original.Priority - 1; } }
|
|
}
|
|
}
|
|
}
|
|
}
|