Add project files.
This commit is contained in:
477
Assets/Cryville/Crtr/Chart.cs
Normal file
477
Assets/Cryville/Crtr/Chart.cs
Normal file
@@ -0,0 +1,477 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Cryville.Crtr {
|
||||
[JsonConverter(typeof(BeatTimeConverter))]
|
||||
public struct BeatTime {
|
||||
[JsonConstructor()]
|
||||
public BeatTime(int _b, int _n, int _d) {
|
||||
b = _b;
|
||||
n = _n;
|
||||
d = _d;
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public int b;
|
||||
|
||||
[JsonIgnore]
|
||||
public int n;
|
||||
|
||||
[JsonIgnore]
|
||||
public int d;
|
||||
}
|
||||
|
||||
public class BeatTimeConverter : JsonConverter {
|
||||
public override bool CanConvert(Type objectType) {
|
||||
return objectType == typeof(int[]);
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
|
||||
int b = (int)reader.ReadAsInt32();
|
||||
int n = (int)reader.ReadAsInt32();
|
||||
int d = (int)reader.ReadAsInt32();
|
||||
reader.Read();
|
||||
return new BeatTime(b, n, d);
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) {
|
||||
BeatTime obj = (BeatTime)value;
|
||||
writer.WriteStartArray();
|
||||
writer.WriteValue(obj.b);
|
||||
writer.WriteValue(obj.n);
|
||||
writer.WriteValue(obj.d);
|
||||
writer.WriteEndArray();
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class ChartEvent {
|
||||
public BeatTime? time;
|
||||
|
||||
[JsonIgnore]
|
||||
public float BeatPosition {
|
||||
get {
|
||||
return time.Value.b + time.Value.n / (float)time.Value.d + BeatOffset;
|
||||
}
|
||||
}
|
||||
|
||||
public BeatTime? endtime;
|
||||
|
||||
[JsonIgnore]
|
||||
public float EndBeatPosition {
|
||||
get {
|
||||
if (endtime == null) return BeatPosition;
|
||||
return endtime.Value.b + endtime.Value.n / (float)endtime.Value.d + BeatOffset;
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public float BeatOffset;
|
||||
|
||||
[JsonIgnore]
|
||||
public abstract int Priority {
|
||||
get;
|
||||
}
|
||||
|
||||
public ChartEvent Clone() {
|
||||
return (ChartEvent)MemberwiseClone();
|
||||
}
|
||||
|
||||
/*[DefaultValue(0.0f)][Obsolete]
|
||||
public float duration = 0.0f;*/
|
||||
|
||||
[JsonIgnore]
|
||||
public float Duration {
|
||||
get {
|
||||
if (endtime == null) return 0;
|
||||
return EndBeatPosition - BeatPosition;
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public bool IsLong {
|
||||
get { return Duration > 0; }
|
||||
}
|
||||
|
||||
/*[JsonIgnore]
|
||||
public float EndBeatPosition {
|
||||
get {
|
||||
return BeatPosition + duration;
|
||||
}
|
||||
}*/
|
||||
|
||||
private InstantEvent attev = null;
|
||||
[JsonIgnore]
|
||||
public InstantEvent AttackEvent {
|
||||
get {
|
||||
if (attev == null) attev = new InstantEvent(this);
|
||||
return attev;
|
||||
}
|
||||
}
|
||||
|
||||
private InstantEvent relev = null;
|
||||
[JsonIgnore]
|
||||
public InstantEvent ReleaseEvent {
|
||||
get {
|
||||
if (relev == null) relev = new InstantEvent(this, true);
|
||||
return relev;
|
||||
}
|
||||
}
|
||||
|
||||
/*[JsonIgnore]
|
||||
[Obsolete]
|
||||
public Dictionary<string, Func<object>> Properties { get; private set; }
|
||||
[Obsolete]
|
||||
protected void SubmitProperty(string name, Func<object> property) {
|
||||
Properties.Add(name, property);
|
||||
}*/
|
||||
|
||||
[JsonIgnore]
|
||||
public Dictionary<string, PropSrc> PropSrcs { get; private set; }
|
||||
protected void SubmitPropSrc(string name, PropSrc property) {
|
||||
PropSrcs.Add(name, property);
|
||||
}
|
||||
[JsonIgnore]
|
||||
public Dictionary<string, PropOp> PropOps { get; private set; }
|
||||
protected void SubmitPropOp(string name, PropOp property) {
|
||||
PropOps.Add(name, property);
|
||||
}
|
||||
|
||||
protected ChartEvent() {
|
||||
/*
|
||||
Properties = new Dictionary<string, Func<object>>();
|
||||
SubmitProperty("long", () => @long);
|
||||
*/
|
||||
PropSrcs = new Dictionary<string, PropSrc>();
|
||||
SubmitPropSrc("long", new PropSrc.Boolean(() => IsLong));
|
||||
PropOps = new Dictionary<string, PropOp>();
|
||||
}
|
||||
}
|
||||
|
||||
public class InstantEvent : ChartEvent {
|
||||
public readonly ChartEvent Original;
|
||||
public bool IsRelease;
|
||||
|
||||
public InstantEvent(ChartEvent orig, bool release = false) {
|
||||
IsRelease = release;
|
||||
if (orig != null) {
|
||||
Original = orig;
|
||||
time = orig.time;
|
||||
if (IsRelease)
|
||||
BeatOffset = orig.Duration;
|
||||
}
|
||||
}
|
||||
|
||||
public override int Priority {
|
||||
get {
|
||||
return Original.Priority + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
public abstract class EventContainer : ChartEvent {
|
||||
public List<Chart.Motion> motions = new List<Chart.Motion>();
|
||||
|
||||
[JsonIgnore]
|
||||
public virtual IEnumerable<ChartEvent> Events {
|
||||
get {
|
||||
return motions.Cast<ChartEvent>();
|
||||
}
|
||||
}
|
||||
|
||||
public virtual EventList GetEventsOfType(string type) {
|
||||
switch (type) {
|
||||
case "motions": return new EventList<Chart.Motion>(motions);
|
||||
default: throw new ArgumentException("Unknown type");
|
||||
}
|
||||
}
|
||||
}
|
||||
public abstract class EventList : ChartEvent {
|
||||
public IList<ChartEvent> Events { get; private set; }
|
||||
protected EventList(IList<ChartEvent> events) {
|
||||
Events = events;
|
||||
SubmitPropSrc("count", new PropSrc.Float(() => Events.Count));
|
||||
SubmitPropOp("count", new ListCountOp(() => Events));
|
||||
}
|
||||
public abstract ChartEvent Create();
|
||||
public override int Priority {
|
||||
get { throw new NotSupportedException("Fake event"); }
|
||||
}
|
||||
class ListCountOp : PropOp {
|
||||
readonly Func<IList<ChartEvent>> _cb;
|
||||
|
||||
public ListCountOp(Func<IList<ChartEvent>> cb) {
|
||||
_cb = cb;
|
||||
}
|
||||
|
||||
protected override void Execute() {
|
||||
int ac = _cb().Count;
|
||||
int ec = (int)Math.Round(GetOperand(0).AsNumber());
|
||||
if (ac != ec) {
|
||||
throw new RulesetViolationException(string.Format(
|
||||
"Event count not matched, expected {0}, got {1}", ec, ac
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public class EventList<T> : EventList where T : ChartEvent, new() {
|
||||
public EventList(List<T> events) : base(new CastedList<ChartEvent>(events)) { }
|
||||
public override ChartEvent Create() {
|
||||
return new T();
|
||||
}
|
||||
}
|
||||
|
||||
public class Chart : EventContainer {
|
||||
[JsonRequired]
|
||||
public long format; // Format Version
|
||||
|
||||
public string ruleset;
|
||||
|
||||
public List<Group> groups = new List<Group>();
|
||||
|
||||
public override IEnumerable<ChartEvent> Events {
|
||||
get {
|
||||
return base.Events
|
||||
.Concat(groups.Cast<ChartEvent>())
|
||||
.Concat(sigs.Cast<ChartEvent>())
|
||||
.Concat(sounds.Cast<ChartEvent>());
|
||||
}
|
||||
}
|
||||
|
||||
public override EventList GetEventsOfType(string type) {
|
||||
switch (type) {
|
||||
case "groups": return new EventList<Group>(groups);
|
||||
default: return base.GetEventsOfType(type);
|
||||
}
|
||||
}
|
||||
|
||||
public override int Priority {
|
||||
get { return 0; }
|
||||
}
|
||||
|
||||
public class Group : EventContainer {
|
||||
public List<Track> tracks = new List<Track>();
|
||||
public List<Note> notes = new List<Note>();
|
||||
public override IEnumerable<ChartEvent> Events {
|
||||
get {
|
||||
return tracks.Cast<ChartEvent>()
|
||||
.Concat(notes.Cast<ChartEvent>()
|
||||
.Concat(motions.Cast<ChartEvent>()
|
||||
));
|
||||
}
|
||||
}
|
||||
public override EventList GetEventsOfType(string type) {
|
||||
switch (type) {
|
||||
case "tracks": return new EventList<Track>(tracks);
|
||||
case "notes": return new EventList<Note>(notes);
|
||||
default: return base.GetEventsOfType(type);
|
||||
}
|
||||
}
|
||||
public override int Priority {
|
||||
get { return 0; }
|
||||
}
|
||||
}
|
||||
|
||||
public class Track : EventContainer {
|
||||
public override int Priority {
|
||||
get { return 0; }
|
||||
}
|
||||
}
|
||||
|
||||
public class Motion : ChartEvent {
|
||||
#pragma warning disable IDE1006
|
||||
[JsonRequired]
|
||||
public string motion {
|
||||
get { return ToString(); }
|
||||
set { LoadFromString(value); }
|
||||
}
|
||||
#pragma warning restore IDE1006
|
||||
|
||||
private void LoadFromString(string s) {
|
||||
Match m = Regex.Match(s, @"^(.+?)(#(\d+))?(@(.+?))?(\^(.+?))?(\*(.+?))?(:(.+))?$");
|
||||
if (!m.Success) throw new ArgumentException(); // TODO
|
||||
name = new MotionName(m.Groups[1].Value);
|
||||
var registry = ChartPlayer.motionRegistry[name.MainName];
|
||||
if (m.Groups[3].Success) {
|
||||
ushort id = ushort.Parse(m.Groups[3].Value);
|
||||
Vec1 time = m.Groups[5].Success ? new Vec1(m.Groups[5].Value) : null;
|
||||
byte? trs = m.Groups[7].Success ? byte.Parse(m.Groups[7].Value) : (byte?)null;
|
||||
Vec1 rate = m.Groups[9].Success ? new Vec1(m.Groups[9].Value) : null;
|
||||
Vector value = m.Groups[11].Success ? Vector.Construct(registry.Type, m.Groups[11].Value) : null;
|
||||
RelativeNode = new MotionNode() {
|
||||
Id = id,
|
||||
Time = time,
|
||||
Transition = (TransitionType?)trs,
|
||||
Rate = rate,
|
||||
Value = value
|
||||
};
|
||||
}
|
||||
else {
|
||||
AbsoluteValue = Vector.Construct(registry.Type, m.Groups[11].Value);
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
string result = Name.ToString();
|
||||
if (RelativeNode != null) {
|
||||
var node = RelativeNode;
|
||||
result += "#" + node.Id;
|
||||
if (node.Time != null) result += "@" + node.Time.ToString();
|
||||
if (node.Transition != null) result = "^" + node.Transition.ToString();
|
||||
if (node.Rate != null) result += "*" + node.Rate.ToString();
|
||||
if (node.Value != null) result += ":" + node.Value.ToString();
|
||||
}
|
||||
else {
|
||||
result += ":" + AbsoluteValue.ToString();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private MotionName name;
|
||||
[JsonIgnore]
|
||||
public MotionName Name {
|
||||
get {
|
||||
return name;
|
||||
}
|
||||
private set {
|
||||
MotionRegistry reg;
|
||||
if (!ChartPlayer.motionRegistry.TryGetValue(value.MainName, out reg))
|
||||
throw new ArgumentException("Invalid motion name");
|
||||
if (RelativeNode != null) RelativeNode.Value = reg.InitValue;
|
||||
else AbsoluteValue = reg.InitValue;
|
||||
name = value;
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public Vector AbsoluteValue;
|
||||
[JsonIgnore]
|
||||
public MotionNode RelativeNode;
|
||||
/*public struct Node {
|
||||
public ushort Id;
|
||||
public Vec1 Time;
|
||||
public TransitionType? Transition;
|
||||
public Vec1 Rate;
|
||||
public Vector Value;
|
||||
|
||||
public Node LerpWith(MotionNode start, float lerpedTime) {
|
||||
Vec1 time = Time == null ? null : (Vec1)Time.LerpWith(start.Time, lerpedTime);
|
||||
Vec1 rate = Rate == null ? null : (Vec1)Rate.LerpWith(start.Rate, lerpedTime);
|
||||
Vector value = Value == null ? null : Value.LerpWith(start.Value, lerpedTime);
|
||||
return new Node() {
|
||||
Id = Id,
|
||||
Time = time,
|
||||
Transition = Transition,
|
||||
Rate = rate,
|
||||
Value = value
|
||||
};
|
||||
}
|
||||
}*/
|
||||
|
||||
[DefaultValue(TransitionType.Ease)]
|
||||
public TransitionType transition = TransitionType.Ease;
|
||||
[DefaultValue(1.0f)]
|
||||
public float rate = 1.0f;
|
||||
[DefaultValue(0.0f)]
|
||||
public float sumfix = 0.0f;
|
||||
|
||||
public override int Priority {
|
||||
get { return -2; }
|
||||
}
|
||||
|
||||
public Motion() {
|
||||
SubmitPropSrc("value", new VectorSrc(() => {
|
||||
if (RelativeNode != null) return RelativeNode.Value;
|
||||
else return AbsoluteValue;
|
||||
}));
|
||||
SubmitPropOp("motion", new PropOp.String(v => motion = v));
|
||||
SubmitPropOp("name", new PropOp.String(v => {
|
||||
var n = new MotionName(v);
|
||||
if (Name.Equals(n)) { }
|
||||
else if (Name.Equals(default(MotionName))) Name = n;
|
||||
else throw new RulesetViolationException(string.Format(
|
||||
"Motion name not matched, expected {0}, got {1}", n, Name
|
||||
));
|
||||
}));
|
||||
SubmitPropOp("value", new VectorOp(v => {
|
||||
var vec = Vector.Construct(ChartPlayer.motionRegistry[Name.MainName].Type, v);
|
||||
if (RelativeNode != null) RelativeNode.Value = vec;
|
||||
else AbsoluteValue = vec;
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
public class Note : EventContainer {
|
||||
public Note() : base() {
|
||||
/*
|
||||
SubmitProperty("judge", () => judge);
|
||||
SubmitProperty("endjudge", () => endjudge);
|
||||
SubmitProperty("track", () => {
|
||||
if (_track == null) {
|
||||
var i = motions.FirstOrDefault(m => m.RelativeNode == null && m.Name.MainName == "track");
|
||||
if (i == null) _track = ((Vec1)ChartPlayer.motionRegistry["track"].InitValue).Value;
|
||||
else _track = ((Vec1)i.AbsoluteValue).Value;
|
||||
}
|
||||
return _track.Value;
|
||||
});
|
||||
*/
|
||||
|
||||
SubmitPropSrc("judge", new PropSrc.String(() => judge));
|
||||
SubmitPropSrc("endjudge", new PropSrc.String(() => endjudge));
|
||||
SubmitPropSrc("track", new PropSrc.Float(() => {
|
||||
var i = motions.FirstOrDefault(m => m.RelativeNode == null && m.Name.MainName == "track");
|
||||
if (i == null) return ((Vec1)ChartPlayer.motionRegistry["track"].InitValue).Value;
|
||||
else return ((Vec1)i.AbsoluteValue).Value;
|
||||
}));
|
||||
SubmitPropOp("judge", new PropOp.String(v => judge = v));
|
||||
SubmitPropOp("endjudge", new PropOp.String(v => endjudge = v));
|
||||
}
|
||||
|
||||
/*[DefaultValue(false)][Obsolete]
|
||||
public bool wipe = false;*/
|
||||
|
||||
public string judge;
|
||||
public string endjudge;
|
||||
|
||||
public override int Priority {
|
||||
get { return 2; }
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
public class InternalJudgement : ChartEvent {
|
||||
public Note Parent;
|
||||
|
||||
public override int Priority {
|
||||
get { return 0; }
|
||||
}
|
||||
}*/
|
||||
|
||||
// TODO will likely be deprecated in the future
|
||||
public List<Signature> sigs; // Signatures
|
||||
// TODO [Obsolete]
|
||||
public class Signature : ChartEvent {
|
||||
public float? tempo;
|
||||
|
||||
public override int Priority {
|
||||
get { return -4; }
|
||||
}
|
||||
}
|
||||
|
||||
public List<Sound> sounds;
|
||||
public class Sound : ChartEvent {
|
||||
[JsonRequired]
|
||||
public string id;
|
||||
|
||||
// TODO [Obsolete]
|
||||
public float offset;
|
||||
|
||||
public override int Priority {
|
||||
get { return 0; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user