Compare commits
41 Commits
0.5.0-rc3
...
c5571e7d17
Author | SHA1 | Date | |
---|---|---|---|
c5571e7d17 | |||
959157255f | |||
06d8012675 | |||
571320630b | |||
207dee9932 | |||
d7b0ca77e9 | |||
e55642cdeb | |||
595fd74662 | |||
3f7becf580 | |||
5d17555744 | |||
e6d94f248c | |||
b0c70bc62e | |||
8eb0b11027 | |||
7f2cfe94c1 | |||
e4524bda0b | |||
226fb15eb1 | |||
645c4af2f2 | |||
6e0f41c7fd | |||
b9001ed9b2 | |||
04abf59521 | |||
251f92532d | |||
f5df56687b | |||
b582da90e5 | |||
815f48fe06 | |||
1470fa87dd | |||
4b4356aaab | |||
a8658856ca | |||
1477e907e6 | |||
f559cea826 | |||
d363042036 | |||
69e4ecd0a9 | |||
35d2e06625 | |||
358e654f51 | |||
d16548e570 | |||
c7201dd62c | |||
e43a0e62b7 | |||
4bcf76819c | |||
31155c909c | |||
ab2670358a | |||
3da70bdccc | |||
e370e1937c |
@@ -1,8 +0,0 @@
|
||||
using System.Reflection;
|
||||
|
||||
[assembly: AssemblyCompany("Cryville")]
|
||||
[assembly: AssemblyCopyright("Copyright © Cryville 2020-2022")]
|
||||
[assembly: AssemblyDefaultAlias("Cosmo Resona")]
|
||||
[assembly: AssemblyProduct("Cosmo Resona")]
|
||||
[assembly: AssemblyTitle("Cosmo Resona")]
|
||||
[assembly: AssemblyVersion("0.5.0")]
|
@@ -73,7 +73,7 @@ namespace Cryville.Common.Buffers {
|
||||
if (!_invalidated) return;
|
||||
_invalidated = false;
|
||||
var ev = OnUpdate;
|
||||
if (ev != null) OnUpdate.Invoke();
|
||||
if (ev != null) ev.Invoke();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() {
|
||||
@@ -84,7 +84,7 @@ namespace Cryville.Common.Buffers {
|
||||
}
|
||||
|
||||
class Enumerator : IEnumerator<char> {
|
||||
TargetString _self;
|
||||
readonly TargetString _self;
|
||||
int _index = -1;
|
||||
public Enumerator(TargetString self) { _self = self; }
|
||||
|
||||
|
@@ -10,10 +10,10 @@ namespace Cryville.Common {
|
||||
/// </summary>
|
||||
public static IdentifierManager SharedInstance = new IdentifierManager();
|
||||
|
||||
Dictionary<object, int> _idents = new Dictionary<object, int>();
|
||||
List<object> _ids = new List<object>();
|
||||
readonly Dictionary<object, int> _idents = new Dictionary<object, int>();
|
||||
readonly List<object> _ids = new List<object>();
|
||||
|
||||
object _syncRoot = new object();
|
||||
readonly object _syncRoot = new object();
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of the <see cref="IdentifierManager" /> class.
|
||||
|
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
|
||||
namespace Cryville.Common {
|
||||
@@ -40,7 +41,7 @@ namespace Cryville.Common {
|
||||
public static void Create(string key, Logger logger) {
|
||||
Instances[key] = logger;
|
||||
if (logPath != null) {
|
||||
Files[key] = new StreamWriter(logPath + "/" + ((int)DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).TotalSeconds).ToString() + "-" + key + ".log") {
|
||||
Files[key] = new StreamWriter(logPath + "/" + ((int)DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).TotalSeconds).ToString(CultureInfo.InvariantCulture) + "-" + key + ".log") {
|
||||
AutoFlush = true
|
||||
};
|
||||
}
|
||||
|
@@ -48,5 +48,31 @@ namespace Cryville.Common.Math {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the greatest common divisor (GCD) of two integers.
|
||||
/// </summary>
|
||||
/// <param name="n">The first integer.</param>
|
||||
/// <param name="d">The second integer.</param>
|
||||
/// <returns>The greatest common divisor (GCD) of the two integers.</returns>
|
||||
public static int GreatestCommonDivisor(int n, int d) {
|
||||
while (d != 0) {
|
||||
int t = d;
|
||||
d = n % d;
|
||||
n = t;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Simplifies a fraction.
|
||||
/// </summary>
|
||||
/// <param name="n">The numerator.</param>
|
||||
/// <param name="d">The denominator.</param>
|
||||
public static void Simplify(ref int n, ref int d) {
|
||||
var gcd = GreatestCommonDivisor(n, d);
|
||||
n /= gcd;
|
||||
d /= gcd;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,9 +1,13 @@
|
||||
namespace Cryville.Common.Math {
|
||||
using System;
|
||||
|
||||
namespace Cryville.Common.Math {
|
||||
/// <summary>
|
||||
/// Represents a square matrix.
|
||||
/// </summary>
|
||||
public class SquareMatrix {
|
||||
readonly float[,] content;
|
||||
readonly float[,] buffer;
|
||||
readonly int[] refl;
|
||||
/// <summary>
|
||||
/// The size of the matrix.
|
||||
/// </summary>
|
||||
@@ -17,6 +21,8 @@
|
||||
/// <param name="size">The size of the matrix.</param>
|
||||
public SquareMatrix(int size) {
|
||||
content = new float[size, size];
|
||||
buffer = new float[size, size];
|
||||
refl = new int[size];
|
||||
Size = size;
|
||||
}
|
||||
/// <summary>
|
||||
@@ -38,38 +44,36 @@
|
||||
/// <returns>The column vector eliminated.</returns>
|
||||
public ColumnVector<T> Eliminate<T>(ColumnVector<T> v, IVectorOperator<T> o) {
|
||||
int s = Size;
|
||||
float[,] d = (float[,])content.Clone();
|
||||
int[] refl = new int[s];
|
||||
for (int i = 0; i < s; i++)
|
||||
refl[i] = i;
|
||||
Array.Copy(content, buffer, Size * Size);
|
||||
for (int i = 0; i < s; i++) refl[i] = i;
|
||||
for (int r = 0; r < s; r++) {
|
||||
for (int r0 = r; r0 < s; r0++)
|
||||
if (d[refl[r0], r] != 0) {
|
||||
if (buffer[refl[r0], r] != 0) {
|
||||
refl[r] = r0;
|
||||
refl[r0] = r;
|
||||
break;
|
||||
}
|
||||
int or = refl[r];
|
||||
float sf0 = d[or, r];
|
||||
float sf0 = buffer[or, r];
|
||||
for (int c0 = r; c0 < s; c0++)
|
||||
d[or, c0] /= sf0;
|
||||
buffer[or, c0] /= sf0;
|
||||
v[or] = o.ScalarMultiply(1 / sf0, v[or]);
|
||||
for (int r1 = r + 1; r1 < s; r1++) {
|
||||
int or1 = refl[r1];
|
||||
float sf1 = d[or1, r];
|
||||
float sf1 = buffer[or1, r];
|
||||
for (int c1 = r; c1 < s; c1++)
|
||||
d[or1, c1] -= d[or, c1] * sf1;
|
||||
buffer[or1, c1] -= buffer[or, c1] * sf1;
|
||||
v[or1] = o.Add(v[or1], o.ScalarMultiply(-sf1, v[or]));
|
||||
}
|
||||
}
|
||||
T[] res = new T[s];
|
||||
ColumnVector<T> res = new ColumnVector<T>(s);
|
||||
for (int r2 = s - 1; r2 >= 0; r2--) {
|
||||
var v2 = v[refl[r2]];
|
||||
for (int c2 = r2 + 1; c2 < s; c2++)
|
||||
v2 = o.Add(v2, o.ScalarMultiply(-d[refl[r2], c2], res[refl[c2]]));
|
||||
v2 = o.Add(v2, o.ScalarMultiply(-buffer[refl[r2], c2], res[refl[c2]]));
|
||||
res[refl[r2]] = v2;
|
||||
}
|
||||
return new ColumnVector<T>(res);
|
||||
return res;
|
||||
}
|
||||
/// <summary>
|
||||
/// Creates a square matrix and fills it with polynomial coefficients.
|
||||
|
@@ -77,7 +77,7 @@ namespace Cryville.Common.Network {
|
||||
encoding = Encoding.UTF8;
|
||||
payload = encoding.GetBytes(body);
|
||||
headers.Add("Content-Encoding", encoding.EncodingName);
|
||||
headers.Add("Content-Length", payload.Length.ToString());
|
||||
headers.Add("Content-Length", payload.Length.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
string request_line = string.Format(
|
||||
"{0} {1} {2}\r\n", method, uri, Version
|
||||
|
@@ -28,7 +28,7 @@ namespace Cryville.Common.Network {
|
||||
}
|
||||
|
||||
private class InternalTlsClient : DefaultTlsClient {
|
||||
string _host;
|
||||
readonly string _host;
|
||||
|
||||
public InternalTlsClient(string host, TlsCrypto crypto) : base(crypto) {
|
||||
_host = host;
|
||||
|
@@ -44,5 +44,21 @@ namespace Cryville.Common {
|
||||
if (result.Length == 0) return "_";
|
||||
return result;
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the process path from a command.
|
||||
/// </summary>
|
||||
/// <param name="command">The command.</param>
|
||||
/// <returns>The process path.</returns>
|
||||
public static string GetProcessPathFromCommand(string command) {
|
||||
command = command.Trim();
|
||||
if (command[0] == '"') {
|
||||
return command.Substring(1, command.IndexOf('"', 1) - 1);
|
||||
}
|
||||
else {
|
||||
int e = command.IndexOf(' ');
|
||||
if (e == -1) return command;
|
||||
else return command.Substring(0, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
@@ -11,13 +12,13 @@ namespace Cryville.Common.Unity {
|
||||
Transform dirs;
|
||||
Transform files;
|
||||
|
||||
public Action Callback { private get; set; }
|
||||
public event Action OnClose;
|
||||
|
||||
#if UNITY_ANDROID && !UNITY_EDITOR_WIN
|
||||
string androidStorage = "";
|
||||
#endif
|
||||
|
||||
string fileName = "";
|
||||
string fileName = null;
|
||||
public string FileName {
|
||||
get { return fileName; }
|
||||
}
|
||||
@@ -27,8 +28,16 @@ namespace Cryville.Common.Unity {
|
||||
set { m_filter = value; }
|
||||
}
|
||||
|
||||
#pragma warning disable IDE0051
|
||||
public Dictionary<string, string> m_presetPaths = new Dictionary<string, string>();
|
||||
public Dictionary<string, string> PresetPaths {
|
||||
get { return m_presetPaths; }
|
||||
set { m_presetPaths = value; }
|
||||
}
|
||||
|
||||
GameObject prefabButton;
|
||||
|
||||
void Start() {
|
||||
prefabButton = Resources.Load<GameObject>("Common/Button");
|
||||
panel = gameObject.transform.Find("Panel");
|
||||
title = panel.Find("Title/Text");
|
||||
drives = panel.Find("Drives/DrivesInner");
|
||||
@@ -38,8 +47,8 @@ namespace Cryville.Common.Unity {
|
||||
#if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN
|
||||
CurrentDirectory = new DirectoryInfo(Directory.GetCurrentDirectory());
|
||||
#elif UNITY_ANDROID
|
||||
using (AndroidJavaClass ajc=new AndroidJavaClass("android.os.Environment"))
|
||||
using (AndroidJavaObject file=ajc.CallStatic<AndroidJavaObject>("getExternalStorageDirectory")) {
|
||||
using (AndroidJavaClass ajc = new AndroidJavaClass("android.os.Environment"))
|
||||
using (AndroidJavaObject file = ajc.CallStatic<AndroidJavaObject>("getExternalStorageDirectory")) {
|
||||
androidStorage = file.Call<string>("getAbsolutePath");
|
||||
CurrentDirectory = new DirectoryInfo(androidStorage);
|
||||
}
|
||||
@@ -47,9 +56,8 @@ namespace Cryville.Common.Unity {
|
||||
#error No default directory
|
||||
#endif
|
||||
}
|
||||
UpdateGUI();
|
||||
UpdateGUI(0);
|
||||
}
|
||||
#pragma warning restore IDE0051
|
||||
|
||||
public void Show() {
|
||||
fileName = null;
|
||||
@@ -57,85 +65,82 @@ namespace Cryville.Common.Unity {
|
||||
}
|
||||
|
||||
public void Close() {
|
||||
if (Callback != null) Callback.Invoke();
|
||||
var ev = OnClose;
|
||||
if (ev != null) ev.Invoke();
|
||||
gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
public DirectoryInfo CurrentDirectory;
|
||||
|
||||
void OnDriveChanged(string s) {
|
||||
#if UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN
|
||||
CurrentDirectory = new DirectoryInfo(s);
|
||||
#elif UNITY_ANDROID
|
||||
switch (s) {
|
||||
case "?storage":
|
||||
CurrentDirectory = new DirectoryInfo(androidStorage);
|
||||
break;
|
||||
}
|
||||
#else
|
||||
#error No change drive logic
|
||||
#endif
|
||||
UpdateGUI();
|
||||
void ChangeDirectory(DirectoryInfo s) {
|
||||
CurrentDirectory = s;
|
||||
UpdateGUI(1);
|
||||
}
|
||||
|
||||
void OnDirectoryChanged(string s) {
|
||||
CurrentDirectory = new DirectoryInfo(CurrentDirectory.FullName + "/" + s);
|
||||
UpdateGUI();
|
||||
}
|
||||
|
||||
void OnFileChanged(string s) {
|
||||
void SelectFile(string s) {
|
||||
fileName = s;
|
||||
Close();
|
||||
}
|
||||
|
||||
void UpdateGUI() {
|
||||
void UpdateGUI(int depth) {
|
||||
title.GetComponent<Text>().text = CurrentDirectory.FullName;
|
||||
|
||||
CallHelper.Purge(drives);
|
||||
if (depth <= 0) {
|
||||
CallHelper.Purge(drives);
|
||||
#if UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN
|
||||
var dl = Directory.GetLogicalDrives();
|
||||
foreach (string d in dl) {
|
||||
GameObject btn = GameObject.Instantiate<GameObject>(Resources.Load<GameObject>("Common/Button"));
|
||||
btn.GetComponentInChildren<Text>().text = d;
|
||||
var ts = d;
|
||||
btn.GetComponentInChildren<Button>().onClick.AddListener(() => OnDriveChanged(ts));
|
||||
btn.transform.SetParent(drives, false);
|
||||
}
|
||||
var dl = Directory.GetLogicalDrives();
|
||||
foreach (string d in dl) {
|
||||
GameObject btn = Instantiate(prefabButton);
|
||||
btn.GetComponentInChildren<Text>().text = d;
|
||||
btn.GetComponentInChildren<Button>().onClick.AddListener(() => ChangeDirectory(new DirectoryInfo(d)));
|
||||
btn.transform.SetParent(drives, false);
|
||||
}
|
||||
#elif UNITY_ANDROID
|
||||
GameObject sbtn = GameObject.Instantiate<GameObject>(Resources.Load<GameObject>("Common/Button"));
|
||||
sbtn.GetComponentInChildren<Text>().text = "Storage";
|
||||
sbtn.GetComponentInChildren<Button>().onClick.AddListener(() => OnDriveChanged("?storage"));
|
||||
sbtn.transform.SetParent(drives, false);
|
||||
GameObject sbtn = GameObject.Instantiate<GameObject>(prefabButton);
|
||||
sbtn.GetComponentInChildren<Text>().text = "Storage";
|
||||
sbtn.GetComponentInChildren<Button>().onClick.AddListener(() => OnDriveChanged(new DirectoryInfo(androidStorage)));
|
||||
sbtn.transform.SetParent(drives, false);
|
||||
#else
|
||||
#error No update GUI logic
|
||||
#endif
|
||||
foreach (var p in m_presetPaths) {
|
||||
var d = new DirectoryInfo(p.Value);
|
||||
if (d.Exists) {
|
||||
GameObject btn = Instantiate(prefabButton);
|
||||
btn.GetComponentInChildren<Text>().text = p.Key;
|
||||
btn.GetComponentInChildren<Button>().onClick.AddListener(() => ChangeDirectory(d));
|
||||
btn.transform.SetParent(drives, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CallHelper.Purge(dirs);
|
||||
DirectoryInfo[] subdirs = CurrentDirectory.GetDirectories();
|
||||
GameObject pbtn = GameObject.Instantiate<GameObject>(Resources.Load<GameObject>("Common/Button"));
|
||||
GameObject pbtn = Instantiate(prefabButton);
|
||||
pbtn.GetComponentInChildren<Text>().text = "..";
|
||||
pbtn.GetComponentInChildren<Button>().onClick.AddListener(() => OnDirectoryChanged(".."));
|
||||
pbtn.GetComponentInChildren<Button>().onClick.AddListener(() => ChangeDirectory(new DirectoryInfo(Path.Combine(CurrentDirectory.FullName, ".."))));
|
||||
pbtn.transform.SetParent(dirs, false);
|
||||
foreach (DirectoryInfo d in subdirs) {
|
||||
GameObject btn = GameObject.Instantiate<GameObject>(Resources.Load<GameObject>("Common/Button"));
|
||||
GameObject btn = Instantiate(prefabButton);
|
||||
btn.GetComponentInChildren<Text>().text = d.Name;
|
||||
var ts = d.Name;
|
||||
btn.GetComponentInChildren<Button>().onClick.AddListener(() => OnDirectoryChanged(ts));
|
||||
var ts = d;
|
||||
btn.GetComponentInChildren<Button>().onClick.AddListener(() => ChangeDirectory(ts));
|
||||
btn.transform.SetParent(dirs, false);
|
||||
}
|
||||
|
||||
CallHelper.Purge(files);
|
||||
FileInfo[] fl = CurrentDirectory.GetFiles();
|
||||
foreach (FileInfo d in fl) {
|
||||
foreach (string ext in m_filter)
|
||||
if (d.Extension == ext) goto ext_matched;
|
||||
continue;
|
||||
ext_matched:
|
||||
GameObject btn = GameObject.Instantiate<GameObject>(Resources.Load<GameObject>("Common/Button"));
|
||||
btn.GetComponentInChildren<Text>().text = d.Name + " / " + (d.Length / 1024.0).ToString("0.0 KiB");
|
||||
var ts = d.FullName;
|
||||
btn.GetComponentInChildren<Button>().onClick.AddListener(() => OnFileChanged(ts));
|
||||
btn.transform.SetParent(files, false);
|
||||
foreach (string ext in m_filter) {
|
||||
if (d.Extension == ext) {
|
||||
GameObject btn = Instantiate(prefabButton);
|
||||
btn.GetComponentInChildren<Text>().text = d.Name + " / " + (d.Length / 1024.0).ToString("0.0 KiB");
|
||||
var ts = d.FullName;
|
||||
btn.GetComponentInChildren<Button>().onClick.AddListener(() => SelectFile(ts));
|
||||
btn.transform.SetParent(files, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -118,7 +118,7 @@ namespace Cryville.Common.Unity {
|
||||
fdialog = GameObject.Instantiate<GameObject>(Resources.Load<GameObject>("Common/FileDialog")).GetComponent<FileDialog>();
|
||||
fdialog.Filter = filter;
|
||||
fdialog.CurrentDirectory = ContextPath;
|
||||
fdialog.Callback = () => OnFileDialogClosed();
|
||||
fdialog.OnClose += OnFileDialogClosed;
|
||||
}
|
||||
editor.SetDescription(PropertyName, desc);
|
||||
UpdateValue();
|
||||
|
9
Assets/Cryville/Crtr/Browsing/ExtensionInterface.cs
Normal file
9
Assets/Cryville/Crtr/Browsing/ExtensionInterface.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Cryville.Crtr.Browsing {
|
||||
public abstract class ExtensionInterface {
|
||||
public abstract IEnumerable<ResourceConverter> GetResourceConverters();
|
||||
public abstract IEnumerable<LocalResourceFinder> GetResourceFinders();
|
||||
}
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a69a6c726b01961419c4835bba37a218
|
||||
guid: 4ffe72fef6ebb9e4da3571b4117f0d6d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
@@ -1,4 +1,6 @@
|
||||
namespace Cryville.Crtr.Browsing {
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Cryville.Crtr.Browsing {
|
||||
public interface IResourceManager<T> {
|
||||
string[] CurrentDirectory { get; }
|
||||
int ChangeDirectory(string[] dir);
|
||||
@@ -10,5 +12,6 @@
|
||||
|
||||
bool ImportItemFrom(string path);
|
||||
string[] GetSupportedFormats();
|
||||
Dictionary<string, string> GetPresetPaths();
|
||||
}
|
||||
}
|
@@ -17,6 +17,8 @@ namespace Cryville.Crtr.Browsing {
|
||||
|
||||
static readonly Dictionary<string, List<ResourceConverter>> converters
|
||||
= new Dictionary<string, List<ResourceConverter>>();
|
||||
static readonly Dictionary<string, string> localRes
|
||||
= new Dictionary<string, string>();
|
||||
|
||||
public LegacyResourceManager(string rootPath) {
|
||||
_rootPath = rootPath;
|
||||
@@ -25,13 +27,35 @@ namespace Cryville.Crtr.Browsing {
|
||||
static LegacyResourceManager() {
|
||||
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) {
|
||||
foreach (var type in asm.GetTypes()) {
|
||||
if (type.IsSubclassOf(typeof(ResourceConverter))) {
|
||||
var converter = (ResourceConverter)Activator.CreateInstance(type);
|
||||
foreach (var f in converter.GetSupportedFormats()) {
|
||||
if (!converters.ContainsKey(f))
|
||||
converters.Add(f, new List<ResourceConverter> { converter });
|
||||
else converters[f].Add(converter);
|
||||
if (!type.IsSubclassOf(typeof(ExtensionInterface))) continue;
|
||||
var ext = (ExtensionInterface)Activator.CreateInstance(type);
|
||||
try {
|
||||
var cs = ext.GetResourceConverters();
|
||||
if (cs != null) {
|
||||
foreach (var c in cs) {
|
||||
var fs = c.GetSupportedFormats();
|
||||
if (fs == null) continue;
|
||||
foreach (var f in fs) {
|
||||
if (f == null) continue;
|
||||
if (!converters.ContainsKey(f))
|
||||
converters.Add(f, new List<ResourceConverter> { c });
|
||||
else converters[f].Add(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
var fs2 = ext.GetResourceFinders();
|
||||
if (fs2 != null) {
|
||||
foreach (var f in fs2) {
|
||||
var name = f.Name;
|
||||
var path = f.GetRootPath();
|
||||
if (name != null && path != null)
|
||||
localRes.Add(name, path);
|
||||
}
|
||||
}
|
||||
Logger.Log("main", 1, "Resource", "Loaded extension {0}", ReflectionHelper.GetNamespaceQualifiedName(type));
|
||||
}
|
||||
catch (Exception ex) {
|
||||
Logger.Log("main", 4, "Resource", "Failed to initialize extension {0}: {1}", ReflectionHelper.GetNamespaceQualifiedName(type), ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -198,5 +222,9 @@ namespace Cryville.Crtr.Browsing {
|
||||
public string[] GetSupportedFormats() {
|
||||
return converters.Keys.ToArray();
|
||||
}
|
||||
|
||||
public Dictionary<string, string> GetPresetPaths() {
|
||||
return localRes;
|
||||
}
|
||||
}
|
||||
}
|
6
Assets/Cryville/Crtr/Browsing/LocalResourceFinder.cs
Normal file
6
Assets/Cryville/Crtr/Browsing/LocalResourceFinder.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace Cryville.Crtr.Browsing {
|
||||
public abstract class LocalResourceFinder {
|
||||
public abstract string Name { get; }
|
||||
public abstract string GetRootPath();
|
||||
}
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d6a3a023271b82a4985d1bbcc86e6fa8
|
||||
guid: f5b3f3294f679f14f8ec1195b0def630
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
@@ -20,6 +20,9 @@ namespace Cryville.Crtr.Browsing {
|
||||
|
||||
_dialog = GameObject.Instantiate(Resources.Load<GameObject>("Common/FileDialog")).GetComponent<FileDialog>();
|
||||
_dialog.gameObject.SetActive(false);
|
||||
_dialog.Filter = ResourceManager.GetSupportedFormats();
|
||||
_dialog.PresetPaths = ResourceManager.GetPresetPaths();
|
||||
_dialog.OnClose += OnAddDialogClosed;
|
||||
}
|
||||
|
||||
private bool LoadPathPart(int id, GameObject obj) {
|
||||
@@ -57,8 +60,6 @@ namespace Cryville.Crtr.Browsing {
|
||||
}
|
||||
|
||||
public void OnAddButtonClicked() {
|
||||
_dialog.Callback = OnAddDialogClosed;
|
||||
_dialog.Filter = ResourceManager.GetSupportedFormats();
|
||||
_dialog.Show();
|
||||
}
|
||||
|
||||
|
@@ -3,19 +3,25 @@ using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Cryville.Crtr {
|
||||
[JsonConverter(typeof(BeatTimeConverter))]
|
||||
public struct BeatTime {
|
||||
public struct BeatTime : IComparable<BeatTime>, IEquatable<BeatTime> {
|
||||
[JsonConstructor()]
|
||||
public BeatTime(int _b, int _n, int _d) {
|
||||
b = _b;
|
||||
n = _n;
|
||||
d = _d;
|
||||
}
|
||||
|
||||
public BeatTime(int _n, int _d) {
|
||||
b = _n / _d;
|
||||
n = _n % _d;
|
||||
d = _d;
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public int b;
|
||||
|
||||
@@ -24,6 +30,36 @@ namespace Cryville.Crtr {
|
||||
|
||||
[JsonIgnore]
|
||||
public int d;
|
||||
|
||||
[JsonIgnore]
|
||||
public double Decimal { get { return b + (double)n / d; } }
|
||||
|
||||
public int CompareTo(BeatTime other) {
|
||||
var c = b.CompareTo(other.b);
|
||||
if (c != 0) return c;
|
||||
return ((double)n / d).CompareTo((double)other.n / other.d);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj) {
|
||||
if (!(obj is BeatTime)) return false;
|
||||
return Equals((BeatTime)obj);
|
||||
}
|
||||
|
||||
public bool Equals(BeatTime other) {
|
||||
return b.Equals(other.b) && ((double)n / d).Equals((double)other.n / other.d);
|
||||
}
|
||||
|
||||
public override int GetHashCode() {
|
||||
return Decimal.GetHashCode();
|
||||
}
|
||||
|
||||
public static bool operator ==(BeatTime left, BeatTime right) {
|
||||
return left.Equals(right);
|
||||
}
|
||||
|
||||
public static bool operator !=(BeatTime left, BeatTime right) {
|
||||
return !left.Equals(right);
|
||||
}
|
||||
}
|
||||
|
||||
public class BeatTimeConverter : JsonConverter {
|
||||
@@ -55,7 +91,7 @@ namespace Cryville.Crtr {
|
||||
[JsonIgnore]
|
||||
public float BeatPosition {
|
||||
get {
|
||||
return time.Value.b + time.Value.n / (float)time.Value.d + BeatOffset;
|
||||
return (float)time.Value.Decimal + BeatOffset;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,7 +101,7 @@ namespace Cryville.Crtr {
|
||||
public float EndBeatPosition {
|
||||
get {
|
||||
if (endtime == null) return BeatPosition;
|
||||
return endtime.Value.b + endtime.Value.n / (float)endtime.Value.d + BeatOffset;
|
||||
return (float)endtime.Value.Decimal + BeatOffset;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -303,7 +339,7 @@ namespace Cryville.Crtr {
|
||||
var node = RelativeNode;
|
||||
result += "#" + node.Id;
|
||||
if (node.Time != null) result += "@" + node.Time.ToString();
|
||||
if (node.Transition != null) result = "^" + node.Transition.ToString();
|
||||
if (node.Transition != null) result = "^" + ((byte)node.Transition).ToString(CultureInfo.InvariantCulture);
|
||||
if (node.Rate != null) result += "*" + node.Rate.ToString();
|
||||
if (node.Value != null) result += ":" + node.Value.ToString();
|
||||
}
|
||||
@@ -391,10 +427,12 @@ namespace Cryville.Crtr {
|
||||
public class Judge : ChartEvent {
|
||||
[JsonIgnore]
|
||||
public Identifier Id;
|
||||
#pragma warning disable IDE1006
|
||||
public string name {
|
||||
get { return Id.ToString(); }
|
||||
set { Id = new Identifier(value); }
|
||||
}
|
||||
#pragma warning restore IDE1006
|
||||
|
||||
public override int Priority {
|
||||
get { return 0; }
|
||||
|
@@ -371,8 +371,9 @@ namespace Cryville.Crtr {
|
||||
texloadtimer.Start();
|
||||
frames = new Dictionary<string, SpriteFrame>();
|
||||
texs = new Dictionary<string, Texture2D>();
|
||||
var skinDir = skinFile.Directory.FullName;
|
||||
foreach (var f in skin.frames) {
|
||||
texLoadQueue.Enqueue(Path.Combine(skinFile.Directory.FullName, f));
|
||||
texLoadQueue.Enqueue(Path.Combine(skinDir, f));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -399,12 +400,16 @@ namespace Cryville.Crtr {
|
||||
Logger.Log("main", 0, "Load/Prehandle", "Prehandling (iteration 4)");
|
||||
cbus.BroadcastPostInit();
|
||||
inputProxy.Activate();
|
||||
if (logEnabled) ToggleLogs();
|
||||
if (logEnabled && Settings.Default.HideLogOnPlay) ToggleLogs();
|
||||
Logger.Log("main", 0, "Load/Prehandle", "Cleaning up");
|
||||
GC.Collect();
|
||||
if (disableGC) GarbageCollector.GCMode = GarbageCollector.Mode.Disabled;
|
||||
timer.Stop();
|
||||
Logger.Log("main", 1, "Load/Prehandle", "Prehandling done ({0}ms)", timer.Elapsed.TotalMilliseconds);
|
||||
if (Settings.Default.ClearLogOnPlay) {
|
||||
logs.text = "";
|
||||
Game.MainLogger.Enumerate((level, module, msg) => { });
|
||||
}
|
||||
Game.AudioSequencer.Playing = true;
|
||||
atime0 = Game.AudioClient.BufferPosition;
|
||||
Thread.Sleep((int)((atime0 - Game.AudioClient.Position) * 1000));
|
||||
|
@@ -22,7 +22,9 @@ namespace Cryville.Crtr.Components {
|
||||
}
|
||||
protected void UpdateZIndex() {
|
||||
if (!mesh.Initialized) return;
|
||||
mesh.Renderer.material.renderQueue = _zindex;
|
||||
foreach (var mat in mesh.Renderer.materials) {
|
||||
mat.renderQueue = _zindex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -52,9 +52,9 @@ namespace Cryville.Crtr.Components {
|
||||
static readonly ArrayPool<Vector2> _shapePool = new ArrayPool<Vector2>(0x100, 0x10000);
|
||||
|
||||
public PolygonSGO() {
|
||||
SubmitProperty("head", new PropOp.String(v => head.FrameName = v));
|
||||
SubmitProperty("body", new PropOp.String(v => body.FrameName = v));
|
||||
SubmitProperty("tail", new PropOp.String(v => tail.FrameName = v));
|
||||
SubmitProperty("head", new PropOp.String(v => head.FrameName = v), 2);
|
||||
SubmitProperty("body", new PropOp.String(v => body.FrameName = v), 2);
|
||||
SubmitProperty("tail", new PropOp.String(v => tail.FrameName = v), 2);
|
||||
SubmitProperty("shape", new op_set_shape(this), 2);
|
||||
}
|
||||
|
||||
@@ -98,18 +98,14 @@ namespace Cryville.Crtr.Components {
|
||||
|
||||
public override void Init() {
|
||||
base.Init();
|
||||
|
||||
head.Load();
|
||||
body.Load();
|
||||
tail.Load();
|
||||
|
||||
mesh.Init(transform);
|
||||
|
||||
List<Material> materials = new List<Material>();
|
||||
if (head.FrameName != null) AddMat(materials, head.FrameName);
|
||||
if (body.FrameName != null) AddMat(materials, body.FrameName);
|
||||
if (tail.FrameName != null) AddMat(materials, tail.FrameName);
|
||||
mesh.Renderer.materials = materials.ToArray();
|
||||
var mats = mesh.Renderer.materials = new Material[] { mesh.NewMaterial, mesh.NewMaterial, mesh.NewMaterial };
|
||||
head.Bind(mats[0]);
|
||||
body.Bind(mats[1]);
|
||||
tail.Bind(mats[2]);
|
||||
|
||||
UpdateZIndex();
|
||||
}
|
||||
|
||||
void AddMat(List<Material> list, string frame) {
|
||||
@@ -156,9 +152,9 @@ namespace Cryville.Crtr.Components {
|
||||
int vcpsec = _shapeLength; // Vertex Count Per Section
|
||||
float width = GetWidth();
|
||||
float headLength = 0;
|
||||
if (head.FrameName != null) headLength = width / head.Ratio;
|
||||
if (head.Frame != null) headLength = width / head.Ratio;
|
||||
float tailLength = 0;
|
||||
if (tail.FrameName != null) tailLength = width / tail.Ratio;
|
||||
if (tail.Frame != null) tailLength = width / tail.Ratio;
|
||||
float endLength = headLength + tailLength;
|
||||
if (sumLength <= endLength) {
|
||||
// The total length of the two ends is longer than the whole mesh, squeeze the two ends
|
||||
@@ -186,17 +182,17 @@ namespace Cryville.Crtr.Components {
|
||||
verts = _vertPool.Rent(vc * vcpsec);
|
||||
uvs = _uvPool.Rent(vc * vcpsec);
|
||||
int i = 0; int t = 0; float l = 0; int m = 0;
|
||||
if (head.FrameName != null) { m++; GenerateMeshTo(verts, uvs, out trih, head, ref i, ref t, ref l, 0, headLength, vcpsec, hvc); }
|
||||
if (body.FrameName != null) { m++; GenerateMeshTo(verts, uvs, out trib, body, ref i, ref t, ref l, headLength, sumLength - tailLength, vcpsec, hvc + bvc); }
|
||||
if (tail.FrameName != null) { m++; GenerateMeshTo(verts, uvs, out trit, tail, ref i, ref t, ref l, sumLength - tailLength, sumLength, vcpsec, vc); }
|
||||
if (head.Frame != null) { m++; GenerateMeshTo(verts, uvs, out trih, head, ref i, ref t, ref l, 0, headLength, vcpsec, hvc); }
|
||||
if (body.Frame != null) { m++; GenerateMeshTo(verts, uvs, out trib, body, ref i, ref t, ref l, headLength, sumLength - tailLength, vcpsec, hvc + bvc); }
|
||||
if (tail.Frame != null) { m++; GenerateMeshTo(verts, uvs, out trit, tail, ref i, ref t, ref l, sumLength - tailLength, sumLength, vcpsec, vc); }
|
||||
|
||||
mesh.Mesh.subMeshCount = m;
|
||||
m = 0;
|
||||
mesh.Mesh.SetVertices(verts);
|
||||
mesh.Mesh.SetUVs(0, uvs);
|
||||
if (head.FrameName != null) mesh.Mesh.SetTriangles(trih, m++);
|
||||
if (body.FrameName != null) mesh.Mesh.SetTriangles(trib, m++);
|
||||
if (tail.FrameName != null) mesh.Mesh.SetTriangles(trit, m++);
|
||||
if (head.Frame != null) mesh.Mesh.SetTriangles(trih, m++);
|
||||
if (body.Frame != null) mesh.Mesh.SetTriangles(trib, m++);
|
||||
if (tail.Frame != null) mesh.Mesh.SetTriangles(trit, m++);
|
||||
mesh.Mesh.RecalculateNormals();
|
||||
|
||||
_vertPool.Return(verts); verts = null;
|
||||
|
@@ -1,4 +1,5 @@
|
||||
using Cryville.Common.Pdt;
|
||||
using Cryville.Common;
|
||||
using Cryville.Common.Pdt;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
@@ -7,21 +8,21 @@ namespace Cryville.Crtr.Components {
|
||||
/// <summary>
|
||||
/// The property operators of the component.
|
||||
/// </summary>
|
||||
public Dictionary<string, SkinProperty> Properties { get; private set; }
|
||||
public Dictionary<int, SkinProperty> Properties { get; private set; }
|
||||
/// <summary>
|
||||
/// Submits a property.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the property.</param>
|
||||
/// <param name="property">The property.</param>
|
||||
protected void SubmitProperty(string name, PdtOperator property, int uct = 1) {
|
||||
Properties.Add(name, new SkinProperty(property, uct));
|
||||
Properties.Add(IdentifierManager.SharedInstance.Request(name), new SkinProperty(property, uct));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a skin component.
|
||||
/// </summary>
|
||||
protected SkinComponent() {
|
||||
Properties = new Dictionary<string, SkinProperty>();
|
||||
Properties = new Dictionary<int, SkinProperty>();
|
||||
}
|
||||
|
||||
public virtual void Init() { }
|
||||
|
@@ -4,7 +4,16 @@ using Logger = Cryville.Common.Logger;
|
||||
|
||||
namespace Cryville.Crtr.Components {
|
||||
public class SpriteInfo {
|
||||
public string FrameName;
|
||||
string m_frameName;
|
||||
public string FrameName {
|
||||
get {
|
||||
return m_frameName;
|
||||
}
|
||||
set {
|
||||
m_frameName = value;
|
||||
Reload();
|
||||
}
|
||||
}
|
||||
public SpriteFrame Frame {
|
||||
get;
|
||||
private set;
|
||||
@@ -20,21 +29,38 @@ namespace Cryville.Crtr.Components {
|
||||
return Rect.width / Rect.height;
|
||||
}
|
||||
}
|
||||
bool _loaded;
|
||||
Material _mat;
|
||||
public void Bind(Material mat) {
|
||||
_loaded = true;
|
||||
_mat = mat;
|
||||
Reload();
|
||||
}
|
||||
public void Load() {
|
||||
if (FrameName != null) {
|
||||
_loaded = true;
|
||||
Reload();
|
||||
}
|
||||
public void Reload() {
|
||||
if (!_loaded) return;
|
||||
if (!string.IsNullOrEmpty(FrameName)) {
|
||||
if (ChartPlayer.frames.ContainsKey(FrameName)) {
|
||||
Frame = ChartPlayer.frames[FrameName];
|
||||
}
|
||||
else {
|
||||
Logger.Log("main", 4, "Skin", "Texture {0} not found", FrameName);
|
||||
Frame = null;
|
||||
}
|
||||
}
|
||||
else Frame = null;
|
||||
if (_mat != null) {
|
||||
_mat.mainTexture = Frame == null ? null : Frame.Texture;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class SpritePlane : SpriteBase {
|
||||
public SpritePlane() {
|
||||
SubmitProperty("frame", new PropOp.String(v => Frame = v));
|
||||
SubmitProperty("frame", new PropOp.String(v => Frame = v), 2);
|
||||
SubmitProperty("fit", new PropOp.Enum<FitMode>(v => Fit = v));
|
||||
SubmitProperty("opacity", new PropOp.Float(v => Opacity = v));
|
||||
}
|
||||
@@ -68,16 +94,11 @@ namespace Cryville.Crtr.Components {
|
||||
}
|
||||
protected void OnFrameUpdate() {
|
||||
if (!mesh.Initialized) return;
|
||||
if (frameInfo.FrameName == null) {
|
||||
if (frameInfo.Frame == null) {
|
||||
mesh.Renderer.enabled = false;
|
||||
return;
|
||||
}
|
||||
mesh.Renderer.enabled = true;
|
||||
frameInfo.Load();
|
||||
if (frameInfo.Frame != null)
|
||||
mesh.Renderer.material.mainTexture = frameInfo.Frame.Texture;
|
||||
else
|
||||
Logger.Log("main", 4, "Skin", "Unable to load texture {0}", frameInfo.FrameName);
|
||||
UpdateUV();
|
||||
UpdateScale();
|
||||
UpdateZIndex();
|
||||
@@ -140,8 +161,8 @@ namespace Cryville.Crtr.Components {
|
||||
}
|
||||
|
||||
public override void Init() {
|
||||
frameInfo.Load();
|
||||
InternalInit();
|
||||
frameInfo.Bind(mesh.Renderer.material);
|
||||
OnFrameUpdate();
|
||||
UpdateOpacity();
|
||||
}
|
||||
|
@@ -25,13 +25,14 @@ namespace Cryville.Crtr.Config {
|
||||
GameObject m_prefabInputConfigEntry;
|
||||
|
||||
public InputProxy proxy;
|
||||
Dictionary<string, InputConfigPanelEntry> _entries = new Dictionary<string, InputConfigPanelEntry>();
|
||||
readonly Dictionary<string, InputConfigPanelEntry> _entries = new Dictionary<string, InputConfigPanelEntry>();
|
||||
|
||||
string _sel;
|
||||
public void OpenDialog(string entry) {
|
||||
_sel = entry;
|
||||
m_inputDialog.SetActive(true);
|
||||
CallHelper.Purge(m_deviceList);
|
||||
Game.InputManager.EnumerateEvents(ev => { });
|
||||
_recvsrcs.Clear();
|
||||
AddSourceItem(null);
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
using Cryville.Crtr.Components;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Cryville.Crtr.Event {
|
||||
@@ -75,7 +76,7 @@ namespace Cryville.Crtr.Event {
|
||||
get;
|
||||
}
|
||||
public virtual void PreInit() {
|
||||
gogroup = new GameObject(TypeName + ":" + Container.GetHashCode().ToString()).transform;
|
||||
gogroup = new GameObject(TypeName + ":" + Container.GetHashCode().ToString(CultureInfo.InvariantCulture)).transform;
|
||||
if (cs.Parent != null)
|
||||
gogroup.SetParent(cs.Parent.Handler.gogroup, false);
|
||||
a_head = new GameObject("::head").transform;
|
||||
|
@@ -56,7 +56,7 @@ namespace Cryville.Crtr.Event {
|
||||
private set;
|
||||
}
|
||||
|
||||
public float Time {
|
||||
public double Time {
|
||||
get {
|
||||
return Bus.Time;
|
||||
}
|
||||
@@ -186,7 +186,6 @@ namespace Cryville.Crtr.Event {
|
||||
child.Value.CopyTo(ct, dest.Children[child.Key]);
|
||||
ValidateChildren();
|
||||
|
||||
RMVPool.ReturnAll();
|
||||
dest.PlayingMotions.Clear();
|
||||
foreach (var m in PlayingMotions) dest.PlayingMotions.Add(m.Key, m.Value);
|
||||
}
|
||||
@@ -226,7 +225,7 @@ namespace Cryville.Crtr.Event {
|
||||
if (tr.Valid) return r;
|
||||
#endif
|
||||
float reltime = 0;
|
||||
if (rootPrototype != null) reltime = Time - rootPrototype.Time;
|
||||
if (rootPrototype != null) reltime = (float)(Time - rootPrototype.Time);
|
||||
GetMotionValue(key).GetValue(reltime, ref r);
|
||||
if (Parent != null) r.ApplyFrom(Parent.GetRawValue(key));
|
||||
#if !DISABLE_CACHE
|
||||
@@ -324,11 +323,14 @@ namespace Cryville.Crtr.Event {
|
||||
if (ev.Unstamped is Chart.Motion) {
|
||||
var tev = (Chart.Motion)ev.Unstamped;
|
||||
var mv = RMVPool.Rent(tev.Name);
|
||||
mv.CloneTypeFlag = CloneType;
|
||||
GetMotionValue(tev.Name).CopyTo(mv);
|
||||
PlayingMotions.Add(ev, mv);
|
||||
Callback(ev, callback);
|
||||
if (!ev.Unstamped.IsLong)
|
||||
if (!ev.Unstamped.IsLong) {
|
||||
PlayingMotions.Remove(ev);
|
||||
RMVPool.Return(mv);
|
||||
}
|
||||
}
|
||||
else if (ev.Unstamped is EventContainer) {
|
||||
var cev = (EventContainer)ev.Unstamped;
|
||||
@@ -348,6 +350,8 @@ namespace Cryville.Crtr.Event {
|
||||
var nev = tev.Original;
|
||||
if (nev is Chart.Motion) {
|
||||
Callback(ev, callback);
|
||||
var mv = PlayingMotions[ev.Origin];
|
||||
if (mv.CloneTypeFlag == CloneType) RMVPool.Return(mv);
|
||||
PlayingMotions.Remove(ev.Origin);
|
||||
}
|
||||
else if (nev is EventContainer) {
|
||||
@@ -390,7 +394,7 @@ namespace Cryville.Crtr.Event {
|
||||
}
|
||||
}
|
||||
else {
|
||||
var scaledTime = (Time - m.Key.Time - ChartPlayer.actualRenderStep * tev.sumfix) / m.Key.Duration;
|
||||
var scaledTime = (float)((Time - m.Key.Time - ChartPlayer.actualRenderStep * tev.sumfix) / m.Key.Duration);
|
||||
var lerpedTime = MotionLerper.GetEaseTime(scaledTime, tev.transition, tev.rate);
|
||||
if (tev.RelativeNode != null) {
|
||||
var target = value.QueryRelativeNode(tev.RelativeNode.Id);
|
||||
|
@@ -4,7 +4,7 @@ using System.Collections.Generic;
|
||||
|
||||
namespace Cryville.Crtr.Event {
|
||||
public class EventBatch : IComparable<EventBatch>, IEnumerable<StampedEvent> {
|
||||
public float Time {
|
||||
public double Time {
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
@@ -14,7 +14,7 @@ namespace Cryville.Crtr.Event {
|
||||
get { return queue.Count; }
|
||||
}
|
||||
|
||||
public EventBatch(float time) {
|
||||
public EventBatch(double time) {
|
||||
Time = time;
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace Cryville.Crtr.Event {
|
||||
}
|
||||
|
||||
public int CompareTo(EventBatch other) {
|
||||
return this.Time.CompareTo(other.Time);
|
||||
return Time.CompareTo(other.Time);
|
||||
}
|
||||
|
||||
public IEnumerator<StampedEvent> GetEnumerator() {
|
||||
|
@@ -17,8 +17,8 @@ namespace Cryville.Crtr.Event {
|
||||
= new Dictionary<ChartEvent, ContainerState>();
|
||||
public List<StampedEvent> stampedEvents = new List<StampedEvent>();
|
||||
readonly List<EventBatch> batches = new List<EventBatch>();
|
||||
|
||||
float beat;
|
||||
|
||||
double beat;
|
||||
float tempo;
|
||||
|
||||
public EventBatcher(Chart c) : base(c, new List<ChartEvent>()) {
|
||||
@@ -56,12 +56,12 @@ namespace Cryville.Crtr.Event {
|
||||
}
|
||||
}
|
||||
|
||||
public override void ForwardOnceToTime(float toTime, Action<ChartEvent> callback) {
|
||||
float toBeat = (float)Math.Round(beat + (toTime - Time) * tempo / 60f, 6);
|
||||
public override void ForwardOnceToTime(double toTime, Action<ChartEvent> callback) {
|
||||
double toBeat = Math.Round(beat + (toTime - Time) * tempo / 60f, 6);
|
||||
if (EventId >= events.Count)
|
||||
goto return_ahead;
|
||||
float ebeat = events[EventId].BeatPosition;
|
||||
float etime = (float)Math.Round((ebeat - beat) / tempo * 60f + Time, 6);
|
||||
double ebeat = events[EventId].BeatPosition;
|
||||
double etime = Math.Round((ebeat - beat) / tempo * 60f + Time, 6);
|
||||
if (etime > toTime)
|
||||
goto return_ahead;
|
||||
var batch = GetEventBatch();
|
||||
|
@@ -114,7 +114,7 @@ namespace Cryville.Crtr.Event {
|
||||
patch.Clear();
|
||||
}
|
||||
|
||||
public override void ForwardOnceToTime(float toTime, Action<EventBatch> callback = null) {
|
||||
public override void ForwardOnceToTime(double toTime, Action<EventBatch> callback = null) {
|
||||
if (EventId < events.Count && events[EventId].Time <= toTime) {
|
||||
Time = events[EventId].Time;
|
||||
var batch = events[EventId];
|
||||
|
@@ -6,11 +6,12 @@ using Newtonsoft.Json.Converters;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
|
||||
namespace Cryville.Crtr.Extensions.Bestdori {
|
||||
public class BestdoriChartConverter : ResourceConverter {
|
||||
static readonly string[] SUPPORTED_FORMATS = { ".json" };
|
||||
static readonly string[] SUPPORTED_FORMATS = { ".bestdori" };
|
||||
public override string[] GetSupportedFormats() {
|
||||
return SUPPORTED_FORMATS;
|
||||
}
|
||||
@@ -35,15 +36,12 @@ namespace Cryville.Crtr.Extensions.Bestdori {
|
||||
motions = new List<Chart.Motion>(),
|
||||
groups = new List<Chart.Group> { group },
|
||||
};
|
||||
var tm = new BeatTimeTimingModel();
|
||||
string bgm = null;
|
||||
double? cbpm = null;
|
||||
double pbeat = 0, ctime = 0;
|
||||
double endbeat = 0;
|
||||
foreach (var ev in src) {
|
||||
double cbeat = ev.StartBeat;
|
||||
ctime += cbpm == null ? 0 : (cbeat - pbeat) / cbpm.Value * 60;
|
||||
pbeat = cbeat;
|
||||
if (cbeat > endbeat) endbeat = cbeat;
|
||||
tm.ForwardTo(ev.StartBeat);
|
||||
if (ev.StartBeat > endbeat) endbeat = ev.StartBeat;
|
||||
if (ev is BestdoriChartEvent.System) {
|
||||
if (bgm != null) continue;
|
||||
var tev = (BestdoriChartEvent.System)ev;
|
||||
@@ -54,7 +52,7 @@ namespace Cryville.Crtr.Extensions.Bestdori {
|
||||
}
|
||||
else if (ev is BestdoriChartEvent.BPM) {
|
||||
var tev = (BestdoriChartEvent.BPM)ev;
|
||||
cbpm = tev.bpm;
|
||||
tm.BPM = tev.bpm;
|
||||
chart.sigs.Add(new Chart.Signature { time = ToBeatTime(tev.beat), tempo = (float)tev.bpm });
|
||||
}
|
||||
else if (ev is BestdoriChartEvent.Single) {
|
||||
@@ -62,7 +60,7 @@ namespace Cryville.Crtr.Extensions.Bestdori {
|
||||
group.notes.Add(new Chart.Note {
|
||||
time = ToBeatTime(tev.beat),
|
||||
judges = new List<Chart.Judge> { new Chart.Judge { name = tev.flick ? "single_flick" : "single" } },
|
||||
motions = new List<Chart.Motion> { new Chart.Motion { motion = "track:" + tev.lane.ToString() } },
|
||||
motions = new List<Chart.Motion> { new Chart.Motion { motion = "track:" + tev.lane.ToString(CultureInfo.InvariantCulture) } },
|
||||
});
|
||||
}
|
||||
else if (ev is BestdoriChartEvent.Long) {
|
||||
@@ -75,13 +73,17 @@ namespace Cryville.Crtr.Extensions.Bestdori {
|
||||
};
|
||||
for (int i = 0; i < tev.connections.Count; i++) {
|
||||
BestdoriChartEvent.Connection c = tev.connections[i];
|
||||
note.motions.Add(new Chart.Motion { motion = "track:" + c.lane.ToString() });
|
||||
if (i == 0)
|
||||
if (i == 0) {
|
||||
note.judges.Add(new Chart.Judge { name = "single" });
|
||||
else if (i == tev.connections.Count - 1)
|
||||
note.judges.Add(new Chart.Judge { time = ToBeatTime(c.beat), name = c.flick ? "longend_flick" : "longend" });
|
||||
else if (!c.hidden)
|
||||
note.judges.Add(new Chart.Judge { time = ToBeatTime(c.beat), name = "longnode" });
|
||||
note.motions.Add(new Chart.Motion { motion = "track:" + c.lane.ToString(CultureInfo.InvariantCulture) });
|
||||
}
|
||||
else {
|
||||
note.motions.Add(new Chart.Motion { time = ToBeatTime(tev.connections[i - 1].beat), endtime = ToBeatTime(c.beat), motion = "track:" + c.lane.ToString(CultureInfo.InvariantCulture) });
|
||||
if (i == tev.connections.Count - 1)
|
||||
note.judges.Add(new Chart.Judge { time = ToBeatTime(c.beat), name = c.flick ? "longend_flick" : "longend" });
|
||||
else if (!c.hidden)
|
||||
note.judges.Add(new Chart.Judge { time = ToBeatTime(c.beat), name = "longnode" });
|
||||
}
|
||||
}
|
||||
if (c1.beat > endbeat) endbeat = c1.beat;
|
||||
group.notes.Add(note);
|
||||
@@ -89,13 +91,14 @@ namespace Cryville.Crtr.Extensions.Bestdori {
|
||||
else throw new NotImplementedException("Unsupported event: " + ev.type);
|
||||
}
|
||||
if (bgm == null) throw new FormatException("Chart contains no song");
|
||||
chart.endtime = ToBeatTime(endbeat);
|
||||
chart.endtime = ToBeatTime(endbeat + 4);
|
||||
if (endbeat > tm.BeatTime) tm.ForwardTo(endbeat);
|
||||
result.Add(new RawChartResource(string.Format("bang_dream_girls_band_party__{0}__{1}", bgm, StringUtils.TrimExt(file.Name)), chart, new ChartMeta {
|
||||
name = string.Format("Bandori {0} {1}", bgm, StringUtils.TrimExt(file.Name)),
|
||||
author = "©BanG Dream! Project ©Craft Egg Inc. ©bushiroad",
|
||||
ruleset = "bang_dream_girls_band_party",
|
||||
note_count = group.notes.Count,
|
||||
length = (float)ctime,
|
||||
length = (float)tm.Time,
|
||||
song = new SongMetaInfo {
|
||||
name = bgm,
|
||||
author = "©BanG Dream! Project ©Craft Egg Inc. ©bushiroad",
|
||||
@@ -110,73 +113,73 @@ namespace Cryville.Crtr.Extensions.Bestdori {
|
||||
i = n / d; n %= d;
|
||||
return new BeatTime(i, n, d);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma warning disable IDE1006
|
||||
[JsonConverter(typeof(BestdoriChartEventCreator))]
|
||||
abstract class BestdoriChartEvent {
|
||||
public abstract string type { get; }
|
||||
public abstract double StartBeat { get; }
|
||||
public abstract class InstantEvent : BestdoriChartEvent {
|
||||
public double beat;
|
||||
public override double StartBeat { get { return beat; } }
|
||||
[JsonConverter(typeof(BestdoriChartEventCreator))]
|
||||
abstract class BestdoriChartEvent {
|
||||
public abstract string type { get; }
|
||||
public abstract double StartBeat { get; }
|
||||
public abstract class InstantEvent : BestdoriChartEvent {
|
||||
public double beat;
|
||||
public override double StartBeat { get { return beat; } }
|
||||
}
|
||||
public class BPM : InstantEvent {
|
||||
public override string type { get { return "BPM"; } }
|
||||
public double bpm;
|
||||
}
|
||||
public class System : InstantEvent {
|
||||
public override string type { get { return "System"; } }
|
||||
public string data;
|
||||
}
|
||||
public abstract class SingleBase : InstantEvent {
|
||||
public double lane;
|
||||
public bool skill;
|
||||
public bool flick;
|
||||
}
|
||||
public class Single : SingleBase {
|
||||
public override string type { get { return "Single"; } }
|
||||
}
|
||||
public class Directional : SingleBase {
|
||||
public override string type { get { return "Directional"; } }
|
||||
public string direction;
|
||||
public int width;
|
||||
}
|
||||
public class Connection : SingleBase {
|
||||
public override string type { get { return null; } }
|
||||
public bool hidden;
|
||||
}
|
||||
public class Long : BestdoriChartEvent {
|
||||
public override string type { get { return "Long"; } }
|
||||
public List<Connection> connections;
|
||||
public override double StartBeat { get { return connections[0].beat; } }
|
||||
}
|
||||
public class Slide : Long {
|
||||
public override string type { get { return "Slide"; } }
|
||||
}
|
||||
}
|
||||
public class BPM : InstantEvent {
|
||||
public override string type { get { return "BPM"; } }
|
||||
public double bpm;
|
||||
}
|
||||
public class System : InstantEvent {
|
||||
public override string type { get { return "System"; } }
|
||||
public string data;
|
||||
}
|
||||
public abstract class SingleBase : InstantEvent {
|
||||
public double lane;
|
||||
public bool skill;
|
||||
public bool flick;
|
||||
}
|
||||
public class Single : SingleBase {
|
||||
public override string type { get { return "Single"; } }
|
||||
}
|
||||
public class Directional : SingleBase {
|
||||
public override string type { get { return "Directional"; } }
|
||||
public string direction;
|
||||
public int width;
|
||||
}
|
||||
public class Connection : SingleBase {
|
||||
public override string type { get { return null; } }
|
||||
public bool hidden;
|
||||
}
|
||||
public class Long : BestdoriChartEvent {
|
||||
public override string type { get { return "Long"; } }
|
||||
public List<Connection> connections;
|
||||
public override double StartBeat { get { return connections[0].beat; } }
|
||||
}
|
||||
public class Slide : Long {
|
||||
public override string type { get { return "Slide"; } }
|
||||
}
|
||||
}
|
||||
#pragma warning restore IDE1006
|
||||
class BestdoriChartEventCreator : CustomCreationConverter<BestdoriChartEvent> {
|
||||
string _currentType;
|
||||
class BestdoriChartEventCreator : CustomCreationConverter<BestdoriChartEvent> {
|
||||
string _currentType;
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
|
||||
var obj = JObject.ReadFrom(reader);
|
||||
var type = obj["type"];
|
||||
if (type == null) _currentType = null;
|
||||
else _currentType = obj["type"].ToObject<string>();
|
||||
return base.ReadJson(obj.CreateReader(), objectType, existingValue, serializer);
|
||||
}
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
|
||||
var obj = JObject.ReadFrom(reader);
|
||||
var type = obj["type"];
|
||||
if (type == null) _currentType = null;
|
||||
else _currentType = obj["type"].ToObject<string>();
|
||||
return base.ReadJson(obj.CreateReader(), objectType, existingValue, serializer);
|
||||
}
|
||||
|
||||
public override BestdoriChartEvent Create(Type objectType) {
|
||||
switch (_currentType) {
|
||||
case "BPM": return new BestdoriChartEvent.BPM();
|
||||
case "System": return new BestdoriChartEvent.System();
|
||||
case "Single": return new BestdoriChartEvent.Single();
|
||||
case "Directional": return new BestdoriChartEvent.Directional();
|
||||
case null: return new BestdoriChartEvent.Connection();
|
||||
case "Long": return new BestdoriChartEvent.Long();
|
||||
case "Slide": return new BestdoriChartEvent.Slide();
|
||||
default: throw new ArgumentException("Unknown event type: " + _currentType);
|
||||
public override BestdoriChartEvent Create(Type objectType) {
|
||||
switch (_currentType) {
|
||||
case "BPM": return new BestdoriChartEvent.BPM();
|
||||
case "System": return new BestdoriChartEvent.System();
|
||||
case "Single": return new BestdoriChartEvent.Single();
|
||||
case "Directional": return new BestdoriChartEvent.Directional();
|
||||
case null: return new BestdoriChartEvent.Connection();
|
||||
case "Long": return new BestdoriChartEvent.Long();
|
||||
case "Slide": return new BestdoriChartEvent.Slide();
|
||||
default: throw new ArgumentException("Unknown event type: " + _currentType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
27
Assets/Cryville/Crtr/Extensions/Extensions.cs
Normal file
27
Assets/Cryville/Crtr/Extensions/Extensions.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using Cryville.Crtr.Browsing;
|
||||
using Cryville.Crtr.Extensions.Bestdori;
|
||||
using Cryville.Crtr.Extensions.Malody;
|
||||
using Cryville.Crtr.Extensions.osu;
|
||||
using Cryville.Crtr.Extensions.Quaver;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Cryville.Crtr.Extensions {
|
||||
public class Extensions : ExtensionInterface {
|
||||
public override IEnumerable<ResourceConverter> GetResourceConverters() {
|
||||
return new ResourceConverter[] {
|
||||
new BestdoriChartConverter(),
|
||||
new MalodyChartConverter(),
|
||||
new osuChartConverter(),
|
||||
new QuaverChartConverter(),
|
||||
};
|
||||
}
|
||||
|
||||
public override IEnumerable<LocalResourceFinder> GetResourceFinders() {
|
||||
return new LocalResourceFinder[] {
|
||||
new MalodyChartFinder(),
|
||||
new osuChartFinder(),
|
||||
new QuaverChartFinder(),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,8 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 62489f8e495a805478e5b45c0f53ca4e
|
||||
timeCreated: 1623583546
|
||||
licenseType: Pro
|
||||
guid: 23377bf2926d93a4b8e3f3ab6040c7f2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
@@ -23,7 +23,6 @@ namespace Cryville.Crtr.Extensions.Malody {
|
||||
src = JsonConvert.DeserializeObject<MalodyChart>(reader.ReadToEnd());
|
||||
}
|
||||
if (src.meta.mode != 0) throw new NotImplementedException("The chart mode is not supported");
|
||||
if (src.meta.mode_ext.column != 4) throw new NotImplementedException("The key count is not supported");
|
||||
|
||||
var ruleset = "malody!" + MODES[src.meta.mode];
|
||||
if (src.meta.mode == 0) {
|
||||
@@ -74,31 +73,29 @@ namespace Cryville.Crtr.Extensions.Malody {
|
||||
Dictionary<MalodyChart.IEvent, StartEventState> longEvents
|
||||
= new Dictionary<MalodyChart.IEvent, StartEventState>();
|
||||
|
||||
float? baseBpm = null, cbpm = null;
|
||||
float pbeat = 0f, ctime = 0f;
|
||||
int[] endbeat = new int[] { 0, 0, 1 };
|
||||
float? baseBpm = null;
|
||||
var tm = new FractionalBeatTimeTimingModel();
|
||||
foreach (var ev in events) {
|
||||
float cbeat = ConvertBeat(ev.beat);
|
||||
ctime += cbpm == null ? 0 : (cbeat - pbeat) / cbpm.Value * 60f;
|
||||
pbeat = cbeat;
|
||||
var beat = new BeatTime(ev.beat[0], ev.beat[1], ev.beat[2]);
|
||||
tm.ForwardTo(beat);
|
||||
if (ev is MalodyChart.Time) {
|
||||
var tev = (MalodyChart.Time)ev;
|
||||
if (baseBpm == null) baseBpm = tev.bpm;
|
||||
cbpm = tev.bpm;
|
||||
tm.BPM = tev.bpm;
|
||||
chart.sigs.Add(new Chart.Signature {
|
||||
time = new BeatTime(ev.beat[0], ev.beat[1], ev.beat[2]),
|
||||
time = beat,
|
||||
tempo = tev.bpm,
|
||||
});
|
||||
chart.motions.Add(new Chart.Motion {
|
||||
time = new BeatTime(ev.beat[0], ev.beat[1], ev.beat[2]),
|
||||
motion = "svm:" + (tev.bpm / baseBpm).ToString()
|
||||
time = beat,
|
||||
motion = "svm:" + (tev.bpm / baseBpm.Value).ToString(CultureInfo.InvariantCulture)
|
||||
});
|
||||
}
|
||||
else if (ev is MalodyChart.Effect) {
|
||||
var tev = (MalodyChart.Effect)ev;
|
||||
if (tev.scroll != null) group.motions.Add(new Chart.Motion {
|
||||
time = new BeatTime(ev.beat[0], ev.beat[1], ev.beat[2]),
|
||||
motion = "svm:" + tev.scroll.ToString()
|
||||
time = beat,
|
||||
motion = "svm:" + tev.scroll.Value.ToString(CultureInfo.InvariantCulture)
|
||||
});
|
||||
}
|
||||
else if (ev is MalodyChart.Note) {
|
||||
@@ -116,19 +113,17 @@ namespace Cryville.Crtr.Extensions.Malody {
|
||||
else throw new NotImplementedException();
|
||||
}
|
||||
else {
|
||||
if (ConvertBeat(tev.beat) > ConvertBeat(endbeat)) endbeat = tev.beat;
|
||||
var rn = new Chart.Note() {
|
||||
time = new BeatTime(tev.beat[0], tev.beat[1], tev.beat[2]),
|
||||
time = beat,
|
||||
motions = new List<Chart.Motion> {
|
||||
new Chart.Motion() { motion = "track:" + tev.column.ToString() }
|
||||
new Chart.Motion() { motion = "track:" + tev.column.ToString(CultureInfo.InvariantCulture) }
|
||||
},
|
||||
};
|
||||
if (tev.endbeat != null) {
|
||||
if (ConvertBeat(tev.endbeat) > ConvertBeat(endbeat)) endbeat = tev.endbeat;
|
||||
rn.endtime = new BeatTime(tev.endbeat[0], tev.endbeat[1], tev.endbeat[2]);
|
||||
longEvents.Add(ev, new StartEventState {
|
||||
Destination = rn,
|
||||
Time = ctime,
|
||||
Time = tm.Time,
|
||||
});
|
||||
}
|
||||
group.notes.Add(rn);
|
||||
@@ -144,8 +139,10 @@ namespace Cryville.Crtr.Extensions.Malody {
|
||||
}
|
||||
else throw new NotSupportedException();
|
||||
}
|
||||
chart.endtime = new BeatTime(endbeat[0] + 4, endbeat[1], endbeat[2]);
|
||||
meta.length = ctime;
|
||||
var endbeat = tm.FractionalBeatTime;
|
||||
endbeat.b += 4;
|
||||
chart.endtime = endbeat;
|
||||
meta.length = (float)tm.Time;
|
||||
meta.note_count = group.notes.Count;
|
||||
string chartName = string.Format("{0} - {1}", meta.song.name, meta.name);
|
||||
if (src.meta.background != null) {
|
||||
@@ -156,77 +153,73 @@ namespace Cryville.Crtr.Extensions.Malody {
|
||||
}
|
||||
|
||||
struct StartEventState {
|
||||
public float Time { get; set; }
|
||||
public double Time { get; set; }
|
||||
public ChartEvent Destination { get; set; }
|
||||
}
|
||||
|
||||
float ConvertBeat(int[] beat) {
|
||||
return beat[0] + (float)beat[1] / beat[2];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma warning disable IDE1006
|
||||
struct MalodyChart {
|
||||
public interface IEvent {
|
||||
int[] beat { get; set; }
|
||||
int[] endbeat { get; set; }
|
||||
int Priority { get; }
|
||||
}
|
||||
public struct EndEvent : IEvent {
|
||||
public int[] beat { get; set; }
|
||||
public int[] endbeat { get; set; }
|
||||
public IEvent StartEvent { get; set; }
|
||||
public int Priority { get { return StartEvent.Priority - 1; } }
|
||||
}
|
||||
|
||||
public Meta meta;
|
||||
public struct Meta {
|
||||
public SongInfo song;
|
||||
public struct SongInfo {
|
||||
public string title;
|
||||
public string artist;
|
||||
public string titleorg;
|
||||
public string artistorg;
|
||||
struct MalodyChart {
|
||||
public interface IEvent {
|
||||
int[] beat { get; set; }
|
||||
int[] endbeat { get; set; }
|
||||
int Priority { get; }
|
||||
}
|
||||
public struct EndEvent : IEvent {
|
||||
public int[] beat { get; set; }
|
||||
public int[] endbeat { get; set; }
|
||||
public IEvent StartEvent { get; set; }
|
||||
public int Priority { get { return StartEvent.Priority - 1; } }
|
||||
}
|
||||
|
||||
public string background;
|
||||
public Meta meta;
|
||||
public struct Meta {
|
||||
public SongInfo song;
|
||||
public struct SongInfo {
|
||||
public string title;
|
||||
public string artist;
|
||||
public string titleorg;
|
||||
public string artistorg;
|
||||
}
|
||||
|
||||
public string creator;
|
||||
public string version;
|
||||
public string background;
|
||||
|
||||
public int mode;
|
||||
public ModeExt mode_ext;
|
||||
public struct ModeExt {
|
||||
public string creator;
|
||||
public string version;
|
||||
|
||||
public int mode;
|
||||
public ModeExt mode_ext;
|
||||
public struct ModeExt {
|
||||
public int column;
|
||||
}
|
||||
}
|
||||
|
||||
public List<Time> time;
|
||||
public struct Time : IEvent {
|
||||
public int[] beat { get; set; }
|
||||
public int[] endbeat { get; set; }
|
||||
public float bpm;
|
||||
public int Priority { get { return -2; } }
|
||||
}
|
||||
|
||||
public List<Effect> effect;
|
||||
public struct Effect : IEvent {
|
||||
public int[] beat { get; set; }
|
||||
public int[] endbeat { get; set; }
|
||||
public float? scroll;
|
||||
public int Priority { get { return 0; } }
|
||||
}
|
||||
|
||||
public List<Note> note;
|
||||
public struct Note : IEvent {
|
||||
public int[] beat { get; set; }
|
||||
public int[] endbeat { get; set; }
|
||||
public int column;
|
||||
public string sound;
|
||||
public int offset;
|
||||
public int type;
|
||||
public int Priority { get { return 0; } }
|
||||
}
|
||||
}
|
||||
|
||||
public List<Time> time;
|
||||
public struct Time : IEvent {
|
||||
public int[] beat { get; set; }
|
||||
public int[] endbeat { get; set; }
|
||||
public float bpm;
|
||||
public int Priority { get { return -2; } }
|
||||
}
|
||||
|
||||
public List<Effect> effect;
|
||||
public struct Effect : IEvent {
|
||||
public int[] beat { get; set; }
|
||||
public int[] endbeat { get; set; }
|
||||
public float? scroll;
|
||||
public int Priority { get { return 0; } }
|
||||
}
|
||||
|
||||
public List<Note> note;
|
||||
public struct Note : IEvent {
|
||||
public int[] beat { get; set; }
|
||||
public int[] endbeat { get; set; }
|
||||
public int column;
|
||||
public string sound;
|
||||
public int offset;
|
||||
public int type;
|
||||
public int Priority { get { return 0; } }
|
||||
}
|
||||
}
|
||||
#pragma warning restore IDE1006
|
||||
}
|
||||
}
|
||||
|
26
Assets/Cryville/Crtr/Extensions/Malody/MalodyChartFinder.cs
Normal file
26
Assets/Cryville/Crtr/Extensions/Malody/MalodyChartFinder.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using Cryville.Common;
|
||||
using Cryville.Crtr.Browsing;
|
||||
using Microsoft.Win32;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Cryville.Crtr.Extensions.Malody {
|
||||
public class MalodyChartFinder : LocalResourceFinder {
|
||||
public override string Name { get { return "Malody beatmaps"; } }
|
||||
|
||||
public override string GetRootPath() {
|
||||
switch (Environment.OSVersion.Platform) {
|
||||
case PlatformID.Unix:
|
||||
return "/storage/emulated/0/data/malody/beatmap";
|
||||
case PlatformID.Win32NT:
|
||||
var reg = Registry.ClassesRoot.OpenSubKey(@"malody\Shell\Open\Command");
|
||||
if (reg == null) return null;
|
||||
var pathObj = reg.GetValue(null);
|
||||
if (pathObj == null) return null;
|
||||
var path = (string)pathObj;
|
||||
return Path.Combine(new FileInfo(StringUtils.GetProcessPathFromCommand(path)).Directory.FullName, "beatmap");
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,8 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 58e01e1e11af164408a19c1086709bd7
|
||||
timeCreated: 1638411495
|
||||
licenseType: Free
|
||||
guid: 3c9beaff62143a2468e18ad4642232c0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
@@ -1,9 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ef3100799cf39eb4d8585dcfba2529a5
|
||||
guid: 6823ead66b33bc048bbad48719feb25d
|
||||
folderAsset: yes
|
||||
timeCreated: 1623583530
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
153
Assets/Cryville/Crtr/Extensions/Quaver/QuaverChartConverter.cs
Normal file
153
Assets/Cryville/Crtr/Extensions/Quaver/QuaverChartConverter.cs
Normal file
@@ -0,0 +1,153 @@
|
||||
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);
|
||||
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;
|
||||
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; } }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b073cac7ce0d41a4f8ca589845678aa2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
24
Assets/Cryville/Crtr/Extensions/Quaver/QuaverChartFinder.cs
Normal file
24
Assets/Cryville/Crtr/Extensions/Quaver/QuaverChartFinder.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using Cryville.Common;
|
||||
using Cryville.Crtr.Browsing;
|
||||
using Microsoft.Win32;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Cryville.Crtr.Extensions.Quaver {
|
||||
public class QuaverChartFinder : LocalResourceFinder {
|
||||
public override string Name { get { return "Quaver beatmaps"; } }
|
||||
|
||||
public override string GetRootPath() {
|
||||
switch (Environment.OSVersion.Platform) {
|
||||
case PlatformID.Win32NT:
|
||||
var reg = Registry.ClassesRoot.OpenSubKey(@"quaver\Shell\Open\Command");
|
||||
if (reg == null) return null;
|
||||
var pathObj = reg.GetValue(null);
|
||||
if (pathObj == null) return null;
|
||||
var path = (string)pathObj;
|
||||
return Path.Combine(new FileInfo(StringUtils.GetProcessPathFromCommand(path)).Directory.FullName, "Songs");
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 68bacf7746cbeea42a78a7d55cfdbea0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
56
Assets/Cryville/Crtr/Extensions/TimingModel.cs
Normal file
56
Assets/Cryville/Crtr/Extensions/TimingModel.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using Cryville.Common.Math;
|
||||
using System;
|
||||
|
||||
namespace Cryville.Crtr.Extensions {
|
||||
public abstract class TimingModel {
|
||||
public double Time { get; protected set; }
|
||||
public double BeatTime { get; protected set; }
|
||||
public BeatTime FractionalBeatTime { get; protected set; }
|
||||
double m_bpm;
|
||||
public double BPM { get { return m_bpm; } set { m_bpm = value; } }
|
||||
public double BeatLength { get { return 60 / m_bpm; } set { m_bpm = 60 / value; } }
|
||||
public TimingModel(double offset) {
|
||||
Time = offset;
|
||||
FractionalBeatTime = new BeatTime(0, 0, 1);
|
||||
}
|
||||
}
|
||||
public class FractionalBeatTimeTimingModel : TimingModel {
|
||||
public FractionalBeatTimeTimingModel(double offset = 0) : base(offset) { }
|
||||
public void ForwardTo(BeatTime t) {
|
||||
if (t == FractionalBeatTime) return;
|
||||
if (BPM == 0) throw new InvalidOperationException("BPM not determined");
|
||||
FractionalBeatTime = t;
|
||||
var nt = t.Decimal;
|
||||
Time += (nt - BeatTime) / BPM * 60;
|
||||
BeatTime = nt;
|
||||
}
|
||||
}
|
||||
public class BeatTimeTimingModel : TimingModel {
|
||||
public BeatTimeTimingModel(double offset = 0) : base(offset) { }
|
||||
public void ForwardTo(double t) {
|
||||
if (t == BeatTime) return;
|
||||
if (BPM == 0) throw new InvalidOperationException("BPM not determined");
|
||||
Time += (t - BeatTime) / BPM * 60;
|
||||
BeatTime = t;
|
||||
FractionalBeatTime = ToBeatTime(t);
|
||||
}
|
||||
static BeatTime ToBeatTime(double beat, double error = 1e-4) {
|
||||
int i, n, d;
|
||||
FractionUtils.ToFraction(beat, error, out n, out d);
|
||||
i = n / d; n %= d;
|
||||
return new BeatTime(i, n, d);
|
||||
}
|
||||
}
|
||||
public class TimeTimingModel : TimingModel {
|
||||
public TimeTimingModel(double offset = 0) : base(offset) { }
|
||||
public void ForwardTo(double t) {
|
||||
if (t == Time) return;
|
||||
if (BPM == 0) throw new InvalidOperationException("BPM not determined");
|
||||
BeatTime += (t - Time) * BPM / 60;
|
||||
int n, d;
|
||||
FractionUtils.ToFraction(BeatTime, 1f / 48 / BPM * 60, out n, out d);
|
||||
FractionalBeatTime = new BeatTime(n, d);
|
||||
Time = t;
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Cryville/Crtr/Extensions/TimingModel.cs.meta
Normal file
11
Assets/Cryville/Crtr/Extensions/TimingModel.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5c4a1fab8f53dd742ba6501d682eb7f6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -1,9 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dc2947c139e087f43b375d2510a449df
|
||||
guid: dbc046e7cabacbb4fbf74520399a7340
|
||||
folderAsset: yes
|
||||
timeCreated: 1621384032
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
373
Assets/Cryville/Crtr/Extensions/osu/osuChartConverter.cs
Normal file
373
Assets/Cryville/Crtr/Extensions/osu/osuChartConverter.cs
Normal file
@@ -0,0 +1,373 @@
|
||||
using Cryville.Crtr.Browsing;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Cryville.Crtr.Extensions.osu {
|
||||
#pragma warning disable IDE1006
|
||||
public class osuChartConverter : ResourceConverter {
|
||||
#pragma warning restore IDE1006
|
||||
static readonly string[] SUPPORTED_FORMATS = { ".osu" };
|
||||
const double OFFSET = 0.07;
|
||||
|
||||
public override string[] GetSupportedFormats() {
|
||||
return SUPPORTED_FORMATS;
|
||||
}
|
||||
|
||||
public override IEnumerable<Resource> ConvertFrom(FileInfo file) {
|
||||
List<Resource> result = new List<Resource>();
|
||||
var meta = new ChartMeta { song = new SongMetaInfo() };
|
||||
var group = new Chart.Group() {
|
||||
tracks = new List<Chart.Track>(),
|
||||
notes = new List<Chart.Note>(),
|
||||
motions = new List<Chart.Motion>(),
|
||||
};
|
||||
var chart = new Chart {
|
||||
format = 2,
|
||||
time = new BeatTime(-4, 0, 1),
|
||||
sigs = new List<Chart.Signature>(),
|
||||
sounds = new List<Chart.Sound>(),
|
||||
motions = new List<Chart.Motion>(),
|
||||
groups = new List<Chart.Group> { group },
|
||||
};
|
||||
var diff = new DifficultyInfo();
|
||||
var evs = new List<osuEvent>();
|
||||
|
||||
using (var reader = new StreamReader(file.FullName, Encoding.UTF8)) {
|
||||
Section section = Section.General;
|
||||
int version;
|
||||
bool flag = false;
|
||||
string line;
|
||||
while ((line = reader.ReadLine()) != null) {
|
||||
if (!flag) {
|
||||
if (line.StartsWith("osu file format v")) {
|
||||
version = int.Parse(line.Substring(17), CultureInfo.InvariantCulture);
|
||||
if (version > 14) throw new NotSupportedException("osu! chart format version too high");
|
||||
else if (version < 5) throw new NotSupportedException("osu! chart format version too low"); // TODO apply offset
|
||||
}
|
||||
else throw new NotSupportedException("Unrecognized osu! chart format");
|
||||
flag = true;
|
||||
}
|
||||
if (ShouldSkipLine(line)) continue;
|
||||
if (section != Section.Metadata) line = StripComments(line);
|
||||
line = line.TrimEnd();
|
||||
if (line.StartsWith('[') && line.EndsWith(']')) {
|
||||
Enum.TryParse(line.Substring(1, line.Length - 2), out section);
|
||||
continue;
|
||||
}
|
||||
ParseLine(meta, chart, diff, evs, section, line);
|
||||
}
|
||||
}
|
||||
|
||||
result.Add(new RawChartResource(string.Format("{0} - {1}", meta.song.name, meta.name), chart, meta));
|
||||
var evc = evs.Count;
|
||||
for (int i = 0; i < evc; i++) if (evs[i].IsLong) evs.Add(new osuEvent.EndEvent(evs[i]));
|
||||
evs.Sort();
|
||||
|
||||
var longevs = new Dictionary<osuEvent, ChartEvent>();
|
||||
Chart.Sound bgmEv = null;
|
||||
TimeTimingModel tm = null;
|
||||
foreach (var ev in evs) {
|
||||
if (tm != null) tm.ForwardTo(ev.StartTime / 1e3);
|
||||
if (ev is osuEvent.Audio) {
|
||||
var tev = (osuEvent.Audio)ev;
|
||||
chart.sounds.Add(bgmEv = new Chart.Sound { time = new BeatTime(0, 0, 1), id = meta.song.name });
|
||||
result.Add(new SongResource(meta.song.name, new FileInfo(Path.Combine(file.DirectoryName, tev.AudioFile))));
|
||||
}
|
||||
else if (ev is osuEvent.Background) {
|
||||
meta.cover = ((osuEvent.Background)ev).FileName;
|
||||
}
|
||||
else if (ev is osuEvent.EffectPoint) {
|
||||
var tev = (osuEvent.EffectPoint)ev;
|
||||
group.motions.Add(new Chart.Motion { motion = string.Format(CultureInfo.InvariantCulture, "svm:{0}", tev.ScrollSpeed) });
|
||||
}
|
||||
else if (ev is osuEvent.EndEvent) {
|
||||
if (tm == null) throw new InvalidOperationException("Unconvertible chart: timed event before first timing point");
|
||||
var tev = (osuEvent.EndEvent)ev;
|
||||
longevs[tev.Original].endtime = tm.FractionalBeatTime;
|
||||
}
|
||||
else if (ev is osuEvent.HOMania) {
|
||||
if (tm == null) throw new InvalidOperationException("Unconvertible chart: timed event before first timing point");
|
||||
var tev = (osuEvent.HOMania)ev;
|
||||
var rn = new Chart.Note {
|
||||
time = tm.FractionalBeatTime,
|
||||
motions = new List<Chart.Motion> {
|
||||
new Chart.Motion{ motion = string.Format(CultureInfo.InvariantCulture, "track:{0}", (int)(tev.X * diff.CircleSize / 512)) }
|
||||
},
|
||||
};
|
||||
group.notes.Add(rn);
|
||||
if (tev.IsLong) longevs.Add(tev, rn);
|
||||
}
|
||||
else if (ev is osuEvent.TimingChange) {
|
||||
var tev = (osuEvent.TimingChange)ev;
|
||||
if (tm == null) {
|
||||
tm = new TimeTimingModel(tev.StartTime / 1e3);
|
||||
bgmEv.offset = (float)(tev.StartTime / 1e3 + OFFSET);
|
||||
}
|
||||
tm.BeatLength = tev.BeatLength / 1e3;
|
||||
chart.sigs.Add(new Chart.Signature {
|
||||
time = tm.FractionalBeatTime,
|
||||
tempo = (float)tm.BPM,
|
||||
});
|
||||
}
|
||||
else throw new NotSupportedException("Unsupported event detected");
|
||||
}
|
||||
var endbeat = tm.FractionalBeatTime;
|
||||
endbeat.b += 4;
|
||||
chart.endtime = endbeat;
|
||||
meta.length = (float)tm.Time;
|
||||
meta.note_count = group.notes.Count;
|
||||
return result;
|
||||
}
|
||||
|
||||
void ParseLine(ChartMeta meta, Chart chart, DifficultyInfo diff, List<osuEvent> evs, Section section, string line) {
|
||||
switch (section) {
|
||||
case Section.General: HandleGeneral(meta, chart, evs, line); return;
|
||||
case Section.Metadata: HandleMetadata(meta, line); return;
|
||||
case Section.Difficulty: HandleDifficulty(diff, line); return;
|
||||
case Section.Events: HandleEvent(evs, line); return;
|
||||
case Section.TimingPoints: HandleTimingPoint(chart, evs, line); return;
|
||||
case Section.HitObjects: HandleHitObject(evs, line); return;
|
||||
}
|
||||
}
|
||||
|
||||
void HandleGeneral(ChartMeta meta, Chart chart, List<osuEvent> evs, string line) {
|
||||
var pair = SplitKeyVal(line);
|
||||
switch (pair.Key) {
|
||||
case @"AudioFilename":
|
||||
evs.Add(new osuEvent.Audio { StartTime = double.NegativeInfinity, AudioFile = pair.Value });
|
||||
break;
|
||||
case @"Mode":
|
||||
int rulesetID = int.Parse(pair.Value, CultureInfo.InvariantCulture);
|
||||
var ruleset = "osu!";
|
||||
switch (rulesetID) {
|
||||
case 0: /*ruleset += "standard";*/ throw new NotSupportedException("osu!standard mode is not supported yet");
|
||||
case 1: /*ruleset += "taiko";*/ throw new NotSupportedException("osu!taiko mode is not supported yet");
|
||||
case 2: /*ruleset += "catch";*/ throw new NotSupportedException("osu!catch mode is not supported yet");
|
||||
case 3: ruleset += "mania"; break;
|
||||
}
|
||||
meta.ruleset = chart.ruleset = ruleset;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void HandleMetadata(ChartMeta meta, string line) {
|
||||
var pair = SplitKeyVal(line);
|
||||
switch (pair.Key) {
|
||||
case @"Title": if (meta.song.name == null) meta.song.name = pair.Value; break;
|
||||
case @"TitleUnicode": meta.song.name = pair.Value; break;
|
||||
case @"Artist": if (meta.song.author == null) meta.song.author = pair.Value; break;
|
||||
case @"ArtistUnicode": meta.song.author = pair.Value; break;
|
||||
case @"Creator": meta.author = pair.Value; break;
|
||||
case @"Version": meta.name = pair.Value; break;
|
||||
}
|
||||
}
|
||||
|
||||
void HandleDifficulty(DifficultyInfo diff, string line) {
|
||||
var pair = SplitKeyVal(line);
|
||||
switch (pair.Key) {
|
||||
case @"CircleSize":
|
||||
diff.CircleSize = float.Parse(pair.Value, CultureInfo.InvariantCulture);
|
||||
break;
|
||||
case @"SliderMultiplier":
|
||||
diff.SliderMultiplier = double.Parse(pair.Value, CultureInfo.InvariantCulture);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void HandleEvent(List<osuEvent> evs, string line) {
|
||||
string[] split = line.Split(',');
|
||||
if (!Enum.TryParse(split[0], out LegacyEventType type))
|
||||
throw new InvalidDataException($@"Unknown event type: {split[0]}");
|
||||
switch (type) {
|
||||
case LegacyEventType.Sprite:
|
||||
if (evs.Count == 0 || !(evs[evs.Count - 1] is osuEvent.Background))
|
||||
evs.Add(new osuEvent.Background { StartTime = double.NegativeInfinity, FileName = CleanFilename(split[3]) });
|
||||
break;
|
||||
case LegacyEventType.Background:
|
||||
evs.Add(new osuEvent.Background { StartTime = double.NegativeInfinity, FileName = CleanFilename(split[2]) });
|
||||
break;
|
||||
}
|
||||
}
|
||||
enum LegacyEventType {
|
||||
Background = 0,
|
||||
Video = 1,
|
||||
Break = 2,
|
||||
Colour = 3,
|
||||
Sprite = 4,
|
||||
Sample = 5,
|
||||
Animation = 6
|
||||
}
|
||||
|
||||
void HandleTimingPoint(Chart chart, List<osuEvent> evs, string line) {
|
||||
string[] split = line.Split(',');
|
||||
|
||||
double time = double.Parse(split[0].Trim(), CultureInfo.InvariantCulture)/* + offset*/;
|
||||
|
||||
// beatLength is allowed to be NaN to handle an edge case in which some beatmaps use NaN slider velocity to disable slider tick generation (see LegacyDifficultyControlPoint).
|
||||
double beatLength = double.Parse(split[1].Trim(), CultureInfo.InvariantCulture);
|
||||
|
||||
// If beatLength is NaN, speedMultiplier should still be 1 because all comparisons against NaN are false.
|
||||
double speedMultiplier = beatLength < 0 ? 100.0 / -beatLength : 1;
|
||||
|
||||
int timeSignature = 4;
|
||||
if (split.Length >= 3)
|
||||
timeSignature = split[2][0] == '0' ? 4 : int.Parse(split[2], CultureInfo.InvariantCulture);
|
||||
|
||||
bool timingChange = true;
|
||||
if (split.Length >= 7)
|
||||
timingChange = split[6][0] == '1';
|
||||
|
||||
//bool omitFirstBarSignature = false;
|
||||
|
||||
//if (split.Length >= 8) {
|
||||
// int effectFlags = int.Parse(split[7], CultureInfo.InvariantCulture);
|
||||
// omitFirstBarSignature = (effectFlags & 0x8) != 0;
|
||||
//}
|
||||
|
||||
if (timingChange) {
|
||||
if (double.IsNaN(beatLength))
|
||||
throw new InvalidDataException("Beat length cannot be NaN in a timing control point");
|
||||
evs.Add(new osuEvent.TimingChange { StartTime = time, BeatLength = beatLength, TimeSignature = timeSignature });
|
||||
}
|
||||
|
||||
// osu!taiko and osu!mania use effect points rather than difficulty points for scroll speed adjustments.
|
||||
if (chart.ruleset == "osu!taiko" || chart.ruleset == "osu!mania")
|
||||
evs.Add(new osuEvent.EffectPoint { StartTime = time, ScrollSpeed = speedMultiplier });
|
||||
}
|
||||
|
||||
void HandleHitObject(List<osuEvent> evs, string line) {
|
||||
string[] split = line.Split(',');
|
||||
|
||||
int posx = (int)float.Parse(split[0], CultureInfo.InvariantCulture);
|
||||
// int posy = (int)float.Parse(split[1], CultureInfo.InvariantCulture);
|
||||
|
||||
double startTime = double.Parse(split[2], CultureInfo.InvariantCulture)/* + Offset*/;
|
||||
|
||||
LegacyHitObjectType type = (LegacyHitObjectType)int.Parse(split[3], CultureInfo.InvariantCulture);
|
||||
|
||||
// int comboOffset = (int)(type & LegacyHitObjectType.ComboOffset) >> 4;
|
||||
type &= ~LegacyHitObjectType.ComboOffset;
|
||||
|
||||
// bool combo = type.HasFlag(LegacyHitObjectType.NewCombo);
|
||||
type &= ~LegacyHitObjectType.NewCombo;
|
||||
|
||||
osuEvent.HitObject result;
|
||||
|
||||
if (type.HasFlag(LegacyHitObjectType.Circle)) {
|
||||
result = new osuEvent.HOManiaHit { X = posx };
|
||||
}
|
||||
else if (type.HasFlag(LegacyHitObjectType.Hold)) {
|
||||
double endTime = Math.Max(startTime, double.Parse(split[2], CultureInfo.InvariantCulture));
|
||||
if (split.Length > 5 && !string.IsNullOrEmpty(split[5])) {
|
||||
string[] ss = split[5].Split(':');
|
||||
endTime = Math.Max(startTime, double.Parse(ss[0], CultureInfo.InvariantCulture));
|
||||
}
|
||||
result = new osuEvent.HOManiaHold { X = posx, EndTime = endTime };
|
||||
}
|
||||
else throw new NotSupportedException(string.Format("Hit objects of type {0} is not supported yet", type));
|
||||
|
||||
if (result == null) throw new InvalidDataException($"Unknown hit object type: {split[3]}");
|
||||
|
||||
result.StartTime = startTime;
|
||||
|
||||
if (result != null) evs.Add(result);
|
||||
}
|
||||
[Flags]
|
||||
enum LegacyHitObjectType {
|
||||
Circle = 1,
|
||||
Slider = 1 << 1,
|
||||
NewCombo = 1 << 2,
|
||||
Spinner = 1 << 3,
|
||||
ComboOffset = (1 << 4) | (1 << 5) | (1 << 6),
|
||||
Hold = 1 << 7
|
||||
}
|
||||
|
||||
static bool ShouldSkipLine(string line) => string.IsNullOrWhiteSpace(line) || line.TrimStart().StartsWith("//", StringComparison.Ordinal)
|
||||
|| line.StartsWith(' ') || line.StartsWith('_');
|
||||
protected string StripComments(string line) {
|
||||
int index = line.IndexOf("//");
|
||||
if (index > 0) return line.Substring(0, index);
|
||||
return line;
|
||||
}
|
||||
KeyValuePair<string, string> SplitKeyVal(string line, char separator = ':', bool shouldTrim = true) {
|
||||
string[] split = line.Split(separator, 2);
|
||||
if (shouldTrim) {
|
||||
for (int i = 0; i < split.Length; i++)
|
||||
split[i] = split[i].Trim();
|
||||
}
|
||||
return new KeyValuePair<string, string> (
|
||||
split[0],
|
||||
split.Length > 1 ? split[1] : string.Empty
|
||||
);
|
||||
}
|
||||
static string CleanFilename(string path) => path.Replace(@"\\", @"\").Trim('"');
|
||||
|
||||
enum Section {
|
||||
General,
|
||||
Editor,
|
||||
Metadata,
|
||||
Difficulty,
|
||||
Events,
|
||||
TimingPoints,
|
||||
Colours,
|
||||
HitObjects,
|
||||
Variables,
|
||||
Fonts,
|
||||
CatchTheBeat,
|
||||
Mania,
|
||||
}
|
||||
|
||||
class DifficultyInfo {
|
||||
public float CircleSize { get; internal set; }
|
||||
public double SliderMultiplier { get; set; }
|
||||
}
|
||||
#pragma warning disable IDE1006 // Naming Styles
|
||||
abstract class osuEvent : IComparable<osuEvent> {
|
||||
public virtual double StartTime { get; set; }
|
||||
public virtual double EndTime { get; set; }
|
||||
public bool IsLong { get { return EndTime - StartTime > 0 && EndTime > 0; } }
|
||||
public abstract int Priority { get; }
|
||||
public int CompareTo(osuEvent other) {
|
||||
var c = StartTime.CompareTo(other.StartTime);
|
||||
if (c != 0) return c;
|
||||
return Priority.CompareTo(other.Priority);
|
||||
}
|
||||
public class EndEvent : osuEvent {
|
||||
public osuEvent Original;
|
||||
public EndEvent(osuEvent ev) { if (!ev.IsLong) throw new ArgumentException("Event is not long"); Original = ev; }
|
||||
public override double StartTime { get { return Original.EndTime; } }
|
||||
public override double EndTime { get { return 0; } }
|
||||
public override int Priority { get { return Original.Priority - 1; } }
|
||||
}
|
||||
public class Audio : osuEvent {
|
||||
public string AudioFile { get; set; }
|
||||
public override int Priority { get { return 0; } }
|
||||
}
|
||||
public class TimingChange : osuEvent {
|
||||
public double BeatLength { get; set; }
|
||||
public int TimeSignature { get; set; }
|
||||
public override int Priority { get { return -4; } }
|
||||
}
|
||||
public class EffectPoint : osuEvent {
|
||||
public double ScrollSpeed { get; set; }
|
||||
public override int Priority { get { return -2; } }
|
||||
}
|
||||
public class Background : osuEvent {
|
||||
public string FileName { get; set; }
|
||||
public override int Priority { get { return 0; } }
|
||||
}
|
||||
public class HitObject : osuEvent {
|
||||
public sealed override int Priority { get { return 0; } }
|
||||
}
|
||||
public class HOMania : HitObject {
|
||||
public float X { get; set; }
|
||||
}
|
||||
public class HOManiaHit : HOMania { }
|
||||
public class HOManiaHold : HOMania { }
|
||||
}
|
||||
#pragma warning restore IDE1006 // Naming Styles
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 82838dd8639c2244caf3c830edfbc59c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
24
Assets/Cryville/Crtr/Extensions/osu/osuChartFinder.cs
Normal file
24
Assets/Cryville/Crtr/Extensions/osu/osuChartFinder.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using Cryville.Common;
|
||||
using Cryville.Crtr.Browsing;
|
||||
using Microsoft.Win32;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Cryville.Crtr.Extensions.osu {
|
||||
public class osuChartFinder : LocalResourceFinder {
|
||||
public override string Name { get { return "osu! beatmaps"; } }
|
||||
|
||||
public override string GetRootPath() {
|
||||
switch (Environment.OSVersion.Platform) {
|
||||
case PlatformID.Win32NT:
|
||||
var reg = Registry.ClassesRoot.OpenSubKey(@"osu!\Shell\Open\Command");
|
||||
if (reg == null) return null;
|
||||
var pathObj = reg.GetValue(null);
|
||||
if (pathObj == null) return null;
|
||||
var path = (string)pathObj;
|
||||
return Path.Combine(new FileInfo(StringUtils.GetProcessPathFromCommand(path)).Directory.FullName, "Songs");
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Cryville/Crtr/Extensions/osu/osuChartFinder.cs.meta
Normal file
11
Assets/Cryville/Crtr/Extensions/osu/osuChartFinder.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 365d879536c05284fa2335a7676c6cf4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -1,7 +1,6 @@
|
||||
using Cryville.Common.Math;
|
||||
using Cryville.Crtr.Event;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
@@ -10,7 +9,7 @@ namespace Cryville.Crtr {
|
||||
public ChartHandler ch;
|
||||
|
||||
SquareMatrix matFrame;
|
||||
List<ContainerState> tracks;
|
||||
ContainerState[] tracks;
|
||||
|
||||
public GroupHandler(Chart.Group tg, ChartHandler ch) : base() {
|
||||
this.ch = ch;
|
||||
@@ -28,20 +27,22 @@ namespace Cryville.Crtr {
|
||||
from c in cs.Children
|
||||
where c.Value.Container is Chart.Track
|
||||
select c.Value
|
||||
).ToList();
|
||||
matFrame = SquareMatrix.WithPolynomialCoefficients(tracks.Count);
|
||||
).ToArray();
|
||||
matFrame = SquareMatrix.WithPolynomialCoefficients(tracks.Length);
|
||||
frame = new ColumnVector<Vector3>(tracks.Length);
|
||||
}
|
||||
|
||||
ColumnVector<Vector3> frame;
|
||||
public ColumnVector<Vector3> GetCurrentFrame(Func<ContainerState, Vector3> func) {
|
||||
var vl = from t in tracks select func(t);
|
||||
return matFrame.Eliminate(
|
||||
new ColumnVector<Vector3>(vl.ToArray()),
|
||||
new Vector3Operator()
|
||||
);
|
||||
for (int i = 0; i < tracks.Length; i++)
|
||||
frame[i] = func(tracks[i]);
|
||||
return matFrame.Eliminate(frame, Vector3Operator.Instance);
|
||||
}
|
||||
}
|
||||
|
||||
class Vector3Operator : IVectorOperator<Vector3> {
|
||||
public static Vector3Operator Instance = new Vector3Operator();
|
||||
|
||||
public Vector3 Add(Vector3 lhs, Vector3 rhs) {
|
||||
return lhs + rhs;
|
||||
}
|
||||
|
@@ -225,7 +225,7 @@ namespace Cryville.Crtr {
|
||||
_etor.ContextCascadeDiscard();
|
||||
if (tv.Type == PdtInternalType.Null) _activeCounts[id.Source]--;
|
||||
}
|
||||
_judge.Cleanup(target, ft, tt);
|
||||
_judge.Cleanup(target, tt);
|
||||
_vecs[pid] = tv;
|
||||
}
|
||||
}
|
||||
|
@@ -17,10 +17,10 @@ namespace Cryville.Crtr {
|
||||
readonly Dictionary<Identifier, List<JudgeEvent>> activeEvs
|
||||
= new Dictionary<Identifier, List<JudgeEvent>>();
|
||||
struct JudgeEvent {
|
||||
public float StartTime { get; set; }
|
||||
public float EndTime { get; set; }
|
||||
public float StartClip { get; set; }
|
||||
public float EndClip { get; set; }
|
||||
public double StartTime { get; set; }
|
||||
public double EndTime { get; set; }
|
||||
public double StartClip { get; set; }
|
||||
public double EndClip { get; set; }
|
||||
public JudgeDefinition Definition { get; set; }
|
||||
public ContainerState State { get; set; }
|
||||
}
|
||||
@@ -35,7 +35,7 @@ namespace Cryville.Crtr {
|
||||
_rs = rs;
|
||||
InitScores();
|
||||
}
|
||||
public void Prepare(float st, float et, Identifier input, JudgeDefinition def, ContainerState container) {
|
||||
public void Prepare(double st, double et, Identifier input, JudgeDefinition def, ContainerState container) {
|
||||
List<JudgeEvent> list;
|
||||
if (!evs.TryGetValue(input, out list)) {
|
||||
ct.Add(input, 0);
|
||||
@@ -89,10 +89,12 @@ namespace Cryville.Crtr {
|
||||
int num3 = num + (num2 - num >> 1);
|
||||
int num4 = -list[num3].Definition.stack.CompareTo(stack);
|
||||
if (num4 == 0) num4 = list[num3].StartClip.CompareTo(time);
|
||||
if (num4 >= 0) num2 = num3 - 1;
|
||||
else num = num3 + 1;
|
||||
if (num4 > 0) num2 = num3 - 1;
|
||||
else if (num4 < 0) num = num3 + 1;
|
||||
else if (num != num3) num2 = num3;
|
||||
else return num;
|
||||
}
|
||||
return num + 1;
|
||||
return ~num;
|
||||
}
|
||||
public void Feed(Identifier target, float ft, float tt) {
|
||||
Forward(target, tt);
|
||||
@@ -103,8 +105,8 @@ namespace Cryville.Crtr {
|
||||
var index = 0;
|
||||
while (index >= 0 && index < actlist.Count) {
|
||||
var ev = actlist[index];
|
||||
LoadNum(_numbuf1, ev.StartTime); _etor.ContextCascadeUpdate(_var_fn, new PropSrc.Arbitrary(PdtInternalType.Number, _numbuf1));
|
||||
LoadNum(_numbuf2, ev.EndTime); _etor.ContextCascadeUpdate(_var_tn, new PropSrc.Arbitrary(PdtInternalType.Number, _numbuf2));
|
||||
LoadNum(_numbuf1, (float)ev.StartTime); _etor.ContextCascadeUpdate(_var_fn, new PropSrc.Arbitrary(PdtInternalType.Number, _numbuf1));
|
||||
LoadNum(_numbuf2, (float)ev.EndTime); _etor.ContextCascadeUpdate(_var_tn, new PropSrc.Arbitrary(PdtInternalType.Number, _numbuf2));
|
||||
var def = ev.Definition;
|
||||
if (def.hit != null) _etor.Evaluate(_flagop, def.hit);
|
||||
else _flag = true;
|
||||
@@ -113,7 +115,7 @@ namespace Cryville.Crtr {
|
||||
if (def.pass != null) Pass(def.pass);
|
||||
actlist.RemoveAt(index);
|
||||
if (def.prop != 0 && actlist.Count > 0) {
|
||||
index = BinarySearchFirst(actlist, ev.StartClip, def.stack - def.prop);
|
||||
index = BinarySearchFirst(actlist, (float)ev.StartClip, def.stack - def.prop);
|
||||
if (index < 0) index = ~index;
|
||||
}
|
||||
else index++;
|
||||
@@ -135,7 +137,7 @@ namespace Cryville.Crtr {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public void Cleanup(Identifier target, float ft, float tt) {
|
||||
public void Cleanup(Identifier target, float tt) {
|
||||
Forward(target, tt);
|
||||
var actlist = activeEvs[target];
|
||||
for (int i = actlist.Count - 1; i >= 0; i--) {
|
||||
@@ -152,7 +154,7 @@ namespace Cryville.Crtr {
|
||||
JudgeEvent ev;
|
||||
while (list.Count > 0 && (ev = list[0]).StartClip <= tt) {
|
||||
list.RemoveAt(0);
|
||||
var index = BinarySearch(actlist, ev.StartClip, ev.Definition.stack);
|
||||
var index = BinarySearch(actlist, (float)ev.StartClip, ev.Definition.stack);
|
||||
if (index < 0) index = ~index;
|
||||
actlist.Insert(index, ev);
|
||||
}
|
||||
|
@@ -41,7 +41,7 @@ namespace Cryville.Crtr {
|
||||
MeshObject.AddComponent<MeshRenderer>();
|
||||
MeshFilter = MeshObject.GetComponent<MeshFilter>();
|
||||
Renderer = MeshObject.GetComponent<Renderer>();
|
||||
Renderer.material = GenericResources.Materials["-SpriteMat"];
|
||||
Renderer.material = NewMaterial;
|
||||
Initialized = true;
|
||||
}
|
||||
public void Destroy() {
|
||||
|
@@ -2,6 +2,7 @@ using Cryville.Common;
|
||||
using Cryville.Common.Pdt;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Text.RegularExpressions;
|
||||
using UnityEngine;
|
||||
|
||||
@@ -22,9 +23,9 @@ namespace Cryville.Crtr {
|
||||
}
|
||||
|
||||
public static class MotionLerper {
|
||||
public static void Lerp<T>(float time, float tt, T tv, float ft, T fv, TransitionType type, float rate, ref T result) where T : Vector {
|
||||
public static void Lerp<T>(double time, double tt, T tv, double ft, T fv, TransitionType type, float rate, ref T result) where T : Vector {
|
||||
if (fv == null) fv = (T)ReflectionHelper.InvokeEmptyConstructor(tv.GetType());
|
||||
Lerp((time - ft) / (tt - ft), fv, tv, type, rate, ref result);
|
||||
Lerp((float)((time - ft) / (tt - ft)), fv, tv, type, rate, ref result);
|
||||
}
|
||||
|
||||
public static void Lerp<T>(float scaledTime, T from, T to, TransitionType type, float rate, ref T result) where T : Vector {
|
||||
@@ -34,7 +35,7 @@ namespace Cryville.Crtr {
|
||||
to.LerpWith(from, GetEaseTime(scaledTime, type, rate), ref r);
|
||||
}
|
||||
|
||||
public static float Delerp<T>(T value, float tt, T tv, float ft, T fv, TransitionType type, float rate) where T : Vector {
|
||||
public static double Delerp<T>(T value, double tt, T tv, double ft, T fv, TransitionType type, float rate) where T : Vector {
|
||||
if (fv == null) fv = (T)ReflectionHelper.InvokeEmptyConstructor(tv.GetType());
|
||||
var t = Delerp(value, fv, tv, type, rate);
|
||||
return ft * (1 - t) + tt * t;
|
||||
@@ -170,6 +171,7 @@ namespace Cryville.Crtr {
|
||||
public class RealtimeMotionValue {
|
||||
public Vector AbsoluteValue;
|
||||
List<MotionNode> RelativeNodes;
|
||||
internal byte CloneTypeFlag;
|
||||
|
||||
public RealtimeMotionValue Init(Vector init) {
|
||||
RelativeNodes = new List<MotionNode> {
|
||||
@@ -433,7 +435,7 @@ namespace Cryville.Crtr {
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return Value.ToString();
|
||||
return Value.ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
public override float[] ToArray() {
|
||||
@@ -493,7 +495,7 @@ namespace Cryville.Crtr {
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return Value.ToString();
|
||||
return Value.ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
public override float[] ToArray() {
|
||||
@@ -553,7 +555,7 @@ namespace Cryville.Crtr {
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return Value.ToString();
|
||||
return Value.ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
public override float[] ToArray() {
|
||||
@@ -648,8 +650,8 @@ namespace Cryville.Crtr {
|
||||
|
||||
public static string ToString(float? w, float? h) {
|
||||
List<string> list = new List<string>();
|
||||
if (w != null) list.Add(w.ToString() + "w");
|
||||
if (h != null) list.Add(h.ToString() + "h");
|
||||
if (w != null) list.Add(w.Value.ToString(CultureInfo.InvariantCulture) + "w");
|
||||
if (h != null) list.Add(h.Value.ToString(CultureInfo.InvariantCulture) + "h");
|
||||
return string.Join("+", list.ToArray());
|
||||
}
|
||||
|
||||
@@ -744,9 +746,9 @@ namespace Cryville.Crtr {
|
||||
|
||||
public override string ToString() {
|
||||
return string.Format("{0},{1},{2}",
|
||||
x != null ? x.ToString() : "",
|
||||
y != null ? y.ToString() : "",
|
||||
z != null ? z.ToString() : ""
|
||||
x != null ? x.Value.ToString(CultureInfo.InvariantCulture) : "",
|
||||
y != null ? y.Value.ToString(CultureInfo.InvariantCulture) : "",
|
||||
z != null ? z.Value.ToString(CultureInfo.InvariantCulture) : ""
|
||||
);
|
||||
}
|
||||
|
||||
@@ -915,7 +917,7 @@ namespace Cryville.Crtr {
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return VecPtComp.ToString(xw, xh) + "," + VecPtComp.ToString(yw, yh) + "," + (z != null ? z.ToString() : "");
|
||||
return VecPtComp.ToString(xw, xh) + "," + VecPtComp.ToString(yw, yh) + "," + (z != null ? z.Value.ToString(CultureInfo.InvariantCulture) : "");
|
||||
}
|
||||
|
||||
public override float[] ToArray() {
|
||||
|
@@ -117,6 +117,7 @@ namespace Cryville.Crtr {
|
||||
return Quaternion.LookRotation(r, state.Normal);
|
||||
}
|
||||
|
||||
List<Vector3> ctrl = new List<Vector3>(2);
|
||||
Vector3 GetFrame(ContainerState state, float track, Func<ContainerState, Vector3> func) {
|
||||
// TODO
|
||||
int id = Mathf.FloorToInt(track);
|
||||
@@ -134,7 +135,7 @@ namespace Cryville.Crtr {
|
||||
if (c0 && c1)
|
||||
return (1 - t) * p1 + t * p2;
|
||||
else {
|
||||
var ctrl = new List<Vector3>(2);
|
||||
ctrl.Clear();
|
||||
if (!c0) {
|
||||
var tp = ts0.GetControlPoint(true, deltaz);
|
||||
if (tp != Vector3.zero) ctrl.Add(tp);
|
||||
@@ -149,7 +150,7 @@ namespace Cryville.Crtr {
|
||||
ColumnVector<float>.WithPolynomialCoefficients(
|
||||
frame.Size, track
|
||||
),
|
||||
new Vector3Operator()
|
||||
Vector3Operator.Instance
|
||||
);
|
||||
}
|
||||
else if (ctrl.Count == 1) {
|
||||
|
@@ -3,6 +3,7 @@ using Cryville.Common.Pdt;
|
||||
using Cryville.Crtr.Event;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Cryville.Crtr {
|
||||
@@ -45,13 +46,13 @@ namespace Cryville.Crtr {
|
||||
}
|
||||
else {
|
||||
type = PdtInternalType.Undefined;
|
||||
LoadNum(name);
|
||||
LoadIdent(name);
|
||||
value = _numbuf;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
unsafe void LoadNum(int value) {
|
||||
unsafe void LoadIdent(int value) {
|
||||
fixed (byte* ptr = _numbuf) *(int*)ptr = value;
|
||||
}
|
||||
unsafe void LoadNum(float value) {
|
||||
@@ -250,7 +251,7 @@ namespace Cryville.Crtr {
|
||||
if (blit) GetReturnFrame(PdtInternalType.Array, len + 2 * sizeof(int)).SetArraySuffix(type, LoadedOperandCount);
|
||||
else GetReturnFrame(PdtInternalType.Vector, len + sizeof(int)).SetArraySuffix(type);
|
||||
}
|
||||
bool IsBlittable(int type) {
|
||||
static bool IsBlittable(int type) {
|
||||
return type == PdtInternalType.Number;
|
||||
}
|
||||
}
|
||||
@@ -298,7 +299,7 @@ namespace Cryville.Crtr {
|
||||
ret.SetArraySuffix(PdtInternalType.String, fc);
|
||||
int o = 0;
|
||||
for (int i = f; i <= t; i++) {
|
||||
var s = pf + i.ToString();
|
||||
var s = pf + i.ToString(CultureInfo.InvariantCulture);
|
||||
ret.SetString(s, o);
|
||||
o += sizeof(int) + s.Length * sizeof(char);
|
||||
}
|
||||
|
@@ -175,6 +175,26 @@ namespace Cryville.Crtr {
|
||||
}
|
||||
}
|
||||
|
||||
[Category("debug")]
|
||||
public bool ClearLogOnPlay {
|
||||
get {
|
||||
return PlayerPrefs.GetInt("ClearLogOnPlay", 1) == 1;
|
||||
}
|
||||
set {
|
||||
PlayerPrefs.SetInt("ClearLogOnPlay", value ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
[Category("debug")]
|
||||
public bool HideLogOnPlay {
|
||||
get {
|
||||
return PlayerPrefs.GetInt("HideLogOnPlay", 1) == 1;
|
||||
}
|
||||
set {
|
||||
PlayerPrefs.SetInt("HideLogOnPlay", value ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
public void Save() { PlayerPrefs.Save(); }
|
||||
public void Reset() { PlayerPrefs.DeleteAll(); }
|
||||
}
|
||||
|
@@ -36,7 +36,7 @@ namespace Cryville.Crtr {
|
||||
}
|
||||
}
|
||||
|
||||
Dictionary<string, List<PropertyInfo>> _categories = new Dictionary<string, List<PropertyInfo>>();
|
||||
readonly Dictionary<string, List<PropertyInfo>> _categories = new Dictionary<string, List<PropertyInfo>>();
|
||||
public void LoadProperties() {
|
||||
_categories.Clear();
|
||||
_invalidated = false;
|
||||
|
@@ -69,7 +69,7 @@ namespace Cryville.Crtr {
|
||||
}
|
||||
public struct SkinPropertyKey {
|
||||
public Type Component;
|
||||
public string Name;
|
||||
public int Name;
|
||||
}
|
||||
public class SkinElementBinder : EmptyBinder {
|
||||
public override object ChangeType(object value, Type type, CultureInfo culture) {
|
||||
@@ -81,9 +81,9 @@ namespace Cryville.Crtr {
|
||||
if (key[0] == '*')
|
||||
return new SkinPropertyKey { Component = GetComponentByName(key.Substring(1)) };
|
||||
else
|
||||
return new SkinPropertyKey { Component = typeof(TransformInterface), Name = key };
|
||||
return new SkinPropertyKey { Component = typeof(TransformInterface), Name = IdentifierManager.SharedInstance.Request(key) };
|
||||
case 2:
|
||||
return new SkinPropertyKey { Component = GetComponentByName(cp[0]), Name = cp[1] };
|
||||
return new SkinPropertyKey { Component = GetComponentByName(cp[0]), Name = IdentifierManager.SharedInstance.Request(cp[1]) };
|
||||
}
|
||||
}
|
||||
return base.ChangeType(value, type, culture);
|
||||
|
@@ -1,4 +1,4 @@
|
||||
using Cryville.Common.Pdt;
|
||||
using Cryville.Common.Pdt;
|
||||
using Cryville.Crtr.Components;
|
||||
using Cryville.Crtr.Event;
|
||||
using System;
|
||||
@@ -35,7 +35,7 @@ namespace Cryville.Crtr {
|
||||
void MatchStatic(SkinElement rel, ContainerState context, Transform anchor = null) {
|
||||
ChartPlayer.etor.ContextTransform = anchor;
|
||||
foreach (var p in rel.properties) {
|
||||
if (p.Key.Name == null)
|
||||
if (p.Key.Name == 0)
|
||||
anchor.gameObject.AddComponent(p.Key.Component);
|
||||
else {
|
||||
ChartPlayer.etor.Evaluate(GetPropOp(anchor, p.Key).Operator, p.Value);
|
||||
@@ -82,7 +82,7 @@ namespace Cryville.Crtr {
|
||||
void MatchDynamic(SkinElement rel, ContainerState context, Transform anchor = null) {
|
||||
ChartPlayer.etor.ContextTransform = anchor;
|
||||
foreach (var p in rel.properties) {
|
||||
if (p.Key.Name == null)
|
||||
if (p.Key.Name == 0)
|
||||
throw new InvalidOperationException("Component creation in dynamic context is not allowed");
|
||||
var prop = GetPropOp(anchor, p.Key);
|
||||
if (context.CloneType > prop.UpdateCloneType) continue;
|
||||
|
@@ -4,7 +4,7 @@ using System.Linq;
|
||||
|
||||
namespace Cryville.Crtr {
|
||||
public class StampedEvent : IComparable<StampedEvent> {
|
||||
public float Time;
|
||||
public double Time;
|
||||
public ChartEvent Unstamped;
|
||||
public EventContainer Container;
|
||||
public StampedEvent Origin;
|
||||
@@ -12,7 +12,7 @@ namespace Cryville.Crtr {
|
||||
private StampedEvent attev = null;
|
||||
private StampedEvent relev = null;
|
||||
|
||||
public float Duration {
|
||||
public double Duration {
|
||||
get {
|
||||
if (Unstamped == null) return 0;
|
||||
if (Unstamped.IsLong)
|
||||
@@ -43,7 +43,7 @@ namespace Cryville.Crtr {
|
||||
public override int Priority {
|
||||
get { return StartEvent == null ? 4 : 6; }
|
||||
}
|
||||
protected override int cmpExtra(StampedEvent other) {
|
||||
protected override int CompareExtra(StampedEvent other) {
|
||||
return Equals(StartEvent, other) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
@@ -75,12 +75,12 @@ namespace Cryville.Crtr {
|
||||
if (u != 0) return u;
|
||||
u = this.Duration.CompareTo(other.Duration);
|
||||
if (u != 0) return u;
|
||||
u = cmpExtra(other);
|
||||
u = CompareExtra(other);
|
||||
if (u != 0) return u;
|
||||
return GetHashCode().CompareTo(other.GetHashCode());
|
||||
}
|
||||
|
||||
protected virtual int cmpExtra(StampedEvent other) {
|
||||
protected virtual int CompareExtra(StampedEvent other) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@@ -4,7 +4,7 @@ using System.Collections.Generic;
|
||||
namespace Cryville.Crtr {
|
||||
public abstract class StateBase<T> {
|
||||
public int EventId;
|
||||
public float Time;
|
||||
public double Time;
|
||||
public Chart chart;
|
||||
public List<T> events;
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace Cryville.Crtr {
|
||||
}
|
||||
|
||||
public virtual StateBase<T> Clone() {
|
||||
return (StateBase<T>)base.MemberwiseClone();
|
||||
return (StateBase<T>)MemberwiseClone();
|
||||
}
|
||||
|
||||
public virtual void CopyTo(StateBase<T> dest) {
|
||||
@@ -32,18 +32,18 @@ namespace Cryville.Crtr {
|
||||
}
|
||||
|
||||
public void Forward(Action<T> callback = null) {
|
||||
ForwardToTime(float.PositiveInfinity, callback);
|
||||
ForwardToTime(double.PositiveInfinity, callback);
|
||||
}
|
||||
|
||||
public void ForwardByTime(float time, Action<T> callback = null) {
|
||||
public void ForwardByTime(double time, Action<T> callback = null) {
|
||||
ForwardToTime(Time + time, callback);
|
||||
}
|
||||
|
||||
public void ForwardOnceByTime(float time, Action<T> callback = null) {
|
||||
public void ForwardOnceByTime(double time, Action<T> callback = null) {
|
||||
ForwardOnceToTime(Time + time, callback);
|
||||
}
|
||||
|
||||
public void ForwardToTime(float toTime, Action<T> callback = null) {
|
||||
public void ForwardToTime(double toTime, Action<T> callback = null) {
|
||||
breakflag = false;
|
||||
ForwardOnceToTime(Time, callback);
|
||||
while (Time < toTime) {
|
||||
@@ -52,20 +52,20 @@ namespace Cryville.Crtr {
|
||||
}
|
||||
}
|
||||
|
||||
public void ForwardStepByTime(float time, float step, Action<T> callback = null) {
|
||||
public void ForwardStepByTime(double time, double step, Action<T> callback = null) {
|
||||
ForwardStepToTime(Time + time, step, callback);
|
||||
}
|
||||
|
||||
public void ForwardStepToTime(float toTime, float step, Action<T> callback = null) {
|
||||
public void ForwardStepToTime(double toTime, double step, Action<T> callback = null) {
|
||||
breakflag = false;
|
||||
ForwardOnceToTime(Time, callback);
|
||||
while (Time < toTime) {
|
||||
float next = Time + step;
|
||||
double next = Time + step;
|
||||
ForwardOnceToTime(next < toTime ? next : toTime, callback);
|
||||
if (breakflag) break;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void ForwardOnceToTime(float toTime, Action<T> callback = null);
|
||||
public abstract void ForwardOnceToTime(double toTime, Action<T> callback = null);
|
||||
}
|
||||
}
|
||||
|
@@ -57,7 +57,7 @@ namespace Cryville.Crtr {
|
||||
Vector3 cpt; // Current point
|
||||
Vector3 ppt = Vector3.zero; // Previous point
|
||||
Vector3 pwp = Vector3.zero; // Previous world point
|
||||
float ptime; // Previous time
|
||||
double ptime; // Previous time
|
||||
float length;
|
||||
|
||||
public override void Update(ContainerState s, StampedEvent ev) {
|
||||
@@ -67,7 +67,7 @@ namespace Cryville.Crtr {
|
||||
var tsv = s.ScrollVelocity;
|
||||
|
||||
Vector3 dpt = (Vector3)tpt - ppt; // Delta 2D point
|
||||
dpt.z = (s.Time - ptime) * ChartPlayer.sv * tsv; // Delta Z
|
||||
dpt.z = (float)((s.Time - ptime) * ChartPlayer.sv * tsv); // Delta Z
|
||||
Quaternion rotq = Quaternion.Euler(s.Direction); // Rotation
|
||||
var dwp = rotq * dpt; // Delta world point
|
||||
var nl = length + dwp.magnitude; // New length
|
||||
@@ -133,7 +133,7 @@ namespace Cryville.Crtr {
|
||||
var tsv = s.ScrollVelocity;
|
||||
|
||||
Vector3 dpt = (Vector3)tpt - ppt;
|
||||
dpt.z = (s.Time - ptime) * ChartPlayer.sv * tsv;
|
||||
dpt.z = (float)((s.Time - ptime) * ChartPlayer.sv * tsv);
|
||||
Quaternion rotq = Quaternion.Euler(s.Direction);
|
||||
var dwp = rotq * dpt; // Delta world point
|
||||
var nl = length + dwp.magnitude; // New length
|
||||
|
16
Assets/Cryville/Cryville.Crtr.asmdef
Normal file
16
Assets/Cryville/Cryville.Crtr.asmdef
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "Cryville.Crtr",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"GUID:d8ea0e0da3ad53a45b65c912ffcacab0"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": true,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
7
Assets/Cryville/Cryville.Crtr.asmdef.meta
Normal file
7
Assets/Cryville/Cryville.Crtr.asmdef.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6eb95bd93da7fd54c8c2da321efabb1f
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -9,6 +9,7 @@ using System.Diagnostics.CodeAnalysis;
|
||||
[assembly: SuppressMessage("Style", "IDE0020")]
|
||||
[assembly: SuppressMessage("Style", "IDE0038")]
|
||||
[assembly: SuppressMessage("Style", "IDE0018")]
|
||||
[assembly: SuppressMessage("Style", "IDE0019")]
|
||||
|
||||
// Null operators not supported
|
||||
[assembly: SuppressMessage("Style", "IDE0016")]
|
||||
@@ -40,3 +41,6 @@ using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
// Local function not supported
|
||||
[assembly: SuppressMessage("Style", "IDE0039")]
|
||||
|
||||
// Readonly struct not supported
|
||||
[assembly: SuppressMessage("Style", "IDE0250")]
|
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 50c5924700029154f807fa804934cd76
|
||||
guid: c800326c576090042bed36b262ea3514
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
@@ -1,15 +0,0 @@
|
||||
#if UNITY_5
|
||||
using System.Text.RegularExpressions;
|
||||
using SyntaxTree.VisualStudio.Unity.Bridge;
|
||||
using UnityEditor;
|
||||
|
||||
[InitializeOnLoad]
|
||||
public class ProjectFilesGeneration {
|
||||
static ProjectFilesGeneration() {
|
||||
ProjectFilesGenerator.ProjectFileGeneration += ReplaceContent;
|
||||
}
|
||||
static string ReplaceContent(string n, string c) {
|
||||
return Regex.Replace(c, @"<LangVersion(.*?)>.*?</LangVersion>", @"<LangVersion$1>3</LangVersion>");
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -1,144 +0,0 @@
|
||||
namespace EricHaines {
|
||||
// Only works on ARGB32, RGB24 and Alpha8 textures that are marked readable
|
||||
|
||||
using System.Threading;
|
||||
using UnityEngine;
|
||||
|
||||
public class TextureScale {
|
||||
public class ThreadData {
|
||||
public int start;
|
||||
public int end;
|
||||
public ThreadData(int s, int e) {
|
||||
start = s;
|
||||
end = e;
|
||||
}
|
||||
}
|
||||
|
||||
private static Color[] texColors;
|
||||
private static Color[] newColors;
|
||||
private static int w;
|
||||
private static float ratioX;
|
||||
private static float ratioY;
|
||||
private static int w2;
|
||||
private static int finishCount;
|
||||
private static Mutex mutex;
|
||||
|
||||
public static void Point(Texture2D tex, int newWidth, int newHeight) {
|
||||
ThreadedScale(tex, newWidth, newHeight, false);
|
||||
}
|
||||
|
||||
public static void Bilinear(Texture2D tex, int newWidth, int newHeight) {
|
||||
ThreadedScale(tex, newWidth, newHeight, true);
|
||||
}
|
||||
|
||||
private static void ThreadedScale(Texture2D tex, int newWidth, int newHeight, bool useBilinear) {
|
||||
texColors = tex.GetPixels();
|
||||
newColors = new Color[newWidth * newHeight];
|
||||
if (useBilinear) {
|
||||
ratioX = 1.0f / ((float)newWidth / (tex.width - 1));
|
||||
ratioY = 1.0f / ((float)newHeight / (tex.height - 1));
|
||||
}
|
||||
else {
|
||||
ratioX = (float)tex.width / newWidth;
|
||||
ratioY = (float)tex.height / newHeight;
|
||||
}
|
||||
w = tex.width;
|
||||
w2 = newWidth;
|
||||
var cores = Mathf.Min(SystemInfo.processorCount, newHeight);
|
||||
var slice = newHeight/cores;
|
||||
|
||||
finishCount = 0;
|
||||
if (mutex == null) {
|
||||
mutex = new Mutex(false);
|
||||
}
|
||||
if (cores > 1) {
|
||||
int i = 0;
|
||||
ThreadData threadData;
|
||||
for (i = 0; i < cores - 1; i++) {
|
||||
threadData = new ThreadData(slice * i, slice * (i + 1));
|
||||
ParameterizedThreadStart ts = useBilinear ? new ParameterizedThreadStart(BilinearScale) : new ParameterizedThreadStart(PointScale);
|
||||
Thread thread = new Thread(ts);
|
||||
thread.Start(threadData);
|
||||
}
|
||||
threadData = new ThreadData(slice * i, newHeight);
|
||||
if (useBilinear) {
|
||||
BilinearScale(threadData);
|
||||
}
|
||||
else {
|
||||
PointScale(threadData);
|
||||
}
|
||||
while (finishCount < cores) {
|
||||
Thread.Sleep(1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
ThreadData threadData = new ThreadData(0, newHeight);
|
||||
if (useBilinear) {
|
||||
BilinearScale(threadData);
|
||||
}
|
||||
else {
|
||||
PointScale(threadData);
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_2021_2_OR_NEWER
|
||||
tex.Reinitialize(newWidth, newHeight);
|
||||
#else
|
||||
tex.Resize(newWidth, newHeight);
|
||||
#endif
|
||||
tex.SetPixels(newColors);
|
||||
tex.Apply();
|
||||
|
||||
texColors = null;
|
||||
newColors = null;
|
||||
}
|
||||
|
||||
public static void BilinearScale(object obj) {
|
||||
ThreadData threadData = (ThreadData) obj;
|
||||
for (var y = threadData.start; y < threadData.end; y++) {
|
||||
int yFloor = (int)Mathf.Floor(y * ratioY);
|
||||
var y1 = yFloor * w;
|
||||
var y2 = (yFloor+1) * w;
|
||||
var yw = y * w2;
|
||||
|
||||
for (var x = 0; x < w2; x++) {
|
||||
int xFloor = (int)Mathf.Floor(x * ratioX);
|
||||
var xLerp = x * ratioX-xFloor;
|
||||
newColors[yw + x] = ColorLerpUnclamped(
|
||||
ColorLerpUnclamped(texColors[y1 + xFloor], texColors[y1 + xFloor + 1], xLerp),
|
||||
ColorLerpUnclamped(texColors[y2 + xFloor], texColors[y2 + xFloor + 1], xLerp),
|
||||
y * ratioY - yFloor
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
mutex.WaitOne();
|
||||
finishCount++;
|
||||
mutex.ReleaseMutex();
|
||||
}
|
||||
|
||||
public static void PointScale(object obj) {
|
||||
ThreadData threadData = (ThreadData) obj;
|
||||
for (var y = threadData.start; y < threadData.end; y++) {
|
||||
var thisY = (int)(ratioY * y) * w;
|
||||
var yw = y * w2;
|
||||
for (var x = 0; x < w2; x++) {
|
||||
newColors[yw + x] = texColors[(int)(thisY + ratioX * x)];
|
||||
}
|
||||
}
|
||||
|
||||
mutex.WaitOne();
|
||||
finishCount++;
|
||||
mutex.ReleaseMutex();
|
||||
}
|
||||
|
||||
private static Color ColorLerpUnclamped(Color c1, Color c2, float value) {
|
||||
return new Color(
|
||||
c1.r + (c2.r - c1.r) * value,
|
||||
c1.g + (c2.g - c1.g) * value,
|
||||
c1.b + (c2.b - c1.b) * value,
|
||||
c1.a + (c2.a - c1.a) * value
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,9 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: abad95983f1ca394a92bb061b76ebb2f
|
||||
guid: 5335612e48e4c3947808c99fb99411d5
|
||||
folderAsset: yes
|
||||
timeCreated: 1638411493
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/Extensions/Quaver.API.meta
Normal file
8
Assets/Extensions/Quaver.API.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 82458af35dc0eff4f9f5bcfc7ffd9482
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/Extensions/Quaver.API/Enums.meta
Normal file
8
Assets/Extensions/Quaver.API/Enums.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 81c3fbb9e3606dd40908ceb861f822ea
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
21
Assets/Extensions/Quaver.API/Enums/GameMode.cs
Normal file
21
Assets/Extensions/Quaver.API/Enums/GameMode.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
* Copyright (c) 2017-2018 Swan & The Quaver Team <support@quavergame.com>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Quaver.API.Enums
|
||||
{
|
||||
public enum GameMode
|
||||
{
|
||||
Keys4 = 1,
|
||||
Keys7 = 2
|
||||
}
|
||||
}
|
11
Assets/Extensions/Quaver.API/Enums/GameMode.cs.meta
Normal file
11
Assets/Extensions/Quaver.API/Enums/GameMode.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e80eaf8c181728041aefa03ada870aed
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
24
Assets/Extensions/Quaver.API/Enums/Hitsounds.cs
Normal file
24
Assets/Extensions/Quaver.API/Enums/Hitsounds.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
* Copyright (c) 2017-2018 Swan & The Quaver Team <support@quavergame.com>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Quaver.API.Enums
|
||||
{
|
||||
[Flags]
|
||||
public enum HitSounds
|
||||
{
|
||||
Normal = 1 << 0, // This is 1, but Normal should be played regardless if it's 0 or 1.
|
||||
Whistle = 1 << 1, // 2
|
||||
Finish = 1 << 2, // 4
|
||||
Clap = 1 << 3 // 8
|
||||
}
|
||||
}
|
11
Assets/Extensions/Quaver.API/Enums/Hitsounds.cs.meta
Normal file
11
Assets/Extensions/Quaver.API/Enums/Hitsounds.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4d483d5965d754445b9a330ba2e8dfbc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
14
Assets/Extensions/Quaver.API/Enums/TimeSignature.cs
Normal file
14
Assets/Extensions/Quaver.API/Enums/TimeSignature.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
|
||||
namespace Quaver.API.Enums
|
||||
{
|
||||
/// <summary>
|
||||
/// Signature of a timing point
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public enum TimeSignature
|
||||
{
|
||||
Quadruple = 4,
|
||||
Triple = 3,
|
||||
}
|
||||
}
|
11
Assets/Extensions/Quaver.API/Enums/TimeSignature.cs.meta
Normal file
11
Assets/Extensions/Quaver.API/Enums/TimeSignature.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bb27bc1bd269d214b8d8b95b91992955
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/Extensions/Quaver.API/Maps.meta
Normal file
8
Assets/Extensions/Quaver.API/Maps.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 15da1854a8e5270489fd79b20f741c1a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
1361
Assets/Extensions/Quaver.API/Maps/Qua.cs
Normal file
1361
Assets/Extensions/Quaver.API/Maps/Qua.cs
Normal file
File diff suppressed because it is too large
Load Diff
11
Assets/Extensions/Quaver.API/Maps/Qua.cs.meta
Normal file
11
Assets/Extensions/Quaver.API/Maps/Qua.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 07f411a2b58802d408e547b9f1cf7ca7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/Extensions/Quaver.API/Maps/Structures.meta
Normal file
8
Assets/Extensions/Quaver.API/Maps/Structures.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0cdc2cff3891fb34d91ee006bafca3a9
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
* Copyright (c) 2017-2019 Swan & The Quaver Team <support@quavergame.com>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Quaver.API.Maps.Structures
|
||||
{
|
||||
/// <summary>
|
||||
/// CustomAudioSamples section of the .qua
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class CustomAudioSampleInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// The path to the audio sample.
|
||||
/// </summary>
|
||||
public string Path { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If true, the audio sample is always played back at 1.0x speed, regardless of the rate.
|
||||
/// </summary>
|
||||
public bool UnaffectedByRate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// By-value comparer, auto-generated by Rider.
|
||||
/// </summary>
|
||||
private sealed class ByValueEqualityComparer : IEqualityComparer<CustomAudioSampleInfo>
|
||||
{
|
||||
public bool Equals(CustomAudioSampleInfo x, CustomAudioSampleInfo y)
|
||||
{
|
||||
if (ReferenceEquals(x, y)) return true;
|
||||
if (ReferenceEquals(x, null)) return false;
|
||||
if (ReferenceEquals(y, null)) return false;
|
||||
if (x.GetType() != y.GetType()) return false;
|
||||
return string.Equals(x.Path, y.Path) && x.UnaffectedByRate == y.UnaffectedByRate;
|
||||
}
|
||||
|
||||
public int GetHashCode(CustomAudioSampleInfo obj)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return ((obj.Path != null ? obj.Path.GetHashCode() : 0) * 397) ^ obj.UnaffectedByRate.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEqualityComparer<CustomAudioSampleInfo> ByValueComparer { get; } = new ByValueEqualityComparer();
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0690882ce72359c409a12dfa0b4999ba
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,79 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
//using MoonSharp.Interpreter;
|
||||
//using MoonSharp.Interpreter.Interop;
|
||||
using YamlDotNet.Serialization;
|
||||
|
||||
namespace Quaver.API.Maps.Structures
|
||||
{
|
||||
[Serializable]
|
||||
/*[MoonSharpUserData]*/
|
||||
public class EditorLayerInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// The name of the layer
|
||||
/// </summary>
|
||||
public string Name { get; /*[MoonSharpVisible(false)]*/ set; }
|
||||
|
||||
/// <summary>
|
||||
/// Is the layer hidden in the editor?
|
||||
/// </summary>
|
||||
public bool Hidden { get; /*[MoonSharpVisible(false)]*/ set; }
|
||||
|
||||
/// <summary>
|
||||
/// The color of the layer (default is white)
|
||||
/// </summary>
|
||||
public string ColorRgb { get; /*[MoonSharpVisible(false)]*/ set; }
|
||||
|
||||
/// <summary>
|
||||
/// Converts the stringified color to a System.Drawing color
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/*[MoonSharpVisible(false)]*/
|
||||
public Color GetColor()
|
||||
{
|
||||
if (ColorRgb == null)
|
||||
return Color.White;
|
||||
|
||||
var split = ColorRgb.Split(',');
|
||||
|
||||
try
|
||||
{
|
||||
return Color.FromArgb(byte.Parse(split[0]), byte.Parse(split[1]), byte.Parse(split[2]));
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return Color.White;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// By-value comparer, auto-generated by Rider.
|
||||
/// </summary>
|
||||
private sealed class ByValueEqualityComparer : IEqualityComparer<EditorLayerInfo>
|
||||
{
|
||||
public bool Equals(EditorLayerInfo x, EditorLayerInfo y)
|
||||
{
|
||||
if (ReferenceEquals(x, y)) return true;
|
||||
if (ReferenceEquals(x, null)) return false;
|
||||
if (ReferenceEquals(y, null)) return false;
|
||||
if (x.GetType() != y.GetType()) return false;
|
||||
return string.Equals(x.Name, y.Name) && x.Hidden == y.Hidden && string.Equals(x.ColorRgb, y.ColorRgb);
|
||||
}
|
||||
|
||||
public int GetHashCode(EditorLayerInfo obj)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
var hashCode = obj.Name.GetHashCode();
|
||||
hashCode = (hashCode * 397) ^ obj.Hidden.GetHashCode();
|
||||
hashCode = (hashCode * 397) ^ obj.ColorRgb.GetHashCode();
|
||||
return hashCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEqualityComparer<EditorLayerInfo> ByValueComparer { get; } = new ByValueEqualityComparer();
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f5d19ab23108e3d41a2d77670afbab10
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
187
Assets/Extensions/Quaver.API/Maps/Structures/HitObjectInfo.cs
Normal file
187
Assets/Extensions/Quaver.API/Maps/Structures/HitObjectInfo.cs
Normal file
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
* Copyright (c) 2017-2019 Swan & The Quaver Team <support@quavergame.com>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
//using MoonSharp.Interpreter;
|
||||
//using MoonSharp.Interpreter.Interop;
|
||||
using Quaver.API.Enums;
|
||||
using YamlDotNet.Serialization;
|
||||
|
||||
namespace Quaver.API.Maps.Structures
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// HitObjects section of the .qua
|
||||
/// </summary>
|
||||
/*[MoonSharpUserData]*/
|
||||
[Serializable]
|
||||
public class HitObjectInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// The time in milliseconds when the HitObject is supposed to be hit.
|
||||
/// </summary>
|
||||
public int StartTime
|
||||
{
|
||||
get;
|
||||
/*[MoonSharpVisible(false)]*/ set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The lane the HitObject falls in
|
||||
/// </summary>
|
||||
public int Lane
|
||||
{
|
||||
get;
|
||||
/*MoonSharpVisible(false)]*/ set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The endtime of the HitObject (if greater than 0, it's considered a hold note.)
|
||||
/// </summary>
|
||||
public int EndTime
|
||||
{
|
||||
get;
|
||||
/*[MoonSharpVisible(false)]*/ set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bitwise combination of hit sounds for this object
|
||||
/// </summary>
|
||||
public HitSounds HitSound
|
||||
{
|
||||
get;
|
||||
/*[MoonSharpVisible(false)]*/ set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Key sounds to play when this object is hit.
|
||||
/// </summary>
|
||||
/*[MoonSharpVisible(false)]*/
|
||||
public List<KeySoundInfo> KeySounds { get; set; } = new List<KeySoundInfo>();
|
||||
|
||||
/// <summary>
|
||||
/// The layer in the editor that the object belongs to.
|
||||
/// </summary>
|
||||
public int EditorLayer
|
||||
{
|
||||
get;
|
||||
/*[MoonSharpVisible(false)]*/ set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If the object is a long note. (EndTime > 0)
|
||||
/// </summary>
|
||||
[YamlIgnore]
|
||||
public bool IsLongNote => EndTime > 0;
|
||||
|
||||
/// <summary>
|
||||
/// Returns if the object is allowed to be edited in lua scripts
|
||||
/// </summary>
|
||||
[YamlIgnore]
|
||||
public bool IsEditableInLuaScript
|
||||
{
|
||||
get;
|
||||
/*[MoonSharpVisible(false)]*/ set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the timing point this object is in range of.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public TimingPointInfo GetTimingPoint(List<TimingPointInfo> timingPoints)
|
||||
{
|
||||
// Search through the entire list for the correct point
|
||||
for (var i = timingPoints.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (StartTime >= timingPoints[i].StartTime)
|
||||
return timingPoints[i];
|
||||
}
|
||||
|
||||
return timingPoints.First();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
/// <param name="time"></param>
|
||||
/// <exception cref="InvalidOperationException"></exception>
|
||||
public void SetStartTime(int time)
|
||||
{
|
||||
ThrowUneditableException();
|
||||
StartTime = time;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException"></exception>
|
||||
public void SetEndTime(int time)
|
||||
{
|
||||
ThrowUneditableException();
|
||||
EndTime = time;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
/// <param name="lane"></param>
|
||||
public void SetLane(int lane)
|
||||
{
|
||||
ThrowUneditableException();
|
||||
Lane = lane;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
/// <param name="hitsounds"></param>
|
||||
public void SetHitSounds(HitSounds hitsounds)
|
||||
{
|
||||
ThrowUneditableException();
|
||||
HitSound = hitsounds;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException"></exception>
|
||||
private void ThrowUneditableException()
|
||||
{
|
||||
if (!IsEditableInLuaScript)
|
||||
throw new InvalidOperationException("Value is not allowed to be edited in lua scripts.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// By-value comparer, mostly auto-generated by Rider: KeySounds-related code is changed to by-value.
|
||||
/// </summary>
|
||||
private sealed class ByValueEqualityComparer : IEqualityComparer<HitObjectInfo>
|
||||
{
|
||||
public bool Equals(HitObjectInfo x, HitObjectInfo y)
|
||||
{
|
||||
if (ReferenceEquals(x, y)) return true;
|
||||
if (ReferenceEquals(x, null)) return false;
|
||||
if (ReferenceEquals(y, null)) return false;
|
||||
if (x.GetType() != y.GetType()) return false;
|
||||
return x.StartTime == y.StartTime && x.Lane == y.Lane && x.EndTime == y.EndTime && x.HitSound == y.HitSound && x.KeySounds.SequenceEqual(y.KeySounds, KeySoundInfo.ByValueComparer) && x.EditorLayer == y.EditorLayer;
|
||||
}
|
||||
|
||||
public int GetHashCode(HitObjectInfo obj)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
var hashCode = obj.StartTime;
|
||||
hashCode = (hashCode * 397) ^ obj.Lane;
|
||||
hashCode = (hashCode * 397) ^ obj.EndTime;
|
||||
hashCode = (hashCode * 397) ^ (int) obj.HitSound;
|
||||
foreach (var keySound in obj.KeySounds)
|
||||
hashCode = (hashCode * 397) ^ KeySoundInfo.ByValueComparer.GetHashCode(keySound);
|
||||
hashCode = (hashCode * 397) ^ obj.EditorLayer;
|
||||
return hashCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEqualityComparer<HitObjectInfo> ByValueComparer { get; } = new ByValueEqualityComparer();
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 14fc15101f91a2c439d64f27a699da09
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
47
Assets/Extensions/Quaver.API/Maps/Structures/KeySoundInfo.cs
Normal file
47
Assets/Extensions/Quaver.API/Maps/Structures/KeySoundInfo.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Quaver.API.Maps.Structures
|
||||
{
|
||||
/// <summary>
|
||||
/// KeySounds property of hit objects.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class KeySoundInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// The one-based index of the sound sample in the CustomAudioSamples array.
|
||||
/// </summary>
|
||||
public int Sample { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The volume of the sound sample. Defaults to 100.
|
||||
/// </summary>
|
||||
public int Volume { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// By-value comparer, auto-generated by Rider.
|
||||
/// </summary>
|
||||
private sealed class ByValueEqualityComparer : IEqualityComparer<KeySoundInfo>
|
||||
{
|
||||
public bool Equals(KeySoundInfo x, KeySoundInfo y)
|
||||
{
|
||||
if (ReferenceEquals(x, y)) return true;
|
||||
if (ReferenceEquals(x, null)) return false;
|
||||
if (ReferenceEquals(y, null)) return false;
|
||||
if (x.GetType() != y.GetType()) return false;
|
||||
return x.Sample == y.Sample && x.Volume == y.Volume;
|
||||
}
|
||||
|
||||
public int GetHashCode(KeySoundInfo obj)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return (obj.Sample * 397) ^ obj.Volume;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEqualityComparer<KeySoundInfo> ByValueComparer { get; } = new ByValueEqualityComparer();
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ad94e179dbb3a5e47b47c8475e3e707f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
* Copyright (c) 2017-2019 Swan & The Quaver Team <support@quavergame.com>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
//using MoonSharp.Interpreter;
|
||||
//using MoonSharp.Interpreter.Interop;
|
||||
using YamlDotNet.Serialization;
|
||||
|
||||
namespace Quaver.API.Maps.Structures
|
||||
{
|
||||
/// <summary>
|
||||
/// SliderVelocities section of the .qua
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
/*[MoonSharpUserData]*/
|
||||
public class SliderVelocityInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// The time in milliseconds when the new SliderVelocity section begins
|
||||
/// </summary>
|
||||
public float StartTime
|
||||
{
|
||||
get;
|
||||
/*[MoonSharpVisible(false)]*/ set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The velocity multiplier relative to the current timing section's BPM
|
||||
/// </summary>
|
||||
public float Multiplier
|
||||
{
|
||||
get;
|
||||
/*[MoonSharpVisible(false)]*/ set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if the SV is allowed to be edited in lua scripts
|
||||
/// </summary>
|
||||
[YamlIgnore]
|
||||
public bool IsEditableInLuaScript
|
||||
{
|
||||
get;
|
||||
/*[MoonSharpVisible(false)]*/ set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the start time of the SV.
|
||||
/// FOR USE IN LUA SCRIPTS ONLY.
|
||||
/// </summary>
|
||||
/// <param name="time"></param>
|
||||
/// <exception cref="InvalidOperationException"></exception>
|
||||
public void SetStartTime(float time)
|
||||
{
|
||||
ThrowUneditableException();
|
||||
StartTime = time;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the multiplier of the SV.
|
||||
/// FOR USE IN LUA SCRIPTS ONLY.
|
||||
/// </summary>
|
||||
/// <param name="multiplier"></param>
|
||||
/// <exception cref="InvalidOperationException"></exception>
|
||||
public void SetMultiplier(float multiplier)
|
||||
{
|
||||
ThrowUneditableException();
|
||||
Multiplier = multiplier;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException"></exception>
|
||||
private void ThrowUneditableException()
|
||||
{
|
||||
if (!IsEditableInLuaScript)
|
||||
throw new InvalidOperationException("Value is not allowed to be edited in lua scripts.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// By-value comparer, auto-generated by Rider.
|
||||
/// </summary>
|
||||
private sealed class ByValueEqualityComparer : IEqualityComparer<SliderVelocityInfo>
|
||||
{
|
||||
public bool Equals(SliderVelocityInfo x, SliderVelocityInfo y)
|
||||
{
|
||||
if (ReferenceEquals(x, y)) return true;
|
||||
if (ReferenceEquals(x, null)) return false;
|
||||
if (ReferenceEquals(y, null)) return false;
|
||||
if (x.GetType() != y.GetType()) return false;
|
||||
return x.StartTime.Equals(y.StartTime) && x.Multiplier.Equals(y.Multiplier);
|
||||
}
|
||||
|
||||
public int GetHashCode(SliderVelocityInfo obj)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return (obj.StartTime.GetHashCode() * 397) ^ obj.Multiplier.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEqualityComparer<SliderVelocityInfo> ByValueComparer { get; } = new ByValueEqualityComparer();
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cebb7330d6e4d9b4da4ceb367c1a2fd4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
* Copyright (c) 2017-2019 Swan & The Quaver Team <support@quavergame.com>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Quaver.API.Maps.Structures
|
||||
{
|
||||
/// <summary>
|
||||
/// SoundEffects section of the .qua
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class SoundEffectInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// The time at which to play the sound sample.
|
||||
/// </summary>
|
||||
public float StartTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The one-based index of the sound sample in the CustomAudioSamples array.
|
||||
/// </summary>
|
||||
public int Sample { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The volume of the sound sample. Defaults to 100.
|
||||
/// </summary>
|
||||
public int Volume { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// By-value comparer, auto-generated by Rider.
|
||||
/// </summary>
|
||||
private sealed class ByValueEqualityComparer : IEqualityComparer<SoundEffectInfo>
|
||||
{
|
||||
public bool Equals(SoundEffectInfo x, SoundEffectInfo y)
|
||||
{
|
||||
if (ReferenceEquals(x, y)) return true;
|
||||
if (ReferenceEquals(x, null)) return false;
|
||||
if (ReferenceEquals(y, null)) return false;
|
||||
if (x.GetType() != y.GetType()) return false;
|
||||
return x.StartTime.Equals(y.StartTime) && x.Sample == y.Sample && x.Volume == y.Volume;
|
||||
}
|
||||
|
||||
public int GetHashCode(SoundEffectInfo obj)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
var hashCode = obj.StartTime.GetHashCode();
|
||||
hashCode = (hashCode * 397) ^ obj.Sample;
|
||||
hashCode = (hashCode * 397) ^ obj.Volume;
|
||||
return hashCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEqualityComparer<SoundEffectInfo> ByValueComparer { get; } = new ByValueEqualityComparer();
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2f1502b1df0fdb9459d43358ed857875
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
102
Assets/Extensions/Quaver.API/Maps/Structures/TimingPointInfo.cs
Normal file
102
Assets/Extensions/Quaver.API/Maps/Structures/TimingPointInfo.cs
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
* Copyright (c) 2017-2019 Swan & The Quaver Team <support@quavergame.com>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
//using MoonSharp.Interpreter;
|
||||
//using MoonSharp.Interpreter.Interop;
|
||||
using Quaver.API.Enums;
|
||||
using YamlDotNet.Serialization;
|
||||
|
||||
namespace Quaver.API.Maps.Structures
|
||||
{
|
||||
/// <summary>
|
||||
/// TimingPoints section of the .qua
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
/*[MoonSharpUserData]*/
|
||||
public class TimingPointInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// The time in milliseconds for when this timing point begins
|
||||
/// </summary>
|
||||
public float StartTime
|
||||
{
|
||||
get;
|
||||
/*[MoonSharpVisible(false)]*/ set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The BPM during this timing point
|
||||
/// </summary>
|
||||
public float Bpm
|
||||
{
|
||||
get;
|
||||
/*[MoonSharpVisible(false)]*/ set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The signature during this timing point
|
||||
/// </summary>
|
||||
public TimeSignature Signature
|
||||
{
|
||||
get;
|
||||
/*[MoonSharpVisible(false)]*/ set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether timing lines during this timing point should be hidden or not
|
||||
/// </summary>
|
||||
public bool Hidden
|
||||
{
|
||||
get;
|
||||
/*[MoonSharpVisible(false)]*/ set;
|
||||
}
|
||||
|
||||
[YamlIgnore]
|
||||
public bool IsEditableInLuaScript
|
||||
{
|
||||
get;
|
||||
/*[MoonSharpVisible(false)]*/ set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The amount of milliseconds per beat this one takes up.
|
||||
/// </summary>
|
||||
[YamlIgnore]
|
||||
public float MillisecondsPerBeat => 60000 / Bpm;
|
||||
|
||||
/// <summary>
|
||||
/// By-value comparer, auto-generated by Rider.
|
||||
/// </summary>
|
||||
private sealed class ByValueEqualityComparer : IEqualityComparer<TimingPointInfo>
|
||||
{
|
||||
public bool Equals(TimingPointInfo x, TimingPointInfo y)
|
||||
{
|
||||
if (ReferenceEquals(x, y)) return true;
|
||||
if (ReferenceEquals(x, null)) return false;
|
||||
if (ReferenceEquals(y, null)) return false;
|
||||
if (x.GetType() != y.GetType()) return false;
|
||||
return x.StartTime.Equals(y.StartTime) && x.Bpm.Equals(y.Bpm) && x.Signature == y.Signature && x.Hidden == y.Hidden;
|
||||
}
|
||||
|
||||
public int GetHashCode(TimingPointInfo obj)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
var hashCode = obj.StartTime.GetHashCode();
|
||||
hashCode = (hashCode * 397) ^ obj.Bpm.GetHashCode();
|
||||
hashCode = (hashCode * 397) ^ (int) obj.Signature;
|
||||
hashCode = (hashCode * 397) ^ (obj.Hidden ? 1 : 0);
|
||||
return hashCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEqualityComparer<TimingPointInfo> ByValueComparer { get; } = new ByValueEqualityComparer();
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 02c7f0a85b74dc34cad4f1e3dea4dbbc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
16
Assets/Extensions/Quaver.API/Quaver.API.asmdef
Normal file
16
Assets/Extensions/Quaver.API/Quaver.API.asmdef
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "Quaver.API",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"GUID:b3f49edfedc855a48aa1a9e5d3cba438"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": true,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": true
|
||||
}
|
7
Assets/Extensions/Quaver.API/Quaver.API.asmdef.meta
Normal file
7
Assets/Extensions/Quaver.API/Quaver.API.asmdef.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d8ea0e0da3ad53a45b65c912ffcacab0
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user