129 Commits

Author SHA1 Message Date
92a3d5018f Merge 'dev-extension' into 'master'. 2023-03-23 19:25:14 +08:00
d510fec57b Update version. 2023-03-23 19:11:24 +08:00
054b17811d Preserve Convert. 2023-03-22 20:04:32 +08:00
94d5f7f82e Preserve BinaryReader and StreamReader. 2023-03-19 14:13:36 +08:00
0e4445e52b Detects assembly references and determines loading order automatically. 2023-03-18 13:46:13 +08:00
c5214dd477 Update gitignore. 2023-03-17 18:08:11 +08:00
ed2c216cf4 Implement extension. 2023-03-17 18:03:59 +08:00
609645c108 Import HybridCLR. 2023-03-17 18:03:22 +08:00
d280d27a0a Improve error log on resource import failure. 2023-03-17 18:00:46 +08:00
5b727065f3 Adapt conversion for RawChartResource. 2023-03-17 17:59:59 +08:00
7aa2577059 Move UMG importers to extensions. 2023-03-17 17:58:45 +08:00
c1b7e9ab55 Separate extension classes into external assembly. 2023-03-17 17:56:12 +08:00
99384397ed Remove extensions. 2023-03-17 17:49:54 +08:00
a2391aeb22 Cleanup. (Skin editor) 2023-03-15 15:44:32 +08:00
2207c80951 Fix incorrect style for single-statement blocks in expression. 2023-03-15 15:43:30 +08:00
bf578d7cb9 Make statements in expression not sortable. 2023-03-15 15:41:02 +08:00
0bc57c368f Improve scaling logic of popup list in skin editor.. 2023-03-15 15:39:31 +08:00
b64f85aaa2 Add category for expression list in skin editor. 2023-03-15 15:36:45 +08:00
93fa2f2d7e Sync some constants, operators, and functions for skin editor. (3) 2023-03-15 15:34:33 +08:00
d72216de8b Sync some constants, operators, and functions for skin editor. (2) 2023-03-15 10:02:09 +08:00
df5133a91a Sync some constants, operators, and functions for skin editor. 2023-03-15 00:46:19 +08:00
88b959a118 Modify border color of expression statement. 2023-03-15 00:44:44 +08:00
310bf91fbd Always collapses delete button in skin editor. 2023-03-15 00:43:49 +08:00
699f47f98d Fix the height of popup list in skin editor. 2023-03-15 00:43:07 +08:00
24e881b138 Sync component and property list for skin editor. 2023-03-14 23:32:35 +08:00
2eef1b5c4e Update translations for skin editor. 2023-03-14 17:27:05 +08:00
c18ceb50d4 Update skin structure in editor. 2023-03-14 17:24:32 +08:00
27ca1a7292 Implement expression in skin editor. 2023-03-14 17:22:48 +08:00
dc59176eac Fix encoding for skin editor. 2023-03-14 16:59:37 +08:00
aec7470ff8 Optimize css for skin editor. 2023-03-14 16:58:03 +08:00
983cba6843 Detects user chart path for Malody chart finder. 2023-03-11 21:41:54 +08:00
871782e73f Remove potentially buggy syncing logic. 2023-03-11 21:41:22 +08:00
9aaa96fe10 Optimize GC for input proxy. 2023-03-11 21:40:34 +08:00
22190a29c1 Fix incorrect array length for vector operator. 2023-03-11 21:39:26 +08:00
613ca467d0 Fix offset error on function anim. 2023-03-09 22:02:34 +08:00
536a3066b2 Fix array operator creating array of type error. 2023-03-09 16:27:16 +08:00
43488cd002 Add "emit effect on self" annotation. 2023-03-09 16:26:43 +08:00
a11ccbd39c Cleanup variable name. 2023-03-09 11:41:25 +08:00
76df4929a7 Implement set variable annotation. 2023-03-09 11:38:49 +08:00
505b826627 Move up non-generic collection types and add debug view. 2023-03-09 11:37:23 +08:00
26a8675922 Make animation time of subspan relative. 2023-03-09 10:07:24 +08:00
b89e1f983e Code cleanup. 2023-03-08 20:36:18 +08:00
717e77b47e Fix inaccurate beat snapping for Quaver charts. 2023-03-06 08:16:42 +08:00
2f10c79dee Adjust offset for osu chart converter. 2023-03-05 23:06:18 +08:00
55f7790f89 Fix potential error on vector property source. 2023-03-05 23:05:48 +08:00
ae5f4a8c16 (Amend to 1851bd3c) 2023-03-05 21:53:30 +08:00
1851bd3c54 Fix inaccurate beat snapping for osu charts. Fix osu charts with too low BPM not able to be imported. 2023-03-05 20:40:02 +08:00
6d74685cb7 Add anim.iteration, anim.direction, and anim.delay properties. 2023-03-03 15:10:52 +08:00
03fd7f6d01 Add inf constant. 2023-03-03 15:09:08 +08:00
28c878f3e5 Code cleanup. 2023-03-03 13:34:12 +08:00
7736eba14d Supplement generic PairCollection. 2023-03-03 13:26:11 +08:00
2e54b38d2b Supplement Insert methods for pair list. 2023-03-03 11:49:32 +08:00
da60dc0903 Fix potential order inconsistency of element and property lists. 2023-03-03 11:45:16 +08:00
215f72b3b5 Add cubic bezier functions. 2023-03-02 10:40:18 +08:00
a93c081dd8 Add easing function parameter to anim function. 2023-03-02 10:39:39 +08:00
456782930a Fix incorrect zero format specifier range. 2023-03-01 17:55:09 +08:00
ba3cbbd64c Add state-based effect. 2023-03-01 00:37:22 +08:00
dfc3e9ca06 Refactor OpenedAnchorName in ISkinnableGroup. (Amend) 2023-03-01 00:36:09 +08:00
f567a2b78e Fix error on setting anim.name to null. 2023-03-01 00:35:19 +08:00
c7e7bd8a77 Add Identifier.Empty. 2023-03-01 00:33:28 +08:00
67720fd0e1 Refactor OpenedAnchorName in ISkinnableGroup. 2023-03-01 00:33:01 +08:00
1a30149942 Prevents infinite propagation on input proxy and judge. 2023-02-28 13:47:38 +08:00
a755cc13bd Implement animation. 2023-02-27 00:17:14 +08:00
9a51cf1b56 Add rewind and tick mechanism for skin component. 2023-02-27 00:16:44 +08:00
256c656e9c Fix once annotation not working on certain properties. 2023-02-27 00:13:38 +08:00
2ac7f05316 Add contextual function anim. 2023-02-27 00:11:37 +08:00
28d46dbabe Disallows multiple meshes in one object. 2023-02-26 16:24:58 +08:00
18b3e0bc84 Code cleanup. 2023-02-26 16:24:28 +08:00
23f2e7c1f2 Fix multiple flags ignored in enum property operator. 2023-02-26 16:23:17 +08:00
998713b41f Pull some init logic in enum property operator to static constructor. 2023-02-26 16:22:37 +08:00
3561354231 Implement execute once annotation on properties. 2023-02-26 16:21:33 +08:00
0cccb170c1 Support extra annotations on skin property key. Code cleanup. 2023-02-26 16:20:25 +08:00
d2480b8a6f Update global suppressions. 2023-02-26 16:16:46 +08:00
6837d3f7ee Make the group in skin container readonly. 2023-02-24 15:25:04 +08:00
3ecf3b4bfc Code cleanup. 2023-02-21 22:47:42 +08:00
1da8647ff1 Re-add start offset stub. 2023-02-21 22:47:24 +08:00
2f19e8daad Add limit for render distance settings. 2023-02-21 22:45:51 +08:00
07f62c7aeb Reduce font size for extra tag in input config. 2023-02-21 22:43:38 +08:00
39db8dfa45 Code cleanup. 2023-02-21 18:43:21 +08:00
f04cd370f1 Allow vector as number in contextual operators. 2023-02-21 18:42:58 +08:00
5c4acd54ce Add ticking stub for effect. 2023-02-21 18:42:03 +08:00
82dbc5c479 Add event property for event. 2023-02-21 18:41:32 +08:00
1f1663d714 Rename index to effect_index. 2023-02-21 18:29:25 +08:00
a3c5392caa Optimize GC for vector property source. 2023-02-21 18:27:29 +08:00
6c983cc2cb Add backward compatibility for opacity property. 2023-02-19 22:44:12 +08:00
3bf3fdac3d Code cleanup. 2023-02-19 22:15:46 +08:00
f2f3dba098 Fix effect queue with multiple items of the same instance. 2023-02-19 22:15:25 +08:00
3728360dd2 Fix index invalidation for effects. 2023-02-19 22:13:57 +08:00
887837bb3d Fix main thread stuck on texture missing. 2023-02-19 22:13:18 +08:00
99b4c2dfc1 Fix error on text frame update if texture not found. 2023-02-19 22:11:59 +08:00
e59769158a Change materials to shared mode in components. 2023-02-19 22:08:09 +08:00
ba3238614b Pull up mesh.color. Remove *.opacity properties. 2023-02-19 22:06:20 +08:00
a115999aab Add additive shader. 2023-02-19 21:57:06 +08:00
393947db9f Add image.shader property. 2023-02-19 21:56:30 +08:00
e9b2a7f894 Fix error on dynamic expressions in static context. 2023-02-19 21:55:01 +08:00
9c73455761 Fix error on appending arg set when current length equals to capacity in string formatter. 2023-02-19 11:07:50 +08:00
59c2210359 Prevents dimension-unapplicable inputs from being assigned. 2023-02-18 15:51:21 +08:00
4fab20953a Improve text hints in input config. 2023-02-18 15:49:45 +08:00
ee7b0f5081 Make pause input optional. 2023-02-18 15:48:02 +08:00
33ee7a9a87 Code cleanup. 2023-02-18 15:46:32 +08:00
900bd7b77a Implement effect. 2023-02-18 14:51:28 +08:00
6bd32c9aef Add context cascade blocking. 2023-02-18 14:48:43 +08:00
13893b2853 Add execute once annotation. 2023-02-18 14:48:09 +08:00
23789c15eb Pull up material disposal to MeshBase. (Amend) 2023-02-18 14:46:38 +08:00
a1f7418d32 Code cleanup. 2023-02-18 14:46:08 +08:00
274a823d02 Fix log not cleared on log toggle. 2023-02-18 14:44:05 +08:00
ba6239068a Optimize GC for sprite update. 2023-02-18 14:42:42 +08:00
ff8c925f32 Optimize GC for setting image.frame. 2023-02-18 14:40:56 +08:00
2a6a33e60c Pull up material disposal to MeshBase. 2023-02-18 14:39:45 +08:00
8910b1f4a0 Allow dynamic anchor reset. 2023-02-17 23:14:51 +08:00
36dddea4d9 Code cleanup. 2023-02-17 21:13:19 +08:00
6a648c2dcd Fix error on image.frame(s) not set. 2023-02-17 21:12:41 +08:00
2d4087dc89 Fix behaviour on parameter overflow. 2023-02-17 21:11:38 +08:00
f91aacd78e Code cleanup. 2023-02-17 18:11:04 +08:00
9c08cbf0d2 Remove some dedicated properties on ISkinnableGroup. 2023-02-17 18:10:46 +08:00
88d35e4eaf Add backward compatibility for skin. (Amend) 2023-02-17 16:27:49 +08:00
675ce68073 Add backward compatibility for skin. 2023-02-17 16:24:24 +08:00
db0165d145 Pull up ISkinnableGroup. 2023-02-17 15:19:18 +08:00
7015426300 Add error handling for setting text.frames. 2023-02-17 14:41:12 +08:00
0d4cc5e208 Add skin property image.frames and image.index. 2023-02-17 14:40:34 +08:00
e7ce0985fb Add effect emitting stub. 2023-02-15 18:13:04 +08:00
eb6dafbd60 Add animation stub and effect stub for skin. 2023-02-15 18:12:41 +08:00
b6e238780e Change fixed skin root to configurable root element in skin container. 2023-02-15 18:09:21 +08:00
c7ea6f1d4b Cleanup logic of PDT interpreter. 2023-02-15 18:07:36 +08:00
4a5b2a6889 Add effect definition. 2023-02-15 15:35:09 +08:00
b84d645aee Pull up PdtBinder. 2023-02-15 15:34:27 +08:00
67b44db1ae Code cleanup. 2023-02-13 16:09:19 +08:00
ee4399109a Optimize GC for log in gameplay scene. 2023-02-12 21:50:57 +08:00
87ef534f59 Fix resize logic in StringBuffer. 2023-02-12 21:48:39 +08:00
603 changed files with 3129 additions and 30455 deletions

1
.gitignore vendored
View File

@@ -68,3 +68,4 @@ crashlytics-build.properties
/UserSettings /UserSettings
/*.zip /*.zip
*.lnk *.lnk
/HybridCLRData

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 5335612e48e4c3947808c99fb99411d5 guid: c4ef48e4a4983de4e9c31483df2a918e
folderAsset: yes folderAsset: yes
DefaultImporter: DefaultImporter:
externalObjects: {} externalObjects: {}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 6823ead66b33bc048bbad48719feb25d guid: 9ec674235c0dd6744af2dab2b58dd53c
folderAsset: yes folderAsset: yes
DefaultImporter: DefaultImporter:
externalObjects: {} externalObjects: {}

View File

@@ -0,0 +1,8 @@
using System.Collections.Generic;
namespace Cryville.Common.Collections.Generic {
public interface IPairList<TKey, TValue> : IList<KeyValuePair<TKey, TValue>> {
void Add(TKey key, TValue value);
void Insert(int index, TKey key, TValue value);
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: f5b3f3294f679f14f8ec1195b0def630 guid: 73fb17b484b343242bcce27c15ed7d44
MonoImporter: MonoImporter:
externalObjects: {} externalObjects: {}
serializedVersion: 2 serializedVersion: 2

View File

@@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace Cryville.Common.Collections.Generic {
[DebuggerDisplay("Count = {Count}"), DebuggerTypeProxy(typeof(PairCollectionDebugView<,>))]
public struct PairCollection<TKey, TValue> : IDisposable {
public void Dispose() { }
readonly IPairList<TKey, TValue> _pairList;
readonly IDictionary<TKey, TValue> _dictionary;
public PairCollection(object collection) : this() {
var type = collection.GetType();
if (typeof(IPairList<TKey, TValue>).IsAssignableFrom(type)) _pairList = (IPairList<TKey, TValue>)collection;
else if (typeof(IDictionary<TKey, TValue>).IsAssignableFrom(type)) _dictionary = (IDictionary<TKey, TValue>)collection;
else throw new ArgumentException("Parameter is not a pair collection");
}
public int Count {
get {
if (_pairList != null) return _pairList.Count;
else return _dictionary.Count;
}
}
public void Add(TKey key, TValue value) {
if (_pairList != null) _pairList.Add(key, value);
else _dictionary.Add(key, value);
}
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int index) {
if (_pairList != null) _pairList.CopyTo(array, index);
else _dictionary.CopyTo(array, index);
}
}
internal class PairCollectionDebugView<TKey, TValue> {
readonly PairCollection<TKey, TValue> _self;
public PairCollectionDebugView(PairCollection<TKey, TValue> self) {
_self = self;
}
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public KeyValuePair<TKey, TValue>[] Items {
get {
KeyValuePair<TKey, TValue>[] array = new KeyValuePair<TKey, TValue>[_self.Count];
_self.CopyTo(array, 0);
return array;
}
}
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 23377bf2926d93a4b8e3f3ab6040c7f2 guid: 2517e8f040bd36f46948e5fafaf5335c
MonoImporter: MonoImporter:
externalObjects: {} externalObjects: {}
serializedVersion: 2 serializedVersion: 2

View File

@@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace Cryville.Common.Collections.Generic {
[DebuggerDisplay("Count = {Count}"), DebuggerTypeProxy(typeof(PairListDebugView<,>))]
public class PairList<TKey, TValue> : List<KeyValuePair<TKey, TValue>>, IPairList<TKey, TValue>, IPairList {
public void Add(TKey key, TValue value) {
Add(new KeyValuePair<TKey, TValue>(key, value));
}
public void Add(object key, object value) {
try {
Add((TKey)key, (TValue)value);
}
catch (InvalidCastException) {
throw new ArgumentException("Wrong key type or value type");
}
}
public void Insert(int index, TKey key, TValue value) {
Insert(index, new KeyValuePair<TKey, TValue>(key, value));
}
public void Insert(int index, object key, object value) {
try {
Insert(index, (TKey)key, (TValue)value);
}
catch (InvalidCastException) {
throw new ArgumentException("Wrong key type or value type");
}
}
}
internal class PairListDebugView<TKey, TValue> {
readonly PairList<TKey, TValue> _self;
public PairListDebugView(PairList<TKey, TValue> self) {
_self = self;
}
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public KeyValuePair<TKey, TValue>[] Items {
get {
KeyValuePair<TKey, TValue>[] array = new KeyValuePair<TKey, TValue>[_self.Count];
_self.CopyTo(array, 0);
return array;
}
}
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 4ffe72fef6ebb9e4da3571b4117f0d6d guid: d9ed5ea8b7b1a934287e7ec5971166c0
MonoImporter: MonoImporter:
externalObjects: {} externalObjects: {}
serializedVersion: 2 serializedVersion: 2

View File

@@ -0,0 +1,8 @@
using System.Collections;
namespace Cryville.Common.Collections {
public interface IPairList : IList {
void Add(object key, object value);
void Insert(int index, object key, object value);
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: e3c5a8bf05d5e284ba498e91cb0dd35e guid: 046617672d437de4ab7e644a55defd3b
MonoImporter: MonoImporter:
externalObjects: {} externalObjects: {}
serializedVersion: 2 serializedVersion: 2

View File

@@ -0,0 +1,47 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
namespace Cryville.Common.Collections {
[DebuggerDisplay("Count = {Count}"), DebuggerTypeProxy(typeof(PairCollectionDebugView))]
public struct PairCollection : IDisposable {
public void Dispose() { }
readonly IPairList _pairList;
readonly IDictionary _dictionary;
public PairCollection(object collection) : this() {
var type = collection.GetType();
if (typeof(IPairList).IsAssignableFrom(type)) _pairList = (IPairList)collection;
else if (typeof(IDictionary).IsAssignableFrom(type)) _dictionary = (IDictionary)collection;
else throw new ArgumentException("Parameter is not a pair collection");
}
public int Count {
get {
if (_pairList != null) return _pairList.Count;
else return _dictionary.Count;
}
}
public void Add(object key, object value) {
if (_pairList != null) _pairList.Add(key, value);
else _dictionary.Add(key, value);
}
public void CopyTo(KeyValuePair<object, object>[] array, int index) {
if (_pairList != null) _pairList.CopyTo(array, index);
else _dictionary.CopyTo(array, index);
}
}
internal class PairCollectionDebugView {
readonly PairCollection _self;
public PairCollectionDebugView(PairCollection self) {
_self = self;
}
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public KeyValuePair<object, object>[] Items {
get {
KeyValuePair<object, object>[] array = new KeyValuePair<object, object>[_self.Count];
_self.CopyTo(array, 0);
return array;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1f87dfb8f6a1f5640b6deae741cd715c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,29 @@
using System.Collections.Generic;
using System.Diagnostics;
namespace Cryville.Common.Collections {
[DebuggerDisplay("Count = {Count}"), DebuggerTypeProxy(typeof(PairListDebugView))]
public class PairList : List<KeyValuePair<object, object>>, IPairList {
public void Add(object key, object value) {
Add(new KeyValuePair<object, object>(key, value));
}
public void Insert(int index, object key, object value) {
Insert(index, new KeyValuePair<object, object>(key, value));
}
}
internal class PairListDebugView {
readonly PairList _self;
public PairListDebugView(PairList self) {
_self = self;
}
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public KeyValuePair<object, object>[] Items {
get {
KeyValuePair<object, object>[] array = new KeyValuePair<object, object>[_self.Count];
_self.CopyTo(array, 0);
return array;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 57fc9f037c1fda5449e2a365a835c82c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -45,7 +45,7 @@ namespace Cryville.Common.Font {
return tableDirectoryOffsets; return tableDirectoryOffsets;
} }
public override TableDirectory GetSubTable(UInt32 item) { public override TableDirectory GetSubTable(UInt32 item) {
var i = (UInt32)item; var i = item;
return new TableDirectory(Reader, i); return new TableDirectory(Reader, i);
} }
} }

View File

@@ -2,6 +2,7 @@
namespace Cryville.Common { namespace Cryville.Common {
public struct Identifier : IEquatable<Identifier> { public struct Identifier : IEquatable<Identifier> {
public static Identifier Empty = new Identifier(0);
public int Key { get; private set; } public int Key { get; private set; }
public object Name { get { return IdentifierManager.SharedInstance.Retrieve(Key); } } public object Name { get { return IdentifierManager.SharedInstance.Retrieve(Key); } }
public Identifier(int key) { public Identifier(int key) {
@@ -24,11 +25,11 @@ namespace Cryville.Common {
if (Key == 0) return ""; if (Key == 0) return "";
return Name.ToString(); return Name.ToString();
} }
public static implicit operator Identifier(string identifier) { public static bool operator ==(Identifier lhs, Identifier rhs) {
return new Identifier(identifier); return lhs.Equals(rhs);
} }
public static implicit operator string(Identifier identifier) { public static bool operator !=(Identifier lhs, Identifier rhs) {
return identifier.ToString(); return !lhs.Equals(rhs);
} }
} }
} }

View File

@@ -0,0 +1,44 @@
using SMath = System.Math;
namespace Cryville.Common.Math {
// Ported from https://github.com/arian/cubic-bezier/blob/master/index.js
public static class CubicBezier {
public static float Evaluate(float t, float x1, float y1, float x2, float y2, float epsilon) {
float x = t, t0, t1, t2, tx, d2, i;
for (t2 = x, i = 0; i < 8; i++) {
tx = CurveX(t2, x1, x2) - x;
if (SMath.Abs(tx) < epsilon) return CurveY(t2, y1, y2);
d2 = DerivativeCurveX(t2, x1, x2);
if (SMath.Abs(d2) < 1e-6) break;
t2 -= tx / d2;
}
t0 = 0; t1 = 1; t2 = x;
if (t2 < t0) return CurveY(t0, y1, y2);
if (t2 > t1) return CurveY(t1, y1, y2);
while (t0 < t1) {
tx = CurveX(t2, x1, x2);
if (SMath.Abs(tx - x) < epsilon) return CurveY(t2, y1, y2);
if (x > tx) t0 = t2;
else t1 = t2;
t2 = (t1 - t0) * .5f + t0;
}
return CurveY(t2, y1, y2);
}
static float CurveX(float t, float x1, float x2) {
float v = 1 - t;
return 3 * v * v * t * x1 + 3 * v * t * t * x2 + t * t * t;
}
static float CurveY(float t, float y1, float y2) {
float v = 1 - t;
return 3 * v * v * t * y1 + 3 * v * t * t * y2 + t * t * t;
}
static float DerivativeCurveX(float t, float x1, float x2) {
float v = 1 - t;
return 3 * (2 * (t - 1) * t + v * v) * x1 + 3 * (-t * t * t + 2 * v * t) * x2;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 17dd6f775fc965f43960da7166b55b87
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -12,12 +12,12 @@ namespace Cryville.Common.Math {
/// <param name="error">The error.</param> /// <param name="error">The error.</param>
/// <param name="n">The numerator.</param> /// <param name="n">The numerator.</param>
/// <param name="d">The denominator.</param> /// <param name="d">The denominator.</param>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="value" /> is less than 0 or <paramref name="error" /> is not greater than 0 or not less than 1.</exception> /// <exception cref="ArgumentOutOfRangeException"><paramref name="value" /> is less than 0 or <paramref name="error" /> is not greater than 0 or greater than 1.</exception>
public static void ToFraction(double value, double error, out int n, out int d) { public static void ToFraction(double value, double error, out int n, out int d) {
if (value < 0.0) if (value < 0.0)
throw new ArgumentOutOfRangeException("value", "Must be >= 0."); throw new ArgumentOutOfRangeException("value", "Must be >= 0.");
if (error <= 0.0 || error >= 1.0) if (error <= 0.0 || error > 1.0)
throw new ArgumentOutOfRangeException("accuracy", "Must be > 0 and < 1."); throw new ArgumentOutOfRangeException("error", "Must be > 0 and <= 1.");
int num = (int)System.Math.Floor(value); int num = (int)System.Math.Floor(value);
value -= num; value -= num;

View File

@@ -5,7 +5,7 @@ namespace Cryville.Common.Pdt {
/// Indicates that the attributed member is an element list. /// Indicates that the attributed member is an element list.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// <para>An element list is a <see cref="System.Collections.IDictionary" /> that represents a collection of PDT elements. There must be at most one element list in a class.</para> /// <para>An element list is a <see cref="System.Collections.IDictionary" /> or <see cref="Cryville.Common.Collections.Generic.IPairList" /> that represents a collection of PDT elements. There must be at most one element list in a class.</para>
/// </remarks> /// </remarks>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class ElementListAttribute : Attribute { } public class ElementListAttribute : Attribute { }
@@ -14,7 +14,7 @@ namespace Cryville.Common.Pdt {
/// Indicates that the attributed member is a property list. /// Indicates that the attributed member is a property list.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// <para>A property list is a <see cref="System.Collections.IDictionary" /> that represents a collection of PDT properties. There must be at most one property list in a class.</para> /// <para>A property list is a <see cref="System.Collections.IDictionary" /> or <see cref="Cryville.Common.Collections.Generic.IPairList" /> that represents a collection of PDT properties. There must be at most one property list in a class.</para>
/// </remarks> /// </remarks>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class PropertyListAttribute : Attribute { } public class PropertyListAttribute : Attribute { }

View File

@@ -186,7 +186,7 @@ namespace Cryville.Common.Pdt {
protected abstract PdtOperator GetOperator(PdtOperatorSignature sig); protected abstract PdtOperator GetOperator(PdtOperatorSignature sig);
unsafe void Operate(PdtOperator op, int pc, bool noset = false) { unsafe void Operate(PdtOperator op, int pc, bool noset = false) {
fixed (byte* pmem = _mem) { fixed (byte* pmem = _mem) {
op.Begin(this); op.Begin(this, pc);
for (int i = 0; i < pc; i++) { for (int i = 0; i < pc; i++) {
var frame = _stack[--_framecount]; var frame = _stack[--_framecount];
op.LoadOperand(new PdtVariableMemory(frame.Type, pmem + frame.Offset, frame.Length)); op.LoadOperand(new PdtVariableMemory(frame.Type, pmem + frame.Offset, frame.Length));

View File

@@ -92,7 +92,7 @@ namespace Cryville.Common.Pdt {
} }
} }
public partial class PdtInterpreter { public partial class PdtInterpreter {
readonly static Dictionary<char, int> OP_PRIORITY = new Dictionary<char, int> { static readonly Dictionary<char, int> OP_PRIORITY = new Dictionary<char, int> {
{ '@', 7 }, { '@', 7 },
{ '*', 6 }, { '/', 6 }, { '%', 6 }, { '*', 6 }, { '/', 6 }, { '%', 6 },
{ '+', 5 }, { '-', 5 }, { '+', 5 }, { '-', 5 },
@@ -103,7 +103,7 @@ namespace Cryville.Common.Pdt {
{ ',', 0 }, { ',', 0 },
{ '$', -1 }, { '$', -1 },
}; };
readonly static Dictionary<char, int> OP_TYPE = new Dictionary<char, int> { static readonly Dictionary<char, int> OP_TYPE = new Dictionary<char, int> {
{ '@', 0 }, { '@', 0 },
{ '*', 0 }, { '/', 0 }, { '%', 0 }, { '*', 0 }, { '/', 0 }, { '%', 0 },
{ '+', 0 }, { '-', 0 }, { '+', 0 }, { '-', 0 },
@@ -115,7 +115,7 @@ namespace Cryville.Common.Pdt {
{ '$', -1 }, { '$', -1 },
}; };
readonly static PdtExpression _emptyexp; static readonly PdtExpression _emptyexp;
static PdtInterpreter() { static PdtInterpreter() {
var ins = new LinkedList<PdtInstruction>(); var ins = new LinkedList<PdtInstruction>();
ins.AddLast(new PdtInstruction.PushConstant( ins.AddLast(new PdtInstruction.PushConstant(
@@ -143,7 +143,7 @@ namespace Cryville.Common.Pdt {
public override string ToString() { public override string ToString() {
return string.Format("0x{0:x4}: {1}", Type, Value); return string.Format("0x{0:x4}: {1}", Type, Value);
} }
public readonly static PdtExpToken EmptyOperator = new PdtExpToken { public static readonly PdtExpToken EmptyOperator = new PdtExpToken {
Type = 0x0080, Type = 0x0080,
Value = "$", Value = "$",
}; };

View File

@@ -6,30 +6,30 @@
/// <summary> /// <summary>
/// Error type. /// Error type.
/// </summary> /// </summary>
public readonly static int Error = 0x00525245; public const int Error = 0x00525245;
/// <summary> /// <summary>
/// Array of a same variable-length type, with a suffix indicating the element count and the element type. /// Array of a same variable-length type, with a suffix indicating the element count and the element type.
/// </summary> /// </summary>
public readonly static int Array = 0x00525241; public const int Array = 0x00525241;
/// <summary> /// <summary>
/// Null type. /// Null type.
/// </summary> /// </summary>
public readonly static int Null = 0x4c4c554e; public const int Null = 0x4c4c554e;
/// <summary> /// <summary>
/// IEEE 754 32-bit floating-point number. /// IEEE 754 32-bit floating-point number.
/// </summary> /// </summary>
public readonly static int Number = 0x004d554e; public const int Number = 0x004d554e;
/// <summary> /// <summary>
/// A sequence of UTF-16 code units, with a prefix indicating the number of the code units. /// A sequence of UTF-16 code units, with a prefix indicating the number of the code units.
/// </summary> /// </summary>
public readonly static int String = 0x00525453; public const int String = 0x00525453;
/// <summary> /// <summary>
/// A sequence of UTF-16 code units, with a prefix indicating the number of the code units, representing the name of an undefined variable. /// A sequence of UTF-16 code units, with a prefix indicating the number of the code units, representing the name of an undefined variable.
/// </summary> /// </summary>
public readonly static int Undefined = 0x00444e55; public const int Undefined = 0x00444e55;
/// <summary> /// <summary>
/// Vector of a same constant-length type, with a suffix indicating the element type. /// Vector of a same constant-length type, with a suffix indicating the element type.
/// </summary> /// </summary>
public readonly static int Vector = 0x00434556; public const int Vector = 0x00434556;
} }
} }

View File

@@ -1,4 +1,5 @@
using System; using Cryville.Common.Collections;
using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@@ -27,7 +28,7 @@ namespace Cryville.Common.Pdt {
/// <item><term><c>0x1000</c></term><description>End of Key</description></item> /// <item><term><c>0x1000</c></term><description>End of Key</description></item>
/// </list> /// </list>
/// </remarks> /// </remarks>
readonly static int[] cm = new int[] { static readonly int[] cm = new int[] {
// 0 1 2 3 4 5 6 7 8 9 A B C D E F // 0 1 2 3 4 5 6 7 8 9 A B C D E F
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0001, 0x0000, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0001, 0x0000, 0x0000, 0x0001, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
@@ -54,15 +55,14 @@ namespace Cryville.Common.Pdt {
/// <param name="binder">The binder.</param> /// <param name="binder">The binder.</param>
/// <returns>The interpreted object.</returns> /// <returns>The interpreted object.</returns>
public static T Interpret<T>(string src, Binder binder) { public static T Interpret<T>(string src, Binder binder) {
return (T)new PdtInterpreter(src, typeof(T), binder).Interpret(); return (T)new PdtInterpreter(src, binder).Interpret(typeof(T));
} }
/// <summary> /// <summary>
/// The source string. /// The source string.
/// </summary> /// </summary>
public string Source { get; private set; } public string Source { get; private set; }
readonly Type _type; Binder _binder;
readonly Binder _binder;
/// <summary> /// <summary>
/// The current position in the string being parsed by the interpreter. /// The current position in the string being parsed by the interpreter.
/// </summary> /// </summary>
@@ -167,23 +167,27 @@ namespace Cryville.Common.Pdt {
/// Creates an instance of the <see cref="PdtInterpreter" /> class. /// Creates an instance of the <see cref="PdtInterpreter" /> class.
/// </summary> /// </summary>
/// <param name="src">The source string.</param> /// <param name="src">The source string.</param>
/// <param name="type">The destination type.</param>
/// <param name="binder">The binder. May be <c>null</c>.</param> /// <param name="binder">The binder. May be <c>null</c>.</param>
public PdtInterpreter(string src, Type type, Binder binder) { public PdtInterpreter(string src, Binder binder) {
Source = src; Source = src;
_type = type;
_binder = binder; _binder = binder;
if (_binder == null) }
_binder = BinderAttribute.CreateBinderOfType(_type); int[] m_formatVersion;
public int[] GetFormatVersion() {
if (m_formatVersion == null) InterpretDirectives();
return m_formatVersion;
} }
/// <summary> /// <summary>
/// Interprets the source to an object. /// Interprets the source to an object.
/// </summary> /// </summary>
/// <param name="type">The output type.</param>
/// <returns>The interpreted object.</returns> /// <returns>The interpreted object.</returns>
public object Interpret() { public object Interpret(Type type) {
try { try {
InterpretDirectives(); if (m_formatVersion == null) InterpretDirectives();
return InterpretObject(_type); if (_binder == null)
_binder = BinderAttribute.CreateBinderOfType(type);
return InterpretObject(type);
} }
catch (Exception ex) { catch (Exception ex) {
throw new PdtParsingException(this, ex); throw new PdtParsingException(this, ex);
@@ -201,7 +205,10 @@ namespace Cryville.Common.Pdt {
break; break;
case "format": case "format":
ws(); ws();
if (GetNumber() != "1") m_formatVersion = (from i in GetNumber().Split('.') select int.Parse(i)).ToArray();
if (m_formatVersion.Length == 0)
throw new FormatException("Invalid format version");
if (m_formatVersion[0] != 1)
throw new NotSupportedException("Format not supported"); throw new NotSupportedException("Format not supported");
flag = true; flag = true;
break; break;
@@ -226,6 +233,10 @@ namespace Cryville.Common.Pdt {
while (true) { while (true) {
try { ws(); } try { ws(); }
catch (IndexOutOfRangeException) { return result; } catch (IndexOutOfRangeException) { return result; }
if (cc == '}') {
GetChar();
return result;
}
object pkey = InterpretKey(type); object pkey = InterpretKey(type);
char c = GetChar(); char c = GetChar();
switch (c) { switch (c) {
@@ -245,13 +256,13 @@ namespace Cryville.Common.Pdt {
if (prop == null) throw new MissingMemberException(string.Format("The property \"{0}\" is not found", pkey)); if (prop == null) throw new MissingMemberException(string.Format("The property \"{0}\" is not found", pkey));
Type ptype = ReflectionHelper.GetMemberType(prop); Type ptype = ReflectionHelper.GetMemberType(prop);
if (flag) { if (flag) {
if (!typeof(IDictionary).IsAssignableFrom(ptype)) using (var collection = new PairCollection(ReflectionHelper.GetValue(prop, result))) {
throw new InvalidOperationException("Internal error: Element list is not a dictionary"); var ktype = ptype.GetGenericArguments()[0];
var ktype = ptype.GetGenericArguments()[0]; var vtype = ptype.GetGenericArguments()[1];
var vtype = ptype.GetGenericArguments()[1]; object key = _binder.ChangeType(pkey, ktype, null);
object key = _binder.ChangeType(pkey, ktype, null); object value = InterpretObject(vtype);
object value = InterpretObject(vtype); collection.Add(key, value);
((IDictionary)ReflectionHelper.GetValue(prop, result)).Add(key, value); }
} }
else ReflectionHelper.SetValue(prop, result, InterpretObject(ptype)); else ReflectionHelper.SetValue(prop, result, InterpretObject(ptype));
} }
@@ -274,13 +285,13 @@ namespace Cryville.Common.Pdt {
if (prop == null) throw new MissingMemberException(string.Format("The property \"{0}\" is not found", pkey)); if (prop == null) throw new MissingMemberException(string.Format("The property \"{0}\" is not found", pkey));
var ptype = ReflectionHelper.GetMemberType(prop); var ptype = ReflectionHelper.GetMemberType(prop);
if (flag) { if (flag) {
if (!typeof(IDictionary).IsAssignableFrom(ptype)) using (var collection = new PairCollection(ReflectionHelper.GetValue(prop, result))) {
throw new InvalidOperationException("Internal error: Property list is not a dictionary"); var ktype = ptype.GetGenericArguments()[0];
var ktype = ptype.GetGenericArguments()[0]; var vtype = ptype.GetGenericArguments()[1];
var vtype = ptype.GetGenericArguments()[1]; object key = _binder.ChangeType(pkey, ktype, null);
object key = _binder.ChangeType(pkey, ktype, null); object value = _binder.ChangeType(exp, vtype, null);
object value = _binder.ChangeType(exp, vtype, null); collection.Add(key, value);
((IDictionary)ReflectionHelper.GetValue(prop, result)).Add(key, value); }
} }
else { else {
object value = _binder.ChangeType(exp, ptype, null); object value = _binder.ChangeType(exp, ptype, null);
@@ -288,8 +299,6 @@ namespace Cryville.Common.Pdt {
} }
} }
break; break;
case '}':
return result;
default: default:
throw new InvalidOperationException("Internal error: Invalid key interpretation"); throw new InvalidOperationException("Internal error: Invalid key interpretation");
} }

View File

@@ -4,14 +4,14 @@ namespace Cryville.Common.Pdt {
/// <summary> /// <summary>
/// PDT operator. /// PDT operator.
/// </summary> /// </summary>
public unsafe abstract class PdtOperator { public abstract unsafe class PdtOperator {
byte* _prmem; byte* _prmem;
int _loadindex; int _loadindex;
readonly PdtVariableMemory[] _operands; readonly PdtVariableMemory[] _operands;
/// <summary> /// <summary>
/// The count of the operands loaded. /// The count of the operands loaded.
/// </summary> /// </summary>
protected int LoadedOperandCount { get { return _pc - _loadindex; } } protected int LoadedOperandCount { get; private set; }
/// <summary> /// <summary>
/// Gets the operand at the specified index. /// Gets the operand at the specified index.
/// </summary> /// </summary>
@@ -35,13 +35,13 @@ namespace Cryville.Common.Pdt {
} }
PdtEvaluatorBase _etor; PdtEvaluatorBase _etor;
bool _rfreq = true; bool _rfreq = true;
internal void Begin(PdtEvaluatorBase etor) { internal void Begin(PdtEvaluatorBase etor, int pc) {
_etor = etor; _etor = etor;
_loadindex = _pc; _loadindex = LoadedOperandCount = pc;
} }
internal void LoadOperand(PdtVariableMemory mem) { internal void LoadOperand(PdtVariableMemory mem) {
if (_loadindex == 0) return; if (--_loadindex >= _pc) return;
_operands[--_loadindex] = mem; _operands[_loadindex] = mem;
} }
internal void Call(byte* prmem, bool noset) { internal void Call(byte* prmem, bool noset) {
_prmem = prmem; _prmem = prmem;

View File

@@ -28,8 +28,8 @@ namespace Cryville.Common.Unity {
set { m_filter = value; } set { m_filter = value; }
} }
public Dictionary<string, string> m_presetPaths = new Dictionary<string, string>(); public IReadOnlyDictionary<string, string> m_presetPaths = new Dictionary<string, string>();
public Dictionary<string, string> PresetPaths { public IReadOnlyDictionary<string, string> PresetPaths {
get { return m_presetPaths; } get { return m_presetPaths; }
set { m_presetPaths = value; } set { m_presetPaths = value; }
} }

View File

@@ -3,6 +3,6 @@ using UnityEngine;
namespace Cryville.Common.Unity.UI { namespace Cryville.Common.Unity.UI {
public abstract class SetParameterBehaviour : StateMachineBehaviour { public abstract class SetParameterBehaviour : StateMachineBehaviour {
[SerializeField] protected string m_name; [SerializeField] protected string m_name;
public override abstract void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex); public abstract override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex);
} }
} }

View File

@@ -1,8 +0,0 @@
using System.Collections.Generic;
namespace Cryville.Crtr.Browsing {
public abstract class ExtensionInterface {
public abstract IEnumerable<ResourceConverter> GetResourceConverters();
public abstract IEnumerable<LocalResourceFinder> GetResourceFinders();
}
}

View File

@@ -0,0 +1,138 @@
using Cryville.Common;
using Cryville.Crtr.Extension;
using Mono.Cecil;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
namespace Cryville.Crtr.Browsing {
internal static class ExtensionManager {
static readonly Dictionary<string, List<ResourceConverter>> _converters
= new Dictionary<string, List<ResourceConverter>>();
public static IEnumerable<string> GetSupportedFormats() {
return _converters.Keys;
}
public static bool TryGetConverters(string extension, out IEnumerable<ResourceConverter> converters) {
List<ResourceConverter> outResult;
bool result = _converters.TryGetValue(extension, out outResult);
converters = outResult;
return result;
}
static readonly Dictionary<string, string> _localRes
= new Dictionary<string, string>();
public static IReadOnlyDictionary<string, string> GetLocalResourcePaths() {
return _localRes;
}
public static void Init(string rootPath) {
LoadExtension(typeof(Extensions.Umg.Extension));
var asms = AppDomain.CurrentDomain.GetAssemblies().Select(a => a.GetName().Name).ToHashSet();
var modules = new Queue<ModuleItem>();
var extensionDir = new DirectoryInfo(Path.Combine(rootPath, "extensions"));
if (extensionDir.Exists) {
foreach (var extension in extensionDir.EnumerateFiles("*.dll")) {
try {
modules.Enqueue(new ModuleItem(extension.OpenRead()));
}
catch (Exception ex) {
Logger.Log("main", 4, "Extension", "Failed to load DLL {0}: {1}", extension, ex);
}
}
}
int refCounter = 0;
while (modules.Count > 0 && refCounter < modules.Count) {
var module = modules.Dequeue();
bool flag = false;
foreach (var reference in module.Definition.AssemblyReferences) {
if (!asms.Contains(reference.Name)) {
flag = true;
break;
}
}
if (flag) {
modules.Enqueue(module);
refCounter++;
}
else {
try {
var stream = module.Stream;
stream.Seek(0, SeekOrigin.Begin);
var buf = new byte[stream.Length];
stream.Read(buf, 0, buf.Length);
var asm = Assembly.Load(buf);
if (asm == null) throw new TypeLoadException("Failed to load the module");
asms.Add(asm.GetName().Name);
foreach (var type in asm.GetTypes()) {
if (typeof(ExtensionInterface).IsAssignableFrom(type)) {
LoadExtension(type);
}
}
Logger.Log("main", 1, "Extension", "Loaded module {0}", module.Definition.Name);
}
catch (Exception ex) {
Logger.Log("main", 4, "Extension", "An error occured while trying to load module {0}: {1}", module.Definition.Name, ex);
}
finally {
module.Definition.Dispose();
module.Stream.Dispose();
refCounter = 0;
}
}
}
var missingList = new List<string>();
while (modules.Count > 0) {
missingList.Clear();
var module = modules.Dequeue();
foreach (var reference in module.Definition.AssemblyReferences) {
if (!asms.Contains(reference.Name)) {
missingList.Add(reference.Name);
}
}
Logger.Log("main", 4, "Extension", "Could not load the module {0} because the following dependencies were missing: {1}", module.Definition.Name, missingList.Aggregate((current, next) => current + ", " + next));
module.Definition.Dispose();
module.Stream.Dispose();
}
}
struct ModuleItem {
public ModuleDefinition Definition { get; set; }
public FileStream Stream { get; set; }
public ModuleItem(FileStream stream) {
Stream = stream;
Definition = ModuleDefinition.ReadModule(stream);
}
}
static void LoadExtension(Type type) {
try {
var extension = (ExtensionInterface)Activator.CreateInstance(type);
var l1 = extension.GetResourceConverters();
if (l1 != null) {
foreach (var c in l1) {
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 l2 = extension.GetResourceFinders();
if (l2 != null) {
foreach (var f in l2) {
var name = f.Name;
var path = f.GetRootPath();
if (name != null && path != null) _localRes.Add(name, path);
}
}
Logger.Log("main", 1, "Extension", "Loaded extension {0}", type);
}
catch (Exception ex) {
Logger.Log("main", 4, "Extension", "Failed to load extension {0}: {1}", type, ex);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a9ea11165e6269b488f916982507a2af
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -12,6 +12,6 @@ namespace Cryville.Crtr.Browsing {
bool ImportItemFrom(string path); bool ImportItemFrom(string path);
string[] GetSupportedFormats(); string[] GetSupportedFormats();
Dictionary<string, string> GetPresetPaths(); IReadOnlyDictionary<string, string> GetPresetPaths();
} }
} }

View File

@@ -1,5 +1,7 @@
using Cryville.Common; using Cryville.Common;
using Cryville.Common.Unity; using Cryville.Common.Unity;
using Cryville.Crtr.Extension;
using Cryville.Crtr.Extensions.Umg;
using Newtonsoft.Json; using Newtonsoft.Json;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -15,49 +17,13 @@ namespace Cryville.Crtr.Browsing {
private DirectoryInfo[] items = new DirectoryInfo[0]; private DirectoryInfo[] items = new DirectoryInfo[0];
public string[] CurrentDirectory { get; private set; } public string[] CurrentDirectory { get; private set; }
static readonly Dictionary<string, List<ResourceConverter>> converters static bool _init;
= new Dictionary<string, List<ResourceConverter>>();
static readonly Dictionary<string, string> localRes
= new Dictionary<string, string>();
public LegacyResourceManager(string rootPath) { public LegacyResourceManager(string rootPath) {
_rootPath = rootPath; _rootPath = rootPath;
} if (!_init) {
_init = true;
static LegacyResourceManager() { ExtensionManager.Init(rootPath);
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) {
foreach (var type in asm.GetTypes()) {
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);
}
}
} }
} }
@@ -149,14 +115,15 @@ namespace Cryville.Crtr.Browsing {
public bool ImportItemFrom(string path) { public bool ImportItemFrom(string path) {
var file = new FileInfo(path); var file = new FileInfo(path);
if (!converters.ContainsKey(file.Extension)) return false; IEnumerable<ResourceConverter> converters;
foreach (var converter in converters[file.Extension]) { if (!ExtensionManager.TryGetConverters(file.Extension, out converters)) return false;
foreach (var converter in converters) {
IEnumerable<Resource> resources = null; IEnumerable<Resource> resources = null;
try { try {
resources = converter.ConvertFrom(file); resources = converter.ConvertFrom(file);
} }
catch (Exception ex) { catch (Exception ex) {
LogAndPopup(4, ex.Message); LogAndPopupExtra(4, ex, "Failed to import resource: {0}", ex.Message);
return false; return false;
} }
foreach (var res in resources) { foreach (var res in resources) {
@@ -168,7 +135,7 @@ namespace Cryville.Crtr.Browsing {
var dir = new DirectoryInfo(_rootPath + "/charts/" + res.Name); var dir = new DirectoryInfo(_rootPath + "/charts/" + res.Name);
if (!dir.Exists) dir.Create(); if (!dir.Exists) dir.Create();
using (var writer = new StreamWriter(dir.FullName + "/.json")) { using (var writer = new StreamWriter(dir.FullName + "/.json")) {
writer.Write(JsonConvert.SerializeObject(tres.Main, Game.GlobalJsonSerializerSettings)); writer.Write(JsonConvert.SerializeObject(ConvertChartData(tres.Main), Game.GlobalJsonSerializerSettings));
} }
using (var writer = new StreamWriter(dir.FullName + "/.umgc")) { using (var writer = new StreamWriter(dir.FullName + "/.umgc")) {
tres.Meta.data = ""; tres.Meta.data = "";
@@ -219,12 +186,89 @@ namespace Cryville.Crtr.Browsing {
Popup.Create(msg); Popup.Create(msg);
} }
public string[] GetSupportedFormats() { void LogAndPopupExtra(int level, object extraLog, string format, params object[] args) {
return converters.Keys.ToArray(); var msg = string.Format(format, args);
Logger.Log("main", level, "Resource", "{0}\n{1}", msg, extraLog);
Popup.Create(msg);
} }
public Dictionary<string, string> GetPresetPaths() { public string[] GetSupportedFormats() {
return localRes; return ExtensionManager.GetSupportedFormats().ToArray();
}
public IReadOnlyDictionary<string, string> GetPresetPaths() {
return ExtensionManager.GetLocalResourcePaths();
}
static Chart ConvertChartData(ChartData i) {
return new Chart {
endtime = ConvertBeatTime(i.endtime),
format = i.format,
groups = ConvertGroups(i.groups),
motions = ConvertMotions(i.motions),
ruleset = i.ruleset,
sigs = ConvertSignatures(i.sigs),
sounds = ConvertSounds(i.sounds),
time = ConvertBeatTime(i.time),
};
}
static BeatTime? ConvertBeatTime(Extension.BeatTime? value) {
if (value == null) return null;
return new BeatTime(value.Value.b, value.Value.n, value.Value.d);
}
static List<Chart.Group> ConvertGroups(List<ChartData.Group> l) {
return l.Select(i => new Chart.Group {
endtime = ConvertBeatTime(i.endtime),
motions = ConvertMotions(i.motions),
notes = ConvertNotes(i.notes),
time = ConvertBeatTime(i.time),
tracks = ConvertTracks(i.tracks),
}).ToList();
}
static List<Chart.Judge> ConvertJudges(List<ChartData.Judge> l) {
return l.Select(i => new Chart.Judge {
endtime = ConvertBeatTime(i.endtime),
name = i.name,
time = ConvertBeatTime(i.time),
}).ToList();
}
static List<Chart.Motion> ConvertMotions(List<ChartData.Motion> l) {
return l.Select(i => new Chart.Motion {
endtime = ConvertBeatTime(i.endtime),
motion = i.motion,
sumfix = i.sumfix,
time = ConvertBeatTime(i.time),
}).ToList();
}
static List<Chart.Note> ConvertNotes(List<ChartData.Note> l) {
return l.Select(i => new Chart.Note {
endtime = ConvertBeatTime(i.endtime),
judges = ConvertJudges(i.judges),
motions = ConvertMotions(i.motions),
time = ConvertBeatTime(i.time),
}).ToList();
}
static List<Chart.Signature> ConvertSignatures(List<ChartData.Signature> l) {
return l.Select(i => new Chart.Signature {
endtime = ConvertBeatTime(i.endtime),
tempo = i.tempo,
time = ConvertBeatTime(i.time),
}).ToList();
}
static List<Chart.Sound> ConvertSounds(List<ChartData.Sound> l) {
return l.Select(i => new Chart.Sound {
endtime = ConvertBeatTime(i.endtime),
id = i.id,
offset = i.offset,
time = ConvertBeatTime(i.time),
}).ToList();
}
static List<Chart.Track> ConvertTracks(List<ChartData.Track> l) {
return l.Select(i => new Chart.Track {
endtime = ConvertBeatTime(i.endtime),
motions = ConvertMotions(i.motions),
time = ConvertBeatTime(i.time),
}).ToList();
} }
} }
} }

View File

@@ -1,6 +0,0 @@
namespace Cryville.Crtr.Browsing {
public abstract class LocalResourceFinder {
public abstract string Name { get; }
public abstract string GetRootPath();
}
}

View File

@@ -9,11 +9,11 @@ namespace Cryville.Crtr.Browsing {
public override object Value { public override object Value {
get { get {
float s_value = GetDisplayValue(); float s_value = GetDisplayValue();
return IntegerMode ? (object)(int)s_value : (object)s_value; return IntegerMode ? (int)s_value : (object)s_value;
} }
set { set {
if (value is double) m_value = (double)value; if (value is double) m_value = (double)value;
else m_value = IntegerMode ? (double)(int)value : (double)(float)value; else m_value = IntegerMode ? (int)value : (double)(float)value;
float s_value = GetDisplayValue(); float s_value = GetDisplayValue();
m_text.text = s_value.ToString(); m_text.text = s_value.ToString();
if (Range != null && MaxStep == 0) { if (Range != null && MaxStep == 0) {

View File

@@ -1,7 +1,7 @@
using Cryville.Common; using Cryville.Common;
using Cryville.Common.Unity.UI; using Cryville.Common.Unity.UI;
using Cryville.Crtr.Config; using Cryville.Crtr.Config;
using Newtonsoft.Json; using Cryville.Crtr.Extension;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
using UnityEngine.SceneManagement; using UnityEngine.SceneManagement;
@@ -94,24 +94,4 @@ namespace Cryville.Crtr.Browsing {
public AsyncDelivery<Texture2D> Cover { get; set; } public AsyncDelivery<Texture2D> Cover { get; set; }
public ChartMeta Meta { get; set; } public ChartMeta Meta { get; set; }
} }
#pragma warning disable IDE1006
public class MetaInfo {
public string name { get; set; }
public string author { get; set; }
[JsonRequired]
public string data { get; set; }
}
public class SongMetaInfo {
public string name { get; set; }
public string author { get; set; }
}
public class ChartMeta : MetaInfo {
public SongMetaInfo song { get; set; }
public float length { get; set; }
public string ruleset { get; set; }
public int note_count { get; set; }
public string cover { get; set; }
}
#pragma warning restore IDE1006
} }

View File

@@ -1,79 +0,0 @@
using Cryville.Common;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.IO;
namespace Cryville.Crtr.Browsing {
public abstract class ResourceConverter {
public abstract string[] GetSupportedFormats();
public abstract IEnumerable<Resource> ConvertFrom(FileInfo file);
}
public abstract class Resource {
protected Resource(string name) {
Name = StringUtils.EscapeFileName(name);
}
public string Name { get; private set; }
public abstract bool Valid { get; }
public override string ToString() {
return string.Format("{0} ({1})", Name, ReflectionHelper.GetSimpleName(GetType()));
}
}
public class RawChartResource : Resource {
public RawChartResource(string name, Chart main, ChartMeta meta) : base(name) {
Main = main; Meta = meta;
}
public Chart Main { get; private set; }
public ChartMeta Meta { get; private set; }
public override bool Valid { get { return true; } }
}
public abstract class FileResource : Resource {
public FileResource(string name, FileInfo master) : base(name) {
Master = master;
Attachments = new List<FileInfo>();
}
public FileInfo Master { get; private set; }
public List<FileInfo> Attachments { get; private set; }
public override bool Valid {
get {
if (!Master.Exists) return false;
foreach (var file in Attachments) {
if (!file.Exists) return false;
}
return true;
}
}
}
public class ChartResource : FileResource {
public ChartResource(string name, FileInfo master) : base(name, master) {
using (var reader = new StreamReader(master.FullName)) {
var meta = JsonConvert.DeserializeObject<ChartMeta>(reader.ReadToEnd());
Attachments.Add(new FileInfo(Path.Combine(master.Directory.FullName, meta.data + ".json")));
if (meta.cover != null) Attachments.Add(new FileInfo(Path.Combine(master.Directory.FullName, meta.cover)));
}
}
}
public class SongResource : FileResource {
public SongResource(string name, FileInfo master) : base(name, master) { }
}
public class RulesetResource : FileResource {
public RulesetResource(string name, FileInfo master) : base(name, master) {
using (var reader = new StreamReader(master.FullName)) {
var meta = JsonConvert.DeserializeObject<Ruleset>(reader.ReadToEnd());
Attachments.Add(new FileInfo(Path.Combine(master.Directory.FullName, meta.data + ".pdt")));
}
}
}
public class SkinResource : FileResource {
public string RulesetName { get; private set; }
public SkinResource(string name, FileInfo master) : base(name, master) {
using (var reader = new StreamReader(master.FullName)) {
var meta = JsonConvert.DeserializeObject<Skin>(reader.ReadToEnd());
RulesetName = meta.ruleset;
Attachments.Add(new FileInfo(Path.Combine(master.Directory.FullName, meta.data + ".pdt")));
foreach (var frame in meta.frames) {
Attachments.Add(new FileInfo(Path.Combine(master.Directory.FullName, frame)));
}
}
}
}
}

View File

@@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: 2546fb1d514348842a14a03531be192d
timeCreated: 1637982768
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,20 +0,0 @@
using Newtonsoft.Json;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace Cryville.Crtr.Browsing {
public class SkinResourceImporter : ResourceConverter {
static readonly string[] SUPPORTED_FORMATS = { ".umgs" };
public override string[] GetSupportedFormats() {
return SUPPORTED_FORMATS;
}
public override IEnumerable<Resource> ConvertFrom(FileInfo file) {
using (StreamReader reader = new StreamReader(file.FullName, Encoding.UTF8)) {
var data = JsonConvert.DeserializeObject<Skin>(reader.ReadToEnd());
return new Resource[] { new SkinResource(data.name, file) };
}
}
}
}

View File

@@ -6,6 +6,7 @@ using System.ComponentModel;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using UnsafeIL;
namespace Cryville.Crtr { namespace Cryville.Crtr {
[JsonConverter(typeof(BeatTimeConverter))] [JsonConverter(typeof(BeatTimeConverter))]
@@ -154,6 +155,10 @@ namespace Cryville.Crtr {
protected ChartEvent() { protected ChartEvent() {
PropSrcs = new Dictionary<int, PropSrc>(); PropSrcs = new Dictionary<int, PropSrc>();
PropOps = new Dictionary<int, PropOp>(); PropOps = new Dictionary<int, PropOp>();
SubmitPropSrc("event", new PropSrc.Float(() => {
int hash = GetHashCode();
return Unsafe.As<int, float>(ref hash);
}));
SubmitPropSrc("long", new PropSrc.Boolean(() => IsLong)); SubmitPropSrc("long", new PropSrc.Boolean(() => IsLong));
SubmitPropSrc("time", new PropSrc.BeatTime(() => time.Value)); SubmitPropSrc("time", new PropSrc.BeatTime(() => time.Value));
SubmitPropSrc("endtime", new PropSrc.BeatTime(() => endtime.Value)); SubmitPropSrc("endtime", new PropSrc.BeatTime(() => endtime.Value));
@@ -320,7 +325,7 @@ namespace Cryville.Crtr {
else { else {
AbsoluteValue = Vector.Construct(registry.Type, m.Groups[11].Value); AbsoluteValue = Vector.Construct(registry.Type, m.Groups[11].Value);
} }
SubmitPropSrc("value", VectorSrc.Construct(() => { SubmitPropSrc("value", new VectorSrc(() => {
if (RelativeNode != null) return RelativeNode.Value; if (RelativeNode != null) return RelativeNode.Value;
else return AbsoluteValue; else return AbsoluteValue;
})); }));

View File

@@ -16,7 +16,6 @@ using UnityEngine;
using UnityEngine.Networking; using UnityEngine.Networking;
using UnityEngine.SceneManagement; using UnityEngine.SceneManagement;
using UnityEngine.Scripting; using UnityEngine.Scripting;
using UnityEngine.UI;
using diag = System.Diagnostics; using diag = System.Diagnostics;
using Logger = Cryville.Common.Logger; using Logger = Cryville.Common.Logger;
@@ -25,7 +24,7 @@ namespace Cryville.Crtr {
#region Fields #region Fields
Chart chart; Chart chart;
Skin skin; Skin skin;
PdtSkin pskin; public static PdtSkin pskin;
Ruleset ruleset; Ruleset ruleset;
PdtRuleset pruleset; PdtRuleset pruleset;
Dictionary<string, Texture2D> texs; Dictionary<string, Texture2D> texs;
@@ -43,14 +42,14 @@ namespace Cryville.Crtr {
EventBus bbus; EventBus bbus;
EventBus tbus; EventBus tbus;
EventBus nbus; EventBus nbus;
InputProxy inputProxy;
Judge judge; Judge judge;
public static EffectManager effectManager;
bool started = false; bool started = false;
static bool initialized; static bool initialized;
static Text logs; TextMeshProUGUI logs;
TextMeshProUGUI status; TextMeshProUGUI status;
readonly TargetString statusstr = new TargetString();
readonly StringBuffer statusbuf = new StringBuffer();
static Vector2 screenSize; static Vector2 screenSize;
public static Rect hitRect; public static Rect hitRect;
@@ -71,15 +70,15 @@ namespace Cryville.Crtr {
public static Dictionary<Identifier, MotionRegistry> motionRegistry = new Dictionary<Identifier, MotionRegistry>(); public static Dictionary<Identifier, MotionRegistry> motionRegistry = new Dictionary<Identifier, MotionRegistry>();
public static PdtEvaluator etor; public static PdtEvaluator etor;
InputProxy inputProxy;
#endregion #endregion
#region MonoBehaviour #region MonoBehaviour
void Start() { void Start() {
d_addLogEntry = new Action<int, string, string>(AddLogEntry);
var logobj = GameObject.Find("Logs"); var logobj = GameObject.Find("Logs");
if (logobj != null) if (logobj != null)
logs = logobj.GetComponent<Text>(); logs = logobj.GetComponent<TextMeshProUGUI>();
if (!initialized) { if (!initialized) {
Game.Init(); Game.Init();
GenericResources.LoadDefault(); GenericResources.LoadDefault();
@@ -162,6 +161,8 @@ namespace Cryville.Crtr {
tbus.ForwardStepByTime(renderDist, step); tbus.ForwardStepByTime(renderDist, step);
tbus.EndGraphicalUpdate(); tbus.EndGraphicalUpdate();
UnityEngine.Profiling.Profiler.EndSample(); UnityEngine.Profiling.Profiler.EndSample();
effectManager.Tick(cbus.Time);
} }
catch (Exception ex) { catch (Exception ex) {
Game.LogException("Game", "An error occured while playing", ex); Game.LogException("Game", "An error occured while playing", ex);
@@ -174,10 +175,21 @@ namespace Cryville.Crtr {
string url = texLoader.url; string url = texLoader.url;
string name = StringUtils.TrimExt(url.Substring(url.LastIndexOfAny(new char[] {'/', '\\'}) + 1)); string name = StringUtils.TrimExt(url.Substring(url.LastIndexOfAny(new char[] {'/', '\\'}) + 1));
#if UNITY_5_4_OR_NEWER #if UNITY_5_4_OR_NEWER
if (texHandler.isDone) { if (texLoader.isDone) {
var tex = texHandler.texture; if (texHandler.isDone) {
tex.wrapMode = TextureWrapMode.Clamp; var tex = texHandler.texture;
texs.Add(name, tex); tex.wrapMode = TextureWrapMode.Clamp;
if (frames.ContainsKey(name)) {
Logger.Log("main", 3, "Load/Prehandle", "Duplicated texture name: {0}", name);
}
else {
frames.Add(name, new SpriteFrame(tex));
}
texs.Add(name, tex);
}
else {
Logger.Log("main", 4, "Load/Prehandle", "Unable to load texture: {0}", name);
}
texLoader.Dispose(); texLoader.Dispose();
texHandler.Dispose(); texHandler.Dispose();
texLoader = null; texLoader = null;
@@ -192,14 +204,14 @@ namespace Cryville.Crtr {
} }
#endif #endif
} }
if (texLoader == null) if (texLoader == null) {
if (texLoadQueue.Count > 0) { if (texLoadQueue.Count > 0) {
#if UNITY_5_4_OR_NEWER #if UNITY_5_4_OR_NEWER
texHandler = new DownloadHandlerTexture(); texHandler = new DownloadHandlerTexture();
texLoader = new UnityWebRequest(Game.FileProtocolPrefix + texLoadQueue.Dequeue(), "GET", texHandler, null); texLoader = new UnityWebRequest(Game.FileProtocolPrefix + texLoadQueue.Dequeue(), "GET", texHandler, null);
texLoader.SendWebRequest(); texLoader.SendWebRequest();
#else #else
texLoader = new WWW(Game.FileProtocolPrefix + texLoadQueue.Dequeue()); texLoader = new WWW(Game.FileProtocolPrefix + texLoadQueue.Dequeue());
#endif #endif
} }
else if (!texloaddone) { else if (!texloaddone) {
@@ -207,6 +219,7 @@ namespace Cryville.Crtr {
texloadtimer.Stop(); texloadtimer.Stop();
Logger.Log("main", 1, "Load/MainThread", "Main thread done ({0}ms)", texloadtimer.Elapsed.TotalMilliseconds); Logger.Log("main", 1, "Load/MainThread", "Main thread done ({0}ms)", texloadtimer.Elapsed.TotalMilliseconds);
} }
}
if (!loadThread.IsAlive) { if (!loadThread.IsAlive) {
if (threadException != null) { if (threadException != null) {
Logger.Log("main", 4, "Load/MainThread", "Load failed"); Logger.Log("main", 4, "Load/MainThread", "Load failed");
@@ -222,25 +235,46 @@ namespace Cryville.Crtr {
} }
} }
} }
readonly TargetString statusstr = new TargetString();
readonly StringBuffer statusbuf = new StringBuffer();
readonly TargetString logsstr = new TargetString();
readonly StringBuffer logsbuf = new StringBuffer();
readonly List<string> logEntries = new List<string>();
int logsLength = 0;
Action<int, string, string> d_addLogEntry;
void AddLogEntry(int level, string module, string msg) {
string color;
switch (level) {
case 0: color = "#888888"; break;
case 1: color = "#bbbbbb"; break;
case 2: color = "#0088ff"; break;
case 3: color = "#ffff00"; break;
case 4: color = "#ff0000"; break;
case 5: color = "#bb0000"; break;
default: color = "#ff00ff"; break;
}
var l = string.Format(
"\n<color={1}bb><{2}> {3}</color>",
DateTime.UtcNow.ToString("s"), color, module, msg
);
logEntries.Add(l);
logsLength += l.Length;
}
void LogUpdate() { void LogUpdate() {
string _logs = logs.text; logsbuf.Clear();
Game.MainLogger.Enumerate((level, module, msg) => { Game.MainLogger.Enumerate(d_addLogEntry);
string color; while (logsLength >= 4096) {
switch (level) { logsLength -= logEntries[0].Length;
case 0: color = "#888888"; break; logEntries.RemoveAt(0);
case 1: color = "#bbbbbb"; break; }
case 2: color = "#0088ff"; break; foreach (var l in logEntries) {
case 3: color = "#ffff00"; break; logsbuf.Append(l);
case 4: color = "#ff0000"; break; }
case 5: color = "#bb0000"; break; logsstr.Length = logsbuf.Count;
default: color = "#ff00ff"; break; var larr = logsstr.TrustedAsArray();
} logsbuf.CopyTo(0, larr, 0, logsbuf.Count);
_logs += string.Format( logs.SetText(larr, 0, logsbuf.Count);
"\r\n<color={1}bb><{2}> {3}</color>",
DateTime.UtcNow.ToString("s"), color, module, msg
);
});
logs.text = _logs.Substring(Mathf.Max(0, _logs.IndexOf('\n', Mathf.Max(0, _logs.Length - 4096))));
statusbuf.Clear(); statusbuf.Clear();
statusbuf.AppendFormat( statusbuf.AppendFormat(
"FPS: i{0:0} / s{1:0}\nSMem: {2:N0} / {3:N0}\nIMem: {4:N0} / {5:N0}", "FPS: i{0:0} / s{1:0}\nSMem: {2:N0} / {3:N0}\nIMem: {4:N0} / {5:N0}",
@@ -281,9 +315,9 @@ namespace Cryville.Crtr {
} }
} }
statusstr.Length = statusbuf.Count; statusstr.Length = statusbuf.Count;
var arr = statusstr.TrustedAsArray(); var sarr = statusstr.TrustedAsArray();
statusbuf.CopyTo(0, arr, 0, statusbuf.Count); statusbuf.CopyTo(0, sarr, 0, statusbuf.Count);
status.SetText(arr, 0, statusbuf.Count); status.SetText(sarr, 0, statusbuf.Count);
} }
#endregion #endregion
@@ -313,6 +347,8 @@ namespace Cryville.Crtr {
bool logEnabled = true; bool logEnabled = true;
public void ToggleLogs() { public void ToggleLogs() {
logEntries.Clear();
logsLength = 0;
logs.text = ""; logs.text = "";
status.SetText(""); status.SetText("");
logEnabled = !logEnabled; logEnabled = !logEnabled;
@@ -424,16 +460,6 @@ namespace Cryville.Crtr {
try { try {
diag::Stopwatch timer = new diag::Stopwatch(); diag::Stopwatch timer = new diag::Stopwatch();
timer.Reset(); timer.Start(); timer.Reset(); timer.Start();
Logger.Log("main", 0, "Load/Prehandle", "Initializing textures");
foreach (var t in texs) {
if (frames.ContainsKey(t.Key)) {
Logger.Log("main", 3, "Load/Prehandle", "Duplicated texture name: {0}", t.Key);
continue;
}
var f = new SpriteFrame(t.Value);
f.Init();
frames.Add(t.Key, f);
}
Logger.Log("main", 0, "Load/Prehandle", "Prehandling (iteration 2)"); Logger.Log("main", 0, "Load/Prehandle", "Prehandling (iteration 2)");
cbus.BroadcastPreInit(); cbus.BroadcastPreInit();
Logger.Log("main", 0, "Load/Prehandle", "Prehandling (iteration 3)"); Logger.Log("main", 0, "Load/Prehandle", "Prehandling (iteration 3)");
@@ -447,15 +473,18 @@ namespace Cryville.Crtr {
Logger.Log("main", 0, "Load/Prehandle", "Cleaning up"); Logger.Log("main", 0, "Load/Prehandle", "Cleaning up");
GC.Collect(); GC.Collect();
if (disableGC) GarbageCollector.GCMode = GarbageCollector.Mode.Disabled; if (disableGC) GarbageCollector.GCMode = GarbageCollector.Mode.Disabled;
cbus.ForwardByTime(startOffset);
bbus.ForwardByTime(startOffset);
timer.Stop(); timer.Stop();
Logger.Log("main", 1, "Load/Prehandle", "Prehandling done ({0}ms)", timer.Elapsed.TotalMilliseconds); Logger.Log("main", 1, "Load/Prehandle", "Prehandling done ({0}ms)", timer.Elapsed.TotalMilliseconds);
if (Settings.Default.ClearLogOnPlay) { if (Settings.Default.ClearLogOnPlay) {
logs.text = ""; logEntries.Clear();
logsLength = 0;
Game.MainLogger.Enumerate((level, module, msg) => { }); Game.MainLogger.Enumerate((level, module, msg) => { });
logs.text = "";
} }
Game.AudioSequencer.Playing = true; Game.AudioSequencer.Playing = true;
atime0 = Game.AudioClient.BufferPosition; atime0 = Game.AudioClient.BufferPosition;
Thread.Sleep((int)((atime0 - Game.AudioClient.Position) * 1000));
inputProxy.SyncTime(cbus.Time); inputProxy.SyncTime(cbus.Time);
started = true; started = true;
} }
@@ -476,6 +505,9 @@ namespace Cryville.Crtr {
if (tbus != null) { tbus.Dispose(); tbus = null; } if (tbus != null) { tbus.Dispose(); tbus = null; }
if (bbus != null) { bbus.Dispose(); bbus = null; } if (bbus != null) { bbus.Dispose(); bbus = null; }
if (cbus != null) { cbus.Dispose(); cbus.DisposeAll(); cbus = null; } if (cbus != null) { cbus.Dispose(); cbus.DisposeAll(); cbus = null; }
effectManager.Dispose();
effectManager = null;
etor = null;
Logger.Log("main", 1, "Game", "Stopped"); Logger.Log("main", 1, "Game", "Stopped");
} }
catch (Exception ex) { catch (Exception ex) {
@@ -559,7 +591,7 @@ namespace Cryville.Crtr {
inputProxy = new InputProxy(pruleset, judge); inputProxy = new InputProxy(pruleset, judge);
inputProxy.LoadFrom(_rscfg.inputs); inputProxy.LoadFrom(_rscfg.inputs);
if (!inputProxy.IsCompleted) { if (!inputProxy.IsCompleted()) {
throw new ArgumentException("Input config not completed\nPlease complete the input settings"); throw new ArgumentException("Input config not completed\nPlease complete the input settings");
} }
@@ -617,6 +649,7 @@ namespace Cryville.Crtr {
skin.LoadPdt(dir); skin.LoadPdt(dir);
pskin = skin.Root; pskin = skin.Root;
pskin.Optimize(etor); pskin.Optimize(etor);
effectManager = new EffectManager(pskin);
} }
#endregion #endregion
} }

View File

@@ -1,12 +1,21 @@
using System; using System;
using UnityEngine;
namespace Cryville.Crtr.Components { namespace Cryville.Crtr.Components {
[DisallowMultipleComponent]
public abstract class MeshBase : SkinComponent { public abstract class MeshBase : SkinComponent {
public MeshBase() { public MeshBase() {
SubmitProperty("color", new PropOp.Color(v => Color = v));
SubmitProperty("opacity", new PropOp.Float(v => {
var c = Color;
c.a *= v;
Color = c;
}));
SubmitProperty("zindex", new PropOp.Integer(v => ZIndex = (short)v)); SubmitProperty("zindex", new PropOp.Integer(v => ZIndex = (short)v));
} }
protected MeshWrapper mesh = new MeshWrapper(); protected MeshWrapper mesh = new MeshWrapper();
protected Material[] materials;
short _zindex; short _zindex;
public short ZIndex { public short ZIndex {
@@ -22,9 +31,36 @@ namespace Cryville.Crtr.Components {
} }
protected void UpdateZIndex() { protected void UpdateZIndex() {
if (!mesh.Initialized) return; if (!mesh.Initialized) return;
foreach (var mat in mesh.Renderer.materials) { foreach (var mat in materials) {
mat.renderQueue = _zindex; mat.renderQueue = _zindex;
} }
} }
Color _color = Color.white;
public Color Color {
get { return _color; }
set {
_color = value;
UpdateColor();
}
}
protected void UpdateColor() {
if (!mesh.Initialized) return;
foreach (var mat in materials) {
mat.color = _color;
}
}
protected override void OnDestroy() {
DestroyMaterials();
mesh.Destroy();
}
protected void DestroyMaterials() {
if (materials == null) return;
foreach (var mat in materials) {
Material.Destroy(mat);
}
}
} }
} }

View File

@@ -19,11 +19,7 @@ namespace Cryville.Crtr.Components {
public SectionalGameObject() { public SectionalGameObject() {
SubmitProperty("partial", new PropOp.Boolean(v => part = Part.idle)); SubmitProperty("partial", new PropOp.Boolean(v => part = Part.idle));
SubmitProperty("part", new PropOp.Enum<Part>(v => part = v, v => (Part)v), 2); SubmitProperty("part", new PropOp.Enum<Part>(v => part = v, v => (Part)v), 1);
}
protected override void OnDestroy() {
mesh.Destroy();
} }
public override void Init() { public override void Init() {
@@ -67,7 +63,7 @@ namespace Cryville.Crtr.Components {
SubmitProperty("head", new PropOp.String(v => head.FrameName = v)); SubmitProperty("head", new PropOp.String(v => head.FrameName = v));
SubmitProperty("body", new PropOp.String(v => body.FrameName = v)); SubmitProperty("body", new PropOp.String(v => body.FrameName = v));
SubmitProperty("tail", new PropOp.String(v => tail.FrameName = v)); SubmitProperty("tail", new PropOp.String(v => tail.FrameName = v));
SubmitProperty("shape", new op_set_shape(this), 2); SubmitProperty("shape", new op_set_shape(this), 1);
} }
#pragma warning disable IDE1006 #pragma warning disable IDE1006
@@ -76,7 +72,7 @@ namespace Cryville.Crtr.Components {
public op_set_shape(PolygonSGO self) : base(1) { public op_set_shape(PolygonSGO self) : base(1) {
_self = self; _self = self;
} }
protected unsafe override void Execute() { protected override unsafe void Execute() {
var o = GetOperand(0); var o = GetOperand(0);
if (o.Type != PdtInternalType.Vector) throw new ArgumentException("Not a vector"); if (o.Type != PdtInternalType.Vector) throw new ArgumentException("Not a vector");
_self._shapeLength = (o.Length - sizeof(int)) / sizeof(Vector2); _self._shapeLength = (o.Length - sizeof(int)) / sizeof(Vector2);
@@ -103,7 +99,6 @@ namespace Cryville.Crtr.Components {
public SpriteInfo body = new SpriteInfo(); public SpriteInfo body = new SpriteInfo();
public SpriteInfo tail = new SpriteInfo(); public SpriteInfo tail = new SpriteInfo();
Material[] mats;
List<Vector3> vertices; List<Vector3> vertices;
List<float> lengths; List<float> lengths;
float sumLength = 0; float sumLength = 0;
@@ -112,23 +107,25 @@ namespace Cryville.Crtr.Components {
base.Init(); base.Init();
mesh.Init(transform); mesh.Init(transform);
mats = mesh.Renderer.materials = new Material[] { mesh.NewMaterial, mesh.NewMaterial, mesh.NewMaterial }; mesh.Renderer.sharedMaterials = materials = new Material[] {
head.Bind(mats[0]); MeshWrapper.NewMaterial(),
body.Bind(mats[1]); MeshWrapper.NewMaterial(),
tail.Bind(mats[2]); MeshWrapper.NewMaterial(),
};
head.Bind(materials[0]);
body.Bind(materials[1]);
tail.Bind(materials[2]);
UpdateZIndex(); UpdateZIndex();
} }
protected override void OnDestroy() { protected override void OnDestroy() {
base.OnDestroy();
Reset();
foreach (var m in mats) Material.Destroy(m);
if (_shape != null) _shapePool.Return(_shape); if (_shape != null) _shapePool.Return(_shape);
if (vertices != null) { if (vertices != null) {
_ptPool.Return(vertices); _ptPool.Return(vertices);
_lPool.Return(lengths); _lPool.Return(lengths);
} }
base.OnDestroy();
} }
protected override void AppendPointInternal(Vector3 p, Quaternion r) { protected override void AppendPointInternal(Vector3 p, Quaternion r) {

View File

@@ -0,0 +1,89 @@
using Cryville.Common;
using System;
using UnityEngine;
using Logger = Cryville.Common.Logger;
namespace Cryville.Crtr.Components {
public class SkinAnimation : SkinComponent {
public SkinAnimation() {
SubmitProperty("name", new PropOp.Identifier(v => Name = v));
SubmitProperty("duration", new PropOp.Float(v => Duration = v));
SubmitProperty("iteration", new PropOp.Float(v => Iteration = v));
SubmitProperty("direction", new PropOp.Enum<AnimationDirection>(v => Direction = v, v => (AnimationDirection)v));
SubmitProperty("delay", new PropOp.Float(v => Delay = v));
Iteration = 1;
}
SkinContext _skinContext;
Transform _writeTransform;
AnimationSpan _anim;
int _name;
public int Name {
set {
if (_name == value) return;
_name = value;
if (value == 0) {
_anim = null;
}
else {
var id = new Identifier(value);
AnimationSpan anim;
if (!ChartPlayer.pskin.animations.TryGetValue(id, out anim)) {
Logger.Log("main", 4, "Skin", "Animation {0} not found", id.Name);
_anim = null;
return;
}
_anim = anim;
}
}
}
public float Duration { get; private set; }
public float Iteration { get; private set; }
public AnimationDirection Direction { get; private set; }
public float Delay { get; private set; }
double _startTime;
public override void Init() {
_skinContext = new SkinContext(transform);
}
public override void Rewind(double time, Transform target) {
_startTime = time;
if (target == null) target = transform;
_writeTransform = target;
}
public override void Tick(SkinContainer c, double time) {
float _rtime = (float)(time - _startTime - Delay) / Duration;
if (_rtime < 0) _rtime = 0;
else if (_rtime > Iteration) {
if (Direction.HasFlag(AnimationDirection.alternate)) {
_rtime = Iteration % 2;
if (_rtime > 1) _rtime = 2 - _rtime;
}
else {
_rtime = Iteration % 1;
if (_rtime == 0) _rtime = 1;
}
}
else {
if (Direction.HasFlag(AnimationDirection.alternate)) {
_rtime %= 2;
if (_rtime > 1) _rtime = 2 - _rtime;
}
else {
_rtime %= 1;
}
}
if (Direction.HasFlag(AnimationDirection.reverse)) _rtime = 1 - _rtime;
if (_anim != null) c.MatchAnimation(_anim, _rtime, new RuntimeSkinContext(_skinContext, _writeTransform));
}
protected override void OnDestroy() { }
}
[Flags]
public enum AnimationDirection {
normal = 0,
reverse = 1,
alternate = 2,
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 80318e36af5412345871bdbf80d49ef2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -14,8 +14,8 @@ namespace Cryville.Crtr.Components {
/// </summary> /// </summary>
/// <param name="name">The name of the property.</param> /// <param name="name">The name of the property.</param>
/// <param name="property">The property.</param> /// <param name="property">The property.</param>
protected void SubmitProperty(string name, PdtOperator property, int uct = 1) { protected void SubmitProperty(string name, PdtOperator property, int udl = 0) {
Properties.Add(IdentifierManager.SharedInstance.Request(name), new SkinProperty(property, uct)); Properties.Add(IdentifierManager.SharedInstance.Request(name), new SkinProperty(property, udl));
} }
/// <summary> /// <summary>
@@ -26,14 +26,16 @@ namespace Cryville.Crtr.Components {
} }
public virtual void Init() { } public virtual void Init() { }
public virtual void Rewind(double time, Transform target) { }
public virtual void Tick(SkinContainer c, double time) { }
protected abstract void OnDestroy(); protected abstract void OnDestroy();
} }
public struct SkinProperty { public struct SkinProperty {
public PdtOperator Operator { get; set; } public PdtOperator Operator { get; set; }
public int UpdateCloneType { get; set; } public int UpdateDynamicLevel { get; set; }
public SkinProperty(PdtOperator op, int uct = 1) { public SkinProperty(PdtOperator op, int udl = 0) {
Operator = op; Operator = op;
UpdateCloneType = uct; UpdateDynamicLevel = udl;
} }
} }
} }

View File

@@ -25,10 +25,6 @@ namespace Cryville.Crtr.Components {
} }
#pragma warning restore IDE1006 #pragma warning restore IDE1006
protected override void OnDestroy() {
mesh.Destroy();
}
Vector2 _scale = Vector2.one; Vector2 _scale = Vector2.one;
public Vector2 Scale { public Vector2 Scale {
get { return _scale; } get { return _scale; }
@@ -92,7 +88,9 @@ namespace Cryville.Crtr.Components {
protected void InternalInit(string meshName = "quad") { protected void InternalInit(string meshName = "quad") {
mesh.Init(transform); mesh.Init(transform);
mesh.Renderer.sharedMaterials = materials = new Material[] { MeshWrapper.NewMaterial() };
mesh.Mesh = GenericResources.Meshes[meshName]; mesh.Mesh = GenericResources.Meshes[meshName];
UpdateColor();
UpdateScale(); UpdateScale();
UpdateZIndex(); UpdateZIndex();
} }

View File

@@ -29,19 +29,12 @@ namespace Cryville.Crtr.Components {
return Rect.width / Rect.height; return Rect.width / Rect.height;
} }
} }
bool _loaded;
Material _mat; Material _mat;
public void Bind(Material mat) { public void Bind(Material mat) {
_loaded = true;
_mat = mat; _mat = mat;
Reload(); Reload();
} }
public void Load() {
_loaded = true;
Reload();
}
public void Reload() { public void Reload() {
if (!_loaded) return;
if (!string.IsNullOrEmpty(FrameName)) { if (!string.IsNullOrEmpty(FrameName)) {
if (ChartPlayer.frames.ContainsKey(FrameName)) { if (ChartPlayer.frames.ContainsKey(FrameName)) {
Frame = ChartPlayer.frames[FrameName]; Frame = ChartPlayer.frames[FrameName];
@@ -56,13 +49,18 @@ namespace Cryville.Crtr.Components {
_mat.mainTexture = Frame == null ? null : Frame.Texture; _mat.mainTexture = Frame == null ? null : Frame.Texture;
} }
} }
public static bool IsNullOrEmpty(SpriteInfo sprite) {
return sprite == null || sprite.Frame == null;
}
} }
public class SpritePlane : SpriteBase { public class SpritePlane : SpriteBase {
public SpritePlane() { public SpritePlane() {
SubmitProperty("frame", new PropOp.String(v => Frame = v)); SubmitProperty("frame", new PropOp.String(v => Frame = v));
SubmitProperty("frames", new PropOp.StringArray(v => Frames = v));
SubmitProperty("index", new PropOp.Integer(v => Index = v));
SubmitProperty("fit", new PropOp.Enum<FitMode>(v => Fit = v, v => (FitMode)v)); SubmitProperty("fit", new PropOp.Enum<FitMode>(v => Fit = v, v => (FitMode)v));
SubmitProperty("opacity", new PropOp.Float(v => Opacity = v)); SubmitProperty("shader", new PropOp.String(v => Shader = v));
} }
static Vector2[] _origuv; static Vector2[] _origuv;
@@ -83,52 +81,73 @@ namespace Cryville.Crtr.Components {
} }
} }
protected SpriteInfo frameInfo = new SpriteInfo(); int m_index;
public int Index {
public string Frame { get { return m_index; }
get { return frameInfo.FrameName; }
set { set {
frameInfo.FrameName = value; m_index = value;
OnFrameUpdate(); OnFrameUpdate();
} }
} }
SpriteInfo[] m_frames = new SpriteInfo[] { new SpriteInfo() };
public string[] Frames {
set {
m_frames = new SpriteInfo[value.Length];
for (int i = 0; i < value.Length; i++) {
m_frames[i] = new SpriteInfo() { FrameName = value[i] };
}
OnFrameUpdate();
}
}
public string Frame {
set {
if (value == CurrentFrame.FrameName) return;
CurrentFrame.FrameName = value;
OnFrameUpdate();
}
}
protected SpriteInfo CurrentFrame {
get {
if (m_frames.Length == 0) return null;
if (m_index < 0) m_index = 0;
else if (m_index >= m_frames.Length) m_index = m_frames.Length - 1;
return m_frames[m_index];
}
}
protected void OnFrameUpdate() { protected void OnFrameUpdate() {
if (!mesh.Initialized) return; if (!mesh.Initialized) return;
if (frameInfo.Frame == null) { var frame = CurrentFrame;
if (SpriteInfo.IsNullOrEmpty(frame)) {
mesh.Renderer.enabled = false; mesh.Renderer.enabled = false;
return; return;
} }
mesh.Renderer.enabled = true; mesh.Renderer.enabled = true;
mesh.Renderer.sharedMaterial.mainTexture = frame.Frame.Texture;
UpdateUV(); UpdateUV();
UpdateScale(); UpdateScale();
}
Shader m_shader;
public string Shader {
set {
m_shader = GenericResources.Shaders[value];
UpdateShader();
}
}
void UpdateShader() {
if (!mesh.Initialized) return;
if (m_shader == null) m_shader = GenericResources.Shaders["default"];
mesh.Renderer.sharedMaterial.shader = m_shader;
UpdateZIndex(); UpdateZIndex();
} }
readonly Vector2[] _uvs = new Vector2[4];
protected virtual void UpdateUV() { protected virtual void UpdateUV() {
if (frameInfo.Frame == null) { var frame = CurrentFrame;
Logger.Log("main", 4, "Skin", "Unable to load texture {0}", frameInfo.FrameName); if (SpriteInfo.IsNullOrEmpty(frame)) return;
return;
}
Vector2[] muv = OriginalUV; Vector2[] muv = OriginalUV;
Vector2[] uv = new Vector2[muv.Length]; for (int i = 0; i < _uvs.Length; i++) {
for (int i = 0; i < uv.Length; i++) { _uvs[i] = frame.Frame.GetUV(muv[i]);
uv[i] = frameInfo.Frame.GetUV(muv[i]);
} }
mesh.Mesh.uv = uv; mesh.Mesh.uv = _uvs;
}
float _opacity = 1;
public float Opacity {
get { return _opacity; }
set {
_opacity = value;
UpdateOpacity();
}
}
void UpdateOpacity() {
if (!mesh.Initialized) return;
var c = mesh.Renderer.material.color;
c.a = _opacity;
mesh.Renderer.material.color = c;
} }
private FitMode m_fit = FitMode.height; private FitMode m_fit = FitMode.height;
@@ -144,7 +163,7 @@ namespace Cryville.Crtr.Components {
} }
protected override void UpdateScale() { protected override void UpdateScale() {
if (frameInfo.Frame == null) return; if (SpriteInfo.IsNullOrEmpty(CurrentFrame)) return;
base.UpdateScale(); base.UpdateScale();
if (m_fit != FitMode.none && Scale.x != Scale.y) m_fit = FitMode.none; if (m_fit != FitMode.none && Scale.x != Scale.y) m_fit = FitMode.none;
} }
@@ -153,8 +172,8 @@ namespace Cryville.Crtr.Components {
get { get {
switch (m_fit) { switch (m_fit) {
case FitMode.none: return Vector3.one; case FitMode.none: return Vector3.one;
case FitMode.width: return new Vector3(1, 1, 1 / frameInfo.Ratio); case FitMode.width: return new Vector3(1, 1, 1 / CurrentFrame.Ratio);
case FitMode.height: return new Vector3(frameInfo.Ratio, 1, 1); case FitMode.height: return new Vector3(CurrentFrame.Ratio, 1, 1);
default: throw new NotSupportedException("Unsupported fit mode"); default: throw new NotSupportedException("Unsupported fit mode");
} }
} }
@@ -162,9 +181,8 @@ namespace Cryville.Crtr.Components {
public override void Init() { public override void Init() {
InternalInit(); InternalInit();
frameInfo.Bind(mesh.Renderer.material);
OnFrameUpdate(); OnFrameUpdate();
UpdateOpacity(); UpdateShader();
} }
} }
} }

View File

@@ -2,22 +2,7 @@
namespace Cryville.Crtr.Components { namespace Cryville.Crtr.Components {
public class SpriteRect : SpriteBase { public class SpriteRect : SpriteBase {
public SpriteRect() { public SpriteRect() { }
SubmitProperty("color", new PropOp.Color(v => Color = v));
}
Color _color;
public Color Color {
get { return _color; }
set {
_color = value;
OnColorUpdate();
}
}
void OnColorUpdate() {
if (!mesh.Initialized) return;
mesh.Renderer.material.SetColor("_Color", _color);
}
protected override Vector3 BaseScale { protected override Vector3 BaseScale {
get { return Vector3.one; } get { return Vector3.one; }
@@ -25,7 +10,6 @@ namespace Cryville.Crtr.Components {
public override void Init() { public override void Init() {
InternalInit(); InternalInit();
OnColorUpdate();
} }
} }
} }

View File

@@ -8,12 +8,12 @@ namespace Cryville.Crtr.Components {
SubmitProperty("border", new PropOp.Vector2(v => Border = v)); SubmitProperty("border", new PropOp.Vector2(v => Border = v));
} }
readonly static Dictionary<float, int> uvrefl static readonly Dictionary<float, int> uvrefl
= new Dictionary<float, int>() { = new Dictionary<float, int>() {
{-0.5f, 0}, {-0.4f, 1}, {0.4f, 2}, {0.5f, 3}, {-0.5f, 0}, {-0.4f, 1}, {0.4f, 2}, {0.5f, 3},
}; };
static Vector2[] _origuv; static Vector2[] _origuv;
protected new static Vector2[] OriginalUV { protected static new Vector2[] OriginalUV {
get { get {
if (_origuv == null) { if (_origuv == null) {
var m = GenericResources.Meshes["quad_scale3h"]; var m = GenericResources.Meshes["quad_scale3h"];
@@ -44,24 +44,26 @@ namespace Cryville.Crtr.Components {
UpdateUV(); UpdateUV();
} }
readonly Vector2[] _uvs = new Vector2[8];
readonly Vector3[] _verts = new Vector3[8];
protected override void UpdateUV() { protected override void UpdateUV() {
Vector2[] muv = OriginalUV; var frame = CurrentFrame;
Vector2[] uv = new Vector2[muv.Length]; if (SpriteInfo.IsNullOrEmpty(frame)) return;
var or = frameInfo.Ratio; Vector2[] muv = OriginalUV;
var or = frame.Ratio;
var sr = Scale.x / Scale.y; var sr = Scale.x / Scale.y;
var b = new Vector2( var rr = or / sr;
(or / sr) * _border.x, var b1 = rr * _border.x;
1 - (or / sr) * (1 - _border.y) var b2 = 1 - rr * (1 - _border.y);
);
Vector3[] vert = mesh.Mesh.vertices;
for (int i = 0; i < muv.Length; i++) { for (int i = 0; i < muv.Length; i++) {
float x; float bx; float x; float bx;
switch ((int)muv[i].x) { switch ((int)muv[i].x) {
case 0: x = 0; bx = 0; break; case 0: x = 0; bx = 0; break;
case 1: x = _border.x; bx = b.x; break; case 1: x = _border.x; bx = b1; break;
case 2: x = _border.y; bx = b.y; break; case 2: x = _border.y; bx = b2; break;
case 3: x = 1; bx = 1; break; case 3: x = 1; bx = 1; break;
default: throw new NotSupportedException("Built-in resource corrupted"); default: throw new NotSupportedException("Built-in resource corrupted");
} }
@@ -71,16 +73,15 @@ namespace Cryville.Crtr.Components {
case 3: y = 1; break; case 3: y = 1; break;
default: throw new NotSupportedException("Built-in resource corrupted"); default: throw new NotSupportedException("Built-in resource corrupted");
} }
uv[i] = frameInfo.Frame.GetUV(x, y); _uvs[i] = frame.Frame.GetUV(x, y);
bx -= 0.5f; y -= 0.5f; bx -= 0.5f; y -= 0.5f;
vert[i] = new Vector3(bx, 0, y); _verts[i] = new Vector3(bx, 0, y);
} }
mesh.Mesh.uv = uv; mesh.Mesh.uv = _uvs;
mesh.Mesh.vertices = vert; mesh.Mesh.vertices = _verts;
} }
public override void Init() { public override void Init() {
frameInfo.Load();
InternalInit("quad_scale3h"); InternalInit("quad_scale3h");
OnFrameUpdate(); OnFrameUpdate();
} }

View File

@@ -11,7 +11,6 @@ namespace Cryville.Crtr.Components {
SubmitProperty("value", new PropOp.TargetString(() => Value)); SubmitProperty("value", new PropOp.TargetString(() => Value));
SubmitProperty("size", new PropOp.Float(v => Size = v)); SubmitProperty("size", new PropOp.Float(v => Size = v));
SubmitProperty("spacing", new PropOp.Float(v => Spacing = v)); SubmitProperty("spacing", new PropOp.Float(v => Spacing = v));
SubmitProperty("opacity", new PropOp.Float(v => Opacity = v));
} }
#pragma warning disable IDE1006 #pragma warning disable IDE1006
@@ -20,11 +19,13 @@ namespace Cryville.Crtr.Components {
public op_set_frames(SpriteText self) : base(2) { public op_set_frames(SpriteText self) : base(2) {
_self = self; _self = self;
} }
protected unsafe override void Execute() { protected override unsafe void Execute() {
var keys = GetOperand(0).AsString(); var keys = GetOperand(0).AsString();
var values = GetOperand(1); var values = GetOperand(1);
int arrtype; int len; int arrtype; int len;
values.GetArraySuffix(out arrtype, out len); values.GetArraySuffix(out arrtype, out len);
if (arrtype != PdtInternalType.String) throw new InvalidCastException("Not an array of strings");
if (len != keys.Length) throw new ArgumentException("Length of key not equal to frame count");
var result = new Dictionary<char, SpriteInfo>(len); var result = new Dictionary<char, SpriteInfo>(len);
int o = 0; int o = 0;
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
@@ -45,7 +46,7 @@ namespace Cryville.Crtr.Components {
Dictionary<char, SpriteInfo> m_frames; Dictionary<char, SpriteInfo> m_frames;
public Dictionary<char, SpriteInfo> Frames { public Dictionary<char, SpriteInfo> Frames {
get { return m_frames; } get { return m_frames; }
set { m_frames = value; UpdateFrames(); UpdateScale(); } set { m_frames = value; UpdateFrames(); }
} }
readonly TargetString m_value = new TargetString(); readonly TargetString m_value = new TargetString();
@@ -76,8 +77,11 @@ namespace Cryville.Crtr.Components {
meshes.Clear(); meshes.Clear();
verts.Clear(); verts.Clear();
uvs.Clear(); uvs.Clear();
DestroyMaterials();
materials = new Material[m_frames.Count];
int i = 0;
foreach (var f in m_frames) { foreach (var f in m_frames) {
f.Value.Load(); if (SpriteInfo.IsNullOrEmpty(f.Value)) continue;
if (frameHeight == 0) frameHeight = f.Value.Rect.height; if (frameHeight == 0) frameHeight = f.Value.Rect.height;
else if (frameHeight != f.Value.Rect.height) throw new Exception("Inconsistent frame height for text component"); else if (frameHeight != f.Value.Rect.height) throw new Exception("Inconsistent frame height for text component");
var tex = f.Value.Frame.Texture; var tex = f.Value.Frame.Texture;
@@ -85,13 +89,17 @@ namespace Cryville.Crtr.Components {
var m = new MeshWrapper(); var m = new MeshWrapper();
m.Init(mesh.MeshTransform); m.Init(mesh.MeshTransform);
m.Mesh = new Mesh(); m.Mesh = new Mesh();
m.Renderer.material.mainTexture = tex; var mat = MeshWrapper.NewMaterial();
mat.mainTexture = tex;
m.Renderer.sharedMaterial = materials[i++] = mat;
meshes.Add(tex, m); meshes.Add(tex, m);
verts.Add(tex, new List<Vector3>()); verts.Add(tex, new List<Vector3>());
uvs.Add(tex, new List<Vector2>()); uvs.Add(tex, new List<Vector2>());
tris.Add(tex, new List<int>()); tris.Add(tex, new List<int>());
} }
} }
UpdateColor();
UpdateScale();
} }
float sum_x; float sum_x;
@@ -102,10 +110,11 @@ namespace Cryville.Crtr.Components {
void UpdateMeshes() { void UpdateMeshes() {
if (meshes.Count == 0) return; if (meshes.Count == 0) return;
sum_x = 0; sum_x = 0;
foreach (var t in meshes.Keys) { foreach (var t in meshes) {
verts[t].Clear(); var key = t.Key;
uvs[t].Clear(); verts[key].Clear();
tris[t].Clear(); uvs[key].Clear();
tris[key].Clear();
} }
foreach (var c in m_value) { foreach (var c in m_value) {
var f = m_frames[c]; var f = m_frames[c];
@@ -121,11 +130,12 @@ namespace Cryville.Crtr.Components {
uvs[t].Add(f.Frame.GetUV(new Vector2(0, 1))); uvs[t].Add(f.Frame.GetUV(new Vector2(0, 1)));
sum_x += w + m_spacing; sum_x += w + m_spacing;
} }
foreach (var t in meshes.Keys) { foreach (var t in meshes) {
var m = meshes[t].Mesh; var key = t.Key;
var m = meshes[key].Mesh;
m.Clear(); m.Clear();
int cc = verts[t].Count / 4; int cc = verts[key].Count / 4;
var _tris = tris[t]; var _tris = tris[key];
for (int i = 0; i < cc; i++) { for (int i = 0; i < cc; i++) {
_tris.Add(i * 4); _tris.Add(i * 4);
_tris.Add(i * 4 + 3); _tris.Add(i * 4 + 3);
@@ -134,9 +144,9 @@ namespace Cryville.Crtr.Components {
_tris.Add(i * 4 + 3); _tris.Add(i * 4 + 3);
_tris.Add(i * 4 + 2); _tris.Add(i * 4 + 2);
} }
m.SetVertices(verts[t]); m.SetVertices(verts[key]);
m.SetUVs(0, uvs[t]); m.SetUVs(0, uvs[key]);
m.SetTriangles(tris[t], 0); m.SetTriangles(tris[key], 0);
m.RecalculateNormals(); m.RecalculateNormals();
} }
sum_x -= m_spacing; sum_x -= m_spacing;
@@ -154,23 +164,6 @@ namespace Cryville.Crtr.Components {
get { return new Vector2(-0.5f, -0.5f); } get { return new Vector2(-0.5f, -0.5f); }
} }
float _opacity = 1;
public float Opacity {
get { return _opacity; }
set {
_opacity = value;
UpdateOpacity();
}
}
void UpdateOpacity() {
if (!mesh.Initialized) return;
foreach (var m in meshes.Values) {
var c = m.Renderer.material.color;
c.a = _opacity;
m.Renderer.material.color = c;
}
}
public override void Init() { public override void Init() {
InternalInit(); InternalInit();
UpdateFrames(); UpdateFrames();

View File

@@ -1,4 +1,5 @@
using Cryville.Common.Unity; using Cryville.Common;
using Cryville.Common.Unity;
using Cryville.Common.Unity.Input; using Cryville.Common.Unity.Input;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
@@ -26,10 +27,10 @@ namespace Cryville.Crtr.Config {
SimpleInputConsumer _consumer; SimpleInputConsumer _consumer;
public InputProxy proxy; public InputProxy proxy;
readonly Dictionary<string, InputConfigPanelEntry> _entries = new Dictionary<string, InputConfigPanelEntry>(); readonly Dictionary<Identifier, InputConfigPanelEntry> _entries = new Dictionary<Identifier, InputConfigPanelEntry>();
string _sel; Identifier _sel;
public void OpenDialog(string entry) { public void OpenDialog(Identifier entry) {
_sel = entry; _sel = entry;
m_inputDialog.SetActive(true); m_inputDialog.SetActive(true);
CallHelper.Purge(m_deviceList); CallHelper.Purge(m_deviceList);
@@ -85,9 +86,21 @@ namespace Cryville.Crtr.Config {
if (_recvsrcs.Contains(src)) return; if (_recvsrcs.Contains(src)) return;
_recvsrcs.Add(src); _recvsrcs.Add(src);
var obj = Instantiate(m_prefabListItem, m_deviceList); var obj = Instantiate(m_prefabListItem, m_deviceList);
obj.transform.Find("Text").GetComponent<Text>().text = src == null ? "(None)" : src.Value.Handler.GetTypeName(src.Value.Type); var text = obj.transform.Find("Text").GetComponent<Text>();
text.text = src == null ? "(None)" : src.Value.Handler.GetTypeName(src.Value.Type);
var btn = obj.GetComponent<Button>(); var btn = obj.GetComponent<Button>();
if (src != null) btn.interactable = !proxy.IsUsed(src.Value); if (src != null) {
var tsrc = src.Value;
bool flag = false;
if (proxy.IsUsed(tsrc)) {
text.text += " <size=9>(Used)</size>";
}
else if (tsrc.Handler.GetDimension(src.Value.Type) < m_configScene.ruleset.Root.inputs[_sel].dim) {
text.text += " <size=9>(Not Applicable)</size>";
}
else flag = true;
btn.interactable = flag;
}
btn.onClick.AddListener(() => { btn.onClick.AddListener(() => {
CloseDialog(src); CloseDialog(src);
}); });

View File

@@ -1,4 +1,5 @@
using UnityEngine; using Cryville.Common;
using UnityEngine;
using UnityEngine.EventSystems; using UnityEngine.EventSystems;
using UnityEngine.UI; using UnityEngine.UI;
@@ -13,8 +14,8 @@ namespace Cryville.Crtr.Config {
[SerializeField] [SerializeField]
Button m_button; Button m_button;
public void SetKey(InputConfigPanel master, string name) { public void SetKey(InputConfigPanel master, Identifier name) {
m_key.text = name; m_key.text = (string)name.Name;
m_value.text = "None"; m_value.text = "None";
m_button.onClick.AddListener(() => { m_button.onClick.AddListener(() => {
master.OpenDialog(name); master.OpenDialog(name);
@@ -26,27 +27,18 @@ namespace Cryville.Crtr.Config {
if (e.Used) { if (e.Used) {
m_button.interactable = false; m_button.interactable = false;
m_value.text = "(Not Required)"; m_value.text = "(Not Required)";
m_value.color = Color.black;
} }
else { else {
m_button.interactable = true; m_button.interactable = true;
if (e.Proxy == null) { if (e.Proxy == null) {
m_value.text = "(Unassigned)"; m_value.text = "(Unassigned)";
m_value.color = Color.yellow; if (e.Required) m_value.text += " (Required)";
} }
else { else {
m_value.text = e.Proxy.Value.Handler.GetTypeName(e.Proxy.Value.Type); m_value.text = e.Proxy.Value.Handler.GetTypeName(e.Proxy.Value.Type);
m_value.color = Color.black;
} }
} }
} m_value.color = e.Required ? Color.yellow : Color.black;
public void SetValue(string name) {
m_value.text = name;
}
public void SetEnabled(bool flag) {
m_button.interactable = flag;
} }
} }
} }

View File

@@ -0,0 +1,75 @@
using Cryville.Common.Buffers;
using System.Collections.Generic;
using UnityEngine;
namespace Cryville.Crtr {
public class EffectGroup {
public EffectDefinition Definition { get; private set; }
readonly EffectPool _pool;
class EffectPool : ObjectPool<EffectInstance> {
readonly List<EffectInstance> _instances
= new List<EffectInstance>();
readonly EffectGroup _group;
public EffectPool(EffectGroup group) : base(256) {
_group = group;
}
protected override EffectInstance Construct() {
var result = new EffectInstance(_group.Definition);
_instances.Add(result);
return result;
}
public void DisposeAll() {
foreach (var i in _instances) i.Dispose();
}
}
readonly Dictionary<float, EffectInstance> _instances
= new Dictionary<float, EffectInstance>();
readonly List<EffectInstance> _endQueue
= new List<EffectInstance>();
public EffectGroup(EffectDefinition def) {
Definition = def;
_pool = new EffectPool(this);
}
double _time;
public void Tick(double time) {
_time = time;
while (_endQueue.Count > 0) {
var item = _endQueue[0];
if (item.EndTime > _time) break;
_endQueue.RemoveAt(0);
if (item.OnStateDone()) {
QueueInstance(item);
}
else {
item.Tick(time);
_instances.Remove(item.Index);
_pool.Return(item);
}
}
foreach (var instance in _instances) {
instance.Value.Tick(time);
}
}
public void Emit(float index, Transform target = null) {
EffectInstance instance;
bool flag = _instances.TryGetValue(index, out instance);
if (!flag) _instances.Add(index, instance = _pool.Rent());
instance.Index = index;
if (instance.CanEmit()) {
if (flag) {
var i = _endQueue.BinarySearch(instance);
_endQueue.RemoveAt(i);
}
instance.OnEmit(_time, target);
QueueInstance(instance);
}
}
void QueueInstance(EffectInstance i) {
var index = ~_endQueue.BinarySearch(i);
_endQueue.Insert(index, i);
}
public void Dispose() {
_pool.DisposeAll();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d0d27f9b4383b3445a2a27bfe94173a5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,121 @@
using Cryville.Common;
using Cryville.Crtr.Components;
using Cryville.Crtr.Event;
using System;
using System.Collections.Generic;
using System.Globalization;
using UnityEngine;
namespace Cryville.Crtr {
public class EffectInstance : ISkinnableGroup, IComparable<EffectInstance> {
readonly EffectDefinition _def;
readonly SkinContainer _skinContainer;
public Transform RootTransform { get; private set; }
readonly SkinComponent[] _comps;
public EffectInstance(EffectDefinition def) {
_def = def;
_skinContainer = new SkinContainer(this, _def.elements);
RootTransform = new GameObject("effect:" + GetHashCode().ToString(CultureInfo.InvariantCulture)).transform;
SkinContext = new SkinContext(RootTransform);
ChartPlayer.etor.ContextCascadeInsertBlock();
_skinContainer.MatchStatic();
ChartPlayer.etor.ContextCascadeDiscardBlock();
_comps = RootTransform.GetComponentsInChildren<SkinComponent>();
foreach (var i in _comps) i.Init();
_indexSrc = new PropSrc.Float(() => Index);
_durationOp = new PropOp.Float(v => _duration = v);
}
public void Rewind(double time, Transform target) {
_startTime = time;
foreach (var i in _comps) i.Rewind(time, target);
}
private float m_index;
public float Index {
get { return m_index; }
set {
if (m_index == value) return;
m_index = value;
_indexSrc.Invalidate();
}
}
Transform _currentTarget;
Identifier _currentStateName = Identifier.Empty;
EffectState _currentState;
ChartEvent _ctxev;
ContainerState _ctxstate;
internal static readonly int _VAR_EFFECT_INDEX = IdentifierManager.SharedInstance.Request("effect_index");
readonly PropSrc _indexSrc;
double _startTime;
float _duration;
readonly PropOp _durationOp;
public double EndTime { get { return _startTime + _duration; } }
public void Tick(double time) {
foreach (var i in _comps) i.Tick(_skinContainer, time);
}
public bool CanEmit() {
return _currentStateName.Key == 0 || _currentState.rewind.Key != 0;
}
public void OnEmit(double time, Transform target) {
_currentTarget = target;
_ctxev = ChartPlayer.etor.ContextEvent;
_ctxstate = ChartPlayer.etor.ContextState;
if (_currentStateName.Key == 0) {
EnterState(_def.init, time, _currentTarget, true);
}
else {
if (_currentState.rewind.Key == 0) throw new InvalidOperationException("Cannot rewind");
EnterState(_currentState.rewind, time, _currentTarget, true);
}
}
void EnterState(Identifier name, double time, Transform target, bool emitting) {
_currentStateName = name;
_currentState = _def.states[name];
Rewind(time, target);
RootTransform.gameObject.SetActive(true);
ChartPlayer.etor.ContextCascadeInsert();
ChartPlayer.etor.ContextCascadeUpdate(_VAR_EFFECT_INDEX, _indexSrc);
ChartPlayer.etor.Evaluate(_durationOp, _currentState.duration);
if (emitting) _skinContainer.MatchDynamic(0, true);
_skinContainer.MatchDynamic(1, emitting);
ChartPlayer.etor.ContextCascadeDiscard();
}
public bool OnStateDone() {
if (_currentState.next.Key == 0) {
RootTransform.gameObject.SetActive(false);
_currentStateName = Identifier.Empty;
_currentState = null;
return false;
}
else {
ChartPlayer.etor.ContextEvent = _ctxev;
ChartPlayer.etor.ContextState = _ctxstate;
EnterState(_currentState.next, EndTime, _currentTarget, false);
ChartPlayer.etor.ContextEvent = null;
ChartPlayer.etor.ContextState = null;
return true;
}
}
public void Dispose() {
GameObject.Destroy(RootTransform.gameObject);
}
public string TypeName { get { throw new InvalidOperationException("Type name undefined"); } }
public SkinContext SkinContext { get; private set; }
public int OpenedAnchorName { get { return _currentStateName.Key; } }
public void PushAnchorEvent(double time, int name) {
throw new InvalidOperationException("Anchor not supported");
}
public void RegisterAnchor(int name) {
throw new InvalidOperationException("Anchor not supported");
}
public bool TryGetAnchorsByName(int name, out IReadOnlyCollection<Anchor> result) {
throw new InvalidOperationException("Anchor not supported");
}
public int CompareTo(EffectInstance other) {
int r = EndTime.CompareTo(other.EndTime);
if (r != 0) return r;
return GetHashCode().CompareTo(other.GetHashCode());
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f442db34239c47046ba1b6fdae8e1216
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,26 @@
using System.Collections.Generic;
using UnityEngine;
namespace Cryville.Crtr {
public class EffectManager {
readonly Dictionary<int, EffectGroup> _groups
= new Dictionary<int, EffectGroup>();
public EffectManager(PdtSkin skin) {
foreach (var e in skin.effects) {
_groups.Add(e.Key.Key, new EffectGroup(e.Value));
}
}
public void Tick(double time) {
foreach (var g in _groups) g.Value.Tick(time);
}
public void Emit(int id, float index) {
_groups[id].Emit(index);
}
public void EmitSelf(int id, float index, Transform target) {
_groups[id].Emit(index, target);
}
public void Dispose() {
foreach (var g in _groups) g.Value.Dispose();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 980c0f18a6f491d44a866a85910cb458
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -8,10 +8,9 @@ using System.Runtime.CompilerServices;
using UnityEngine; using UnityEngine;
namespace Cryville.Crtr.Event { namespace Cryville.Crtr.Event {
public abstract class ContainerHandler { public abstract class ContainerHandler : ISkinnableGroup {
#region Struct #region Struct
public ContainerHandler() { } public ContainerHandler() { }
public abstract string TypeName { get; }
/// <summary> /// <summary>
/// Prehandling <see cref="ContainerState"/>, prehandling the events. /// Prehandling <see cref="ContainerState"/>, prehandling the events.
@@ -38,11 +37,9 @@ namespace Cryville.Crtr.Event {
/// </summary> /// </summary>
public ContainerState ts; public ContainerState ts;
/// <summary> protected Transform RootTransform;
/// <see cref="GameObject"/> group, the <see cref="Transform"/> containing all the generated elements in the <see cref="ContainerHandler"/>.
/// </summary> SkinComponent[] _comps;
protected Transform gogroup;
public SkinContext SkinContext;
public Vector3 Position { get; protected set; } public Vector3 Position { get; protected set; }
public Quaternion Rotation { get; protected set; } public Quaternion Rotation { get; protected set; }
@@ -72,32 +69,31 @@ namespace Cryville.Crtr.Event {
SkinContainer skinContainer; SkinContainer skinContainer;
protected Judge judge; protected Judge judge;
public void AttachSystems(PdtSkin skin, Judge judge) { public void AttachSystems(PdtSkin skin, Judge judge) {
skinContainer = new SkinContainer(skin); skinContainer = new SkinContainer(this, skin.elements);
this.judge = judge; this.judge = judge;
} }
public readonly Dictionary<int, List<Anchor>> Anchors = new Dictionary<int, List<Anchor>>(); public readonly Dictionary<int, List<Anchor>> Anchors = new Dictionary<int, List<Anchor>>();
public readonly Dictionary<int, Anchor> DynamicAnchors = new Dictionary<int, Anchor>(); public readonly Dictionary<int, Anchor> DynamicAnchors = new Dictionary<int, Anchor>();
public readonly Dictionary<int, bool> DynamicAnchorSet = new Dictionary<int, bool>(); public readonly Dictionary<int, double> DynamicAnchorSetTime = new Dictionary<int, double>();
public Anchor OpenedAnchor;
Anchor a_cur; Anchor a_cur;
Anchor a_head; Anchor a_head;
Anchor a_tail; Anchor a_tail;
readonly static int _a_cur = IdentifierManager.SharedInstance.Request("cur"); static readonly int _a_cur = IdentifierManager.SharedInstance.Request("cur");
readonly static int _a_head = IdentifierManager.SharedInstance.Request("head"); static readonly int _a_head = IdentifierManager.SharedInstance.Request("head");
readonly static int _a_tail = IdentifierManager.SharedInstance.Request("tail"); static readonly int _a_tail = IdentifierManager.SharedInstance.Request("tail");
double atime_head; double atime_head;
double atime_tail; double atime_tail;
public Anchor RegisterAnchor(int name, bool dyn = false, int propSrcCount = 0) { public Anchor RegisterAnchor(int name, bool dyn = false, int propSrcCount = 0) {
var strname = IdentifierManager.SharedInstance.Retrieve(name); var strname = IdentifierManager.SharedInstance.Retrieve(name);
var go = new GameObject("." + strname).transform; var go = new GameObject("." + strname).transform;
go.SetParent(gogroup, false); go.SetParent(RootTransform, false);
var result = new Anchor(name, go, propSrcCount); var result = new Anchor(name, go, propSrcCount);
if (dyn) { if (dyn) {
if (DynamicAnchors.ContainsKey(name)) if (DynamicAnchors.ContainsKey(name))
throw new ArgumentException(string.Format("The anchor \"{0}\" already exists", strname)); throw new ArgumentException(string.Format("The anchor \"{0}\" already exists", strname));
DynamicAnchors.Add(name, result); DynamicAnchors.Add(name, result);
DynamicAnchorSet.Add(name, false); DynamicAnchorSetTime.Add(name, double.NaN);
} }
List<Anchor> list; List<Anchor> list;
if (!Anchors.TryGetValue(name, out list)) if (!Anchors.TryGetValue(name, out list))
@@ -106,35 +102,39 @@ namespace Cryville.Crtr.Event {
return result; return result;
} }
protected void OpenAnchor(Anchor anchor) { protected void OpenAnchor(Anchor anchor) {
if (OpenedAnchor != null) throw new InvalidOperationException("An anchor has been opened"); if (_openedAnchor != null) throw new InvalidOperationException("An anchor has been opened");
anchor.Transform.gameObject.SetActive(true); anchor.Transform.gameObject.SetActive(true);
OpenedAnchor = anchor; _openedAnchor = anchor;
} }
protected void CloseAnchor() { protected void CloseAnchor() {
OpenedAnchor = null; _openedAnchor = null;
} }
#endregion #endregion
#region Logic #region Logic
#region Init methods: Called on prehandle #region Init methods: Called on prehandle
public virtual void PreInit() { public virtual void PreInit() {
gogroup = new GameObject(TypeName + ":" + Container.GetHashCode().ToString(CultureInfo.InvariantCulture)).transform; RootTransform = new GameObject(TypeName + ":" + Container.GetHashCode().ToString(CultureInfo.InvariantCulture)).transform;
SkinContext = new SkinContext(gogroup); SkinContext = new SkinContext(RootTransform);
if (cs.Parent != null) if (cs.Parent != null)
gogroup.SetParent(cs.Parent.Handler.gogroup, false); RootTransform.SetParent(cs.Parent.Handler.RootTransform, false);
a_cur = RegisterAnchor(_a_cur); a_cur = RegisterAnchor(_a_cur);
a_head = RegisterAnchor(_a_head, true); a_head = RegisterAnchor(_a_head, true);
a_tail = RegisterAnchor(_a_tail, true); a_tail = RegisterAnchor(_a_tail, true);
} }
public virtual void Init() { public virtual void Init() {
skinContainer.MatchStatic(ps); ChartPlayer.etor.ContextState = ps;
foreach (var i in gogroup.GetComponentsInChildren<SkinComponent>()) ChartPlayer.etor.ContextEvent = Container;
i.Init(); skinContainer.MatchStatic();
ChartPlayer.etor.ContextEvent = null;
ChartPlayer.etor.ContextState = null;
_comps = RootTransform.GetComponentsInChildren<SkinComponent>();
foreach (var i in _comps) i.Init();
} }
public virtual void PostInit() { public virtual void PostInit() {
PropSrcs.Add(_var_current_time, new PropSrc.Float(() => (float)cs.rootPrototype.Time)); PropSrcs.Add(_var_current_time, new PropSrc.Float(() => (float)cs.rootPrototype.Time));
PropSrcs.Add(_var_invisible_bounds, new PropSrc.Boolean(() => atime_head > atime_tail)); PropSrcs.Add(_var_invisible_bounds, new PropSrc.Boolean(() => atime_head > atime_tail));
gogroup.gameObject.SetActive(false); RootTransform.gameObject.SetActive(false);
} }
#endregion #endregion
#region Start methods #region Start methods
@@ -143,16 +143,16 @@ namespace Cryville.Crtr.Event {
else if (s.CloneType == 17) Init(); else if (s.CloneType == 17) Init();
} }
public virtual void StartLogicalUpdate(ContainerState s) { } public virtual void StartLogicalUpdate(ContainerState s) { }
public virtual void StartPreGraphicalUpdate(ContainerState s) { } protected virtual void StartPreGraphicalUpdate(ContainerState s) { }
public virtual void StartGraphicalUpdate(ContainerState s) { protected virtual void StartGraphicalUpdate(ContainerState s) {
if (gogroup) gogroup.gameObject.SetActive(true); if (RootTransform) RootTransform.gameObject.SetActive(true);
} }
#endregion #endregion
public virtual void Update(ContainerState s, StampedEvent ev) { public virtual void Update(ContainerState s, StampedEvent ev) {
if (s.CloneType == 3) SetPreGraphicalActive(true, s); if (s.CloneType == 3) SetPreGraphicalActive(true, s);
else if (ev is StampedEvent.Anchor) { else if (ev is StampedEvent.Anchor) {
var tev = (StampedEvent.Anchor)ev; var tev = (StampedEvent.Anchor)ev;
if (gogroup) { if (RootTransform) {
OpenAnchor(tev.Target); OpenAnchor(tev.Target);
#if UNITY_5_6_OR_NEWER #if UNITY_5_6_OR_NEWER
tev.Target.Transform.SetPositionAndRotation(Position, Rotation); tev.Target.Transform.SetPositionAndRotation(Position, Rotation);
@@ -160,7 +160,7 @@ namespace Cryville.Crtr.Event {
tev.Target.Transform.position = Position; tev.Target.Transform.position = Position;
tev.Target.Transform.rotation = Rotation; tev.Target.Transform.rotation = Rotation;
#endif #endif
skinContainer.MatchDynamic(s); MatchDynamic(s, 1);
CloseAnchor(); CloseAnchor();
} }
if (tev.Target == a_head) { if (tev.Target == a_head) {
@@ -171,52 +171,56 @@ namespace Cryville.Crtr.Event {
} }
anchorEvPool.Return(tev); anchorEvPool.Return(tev);
} }
else if (gogroup && s.CloneType == 2) skinContainer.MatchDynamic(s); else if (RootTransform && s.CloneType == 2) MatchDynamic(s, 1);
} }
#region End methods #region End methods
public virtual void EndGraphicalUpdate(ContainerState s) { } protected virtual void EndGraphicalUpdate(ContainerState s) { }
public virtual void EndPreGraphicalUpdate(ContainerState s) { } protected virtual void EndPreGraphicalUpdate(ContainerState s) { }
public virtual void EndLogicalUpdate(ContainerState s) { } public virtual void EndLogicalUpdate(ContainerState s) { }
public virtual void EndPhysicalUpdate(ContainerState s) { } public virtual void EndPhysicalUpdate(ContainerState s) { }
public virtual void Dispose() { public virtual void Dispose() {
if (gogroup) if (RootTransform)
GameObject.Destroy(gogroup.gameObject); GameObject.Destroy(RootTransform.gameObject);
Alive = false; Alive = false;
} }
public virtual void DisposeAll() { } public virtual void DisposeAll() { }
#endregion #endregion
#region Utils
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
protected static bool CanDoGraphicalUpdate(ContainerState s) { return s.CloneType >= 2 && s.CloneType < 16; } protected static bool CanDoGraphicalUpdate(ContainerState s) { return s.CloneType >= 2 && s.CloneType < 16; }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
void MatchDynamic(ContainerState s, int dl) {
ChartPlayer.etor.ContextState = s;
ChartPlayer.etor.ContextEvent = Container;
skinContainer.MatchDynamic(dl);
ChartPlayer.etor.ContextEvent = null;
ChartPlayer.etor.ContextState = null;
}
#endregion
#region Anchor #region Anchor
public virtual void Anchor() { public virtual void Anchor() {
foreach (var p in PropSrcs.Values) p.Invalidate(); foreach (var p in PropSrcs) p.Value.Invalidate();
foreach (var a in DynamicAnchors.Keys) DynamicAnchorSet[a] = false; foreach (var a in DynamicAnchors) DynamicAnchorSetTime[a.Key] = double.NaN;
atime_head = cs.StampedContainer.Time; atime_head = cs.StampedContainer.Time;
atime_tail = atime_head + cs.StampedContainer.Duration; atime_tail = atime_head + cs.StampedContainer.Duration;
skinContainer.MatchDynamic(cs); MatchDynamic(cs, 0);
foreach (var i in _comps) i.Tick(skinContainer, cs.Time);
if (cs.Active) PushAnchorEvent(cs.Time, a_cur); if (cs.Active) PushAnchorEvent(cs.Time, a_cur);
if (Alive) { if (double.IsNaN(DynamicAnchorSetTime[_a_head])) DynamicAnchorSetTime[_a_head] = atime_head;
if (!DynamicAnchorSet[_a_head]) PushAnchorEvent(atime_head, a_head, -1, true); if (double.IsNaN(DynamicAnchorSetTime[_a_tail])) DynamicAnchorSetTime[_a_tail] = atime_tail;
if (!DynamicAnchorSet[_a_tail]) PushAnchorEvent(atime_tail, a_tail, 1, true); foreach (var t in DynamicAnchorSetTime) {
foreach (var anchors in Anchors.Values) foreach (var anchor in anchors) anchor.Transform.gameObject.SetActive(false); if (double.IsNaN(t.Value)) continue;
int priority = 0;
bool forced = true;
if (t.Key == _a_head) { priority = -1; }
else if (t.Key == _a_tail) { priority = 1; }
else forced = false;
PushAnchorEvent(t.Value, DynamicAnchors[t.Key], priority, forced);
} }
foreach (var anchors in Anchors) foreach (var anchor in anchors.Value) anchor.Transform.gameObject.SetActive(false);
} }
static readonly SimpleObjectPool<StampedEvent.Anchor> anchorEvPool static readonly SimpleObjectPool<StampedEvent.Anchor> anchorEvPool
= new SimpleObjectPool<StampedEvent.Anchor>(1024); = new SimpleObjectPool<StampedEvent.Anchor>(1024);
public void PushAnchorEvent(double time, int name) {
Anchor anchor;
if (!DynamicAnchors.TryGetValue(name, out anchor))
throw new ArgumentException(string.Format("Specified anchor \"{0}\" not found", IdentifierManager.SharedInstance.Retrieve(name)));
if (DynamicAnchorSet[name])
throw new InvalidOperationException(string.Format("Specified anchor \"{0}\" has been set", IdentifierManager.SharedInstance.Retrieve(name)));
int priority = 0;
bool forced = true;
if (name == _a_head) { priority = -1; atime_head = time; }
else if (name == _a_tail) { priority = 1; atime_tail = time; }
else forced = false;
PushAnchorEvent(time, anchor, priority, forced);
DynamicAnchorSet[name] = true;
}
void PushAnchorEvent(double time, Anchor anchor, int priority = 0, bool forced = false) { void PushAnchorEvent(double time, Anchor anchor, int priority = 0, bool forced = false) {
var tev = anchorEvPool.Rent(); var tev = anchorEvPool.Rent();
tev.Time = time; tev.Time = time;
@@ -233,5 +237,28 @@ namespace Cryville.Crtr.Event {
} }
#endregion #endregion
#endregion #endregion
#region ISkinnableGroup
public abstract string TypeName { get; }
public SkinContext SkinContext { get; private set; }
Anchor _openedAnchor;
public int OpenedAnchorName { get { return _openedAnchor == null ? 0 : _openedAnchor.Name; } }
public bool TryGetAnchorsByName(int name, out IReadOnlyCollection<Anchor> result) {
List<Anchor> anchors;
var ret = Anchors.TryGetValue(name, out anchors);
result = anchors;
return ret;
}
void ISkinnableGroup.RegisterAnchor(int name) {
RegisterAnchor(name, true);
}
public void PushAnchorEvent(double time, int name) {
if (!DynamicAnchors.ContainsKey(name))
throw new ArgumentException(string.Format("Specified anchor \"{0}\" not found", IdentifierManager.SharedInstance.Retrieve(name)));
if (name == _a_head) atime_head = time;
else if (name == _a_tail) atime_tail = time;
DynamicAnchorSetTime[name] = time;
}
#endregion
} }
} }

View File

@@ -434,14 +434,14 @@ namespace Cryville.Crtr.Event {
public void BroadcastPreInit() { public void BroadcastPreInit() {
Handler.PreInit(); Handler.PreInit();
foreach (var c in Children.Values) { foreach (var c in Children) {
c.BroadcastPreInit(); c.Value.BroadcastPreInit();
} }
} }
public void BroadcastPostInit() { public void BroadcastPostInit() {
Handler.PostInit(); Handler.PostInit();
foreach (var c in Children.Values) { foreach (var c in Children) {
c.BroadcastPostInit(); c.Value.BroadcastPostInit();
} }
} }
@@ -461,8 +461,8 @@ namespace Cryville.Crtr.Event {
public void Anchor() { public void Anchor() {
Handler.Anchor(); Handler.Anchor();
foreach (var ls in Children.Values) { foreach (var ls in Children) {
if (ls.Handler.Alive) ls.Anchor(); if (ls.Value.Handler.Alive) ls.Value.Anchor();
} }
} }
#endregion #endregion

View File

@@ -63,8 +63,8 @@ namespace Cryville.Crtr.Event {
s = RootState; s = RootState;
} }
AddState(s); AddState(s);
foreach (var c in s.Children.Values) foreach (var c in s.Children)
Expand(c); Expand(c.Value);
} }
public void AddState(ContainerState s) { public void AddState(ContainerState s) {
@@ -73,13 +73,13 @@ namespace Cryville.Crtr.Event {
} }
void AttachBus() { void AttachBus() {
foreach (var s in states.Values) foreach (var s in states)
s.Bus = this; s.Value.Bus = this;
} }
public void AttachSystems(PdtSkin skin, Judge judge) { public void AttachSystems(PdtSkin skin, Judge judge) {
foreach (var s in states.Values) foreach (var s in states)
s.AttachSystems(skin, judge); s.Value.AttachSystems(skin, judge);
} }
List<StampedEvent.Temporary> tempEvents = new List<StampedEvent.Temporary>(); List<StampedEvent.Temporary> tempEvents = new List<StampedEvent.Temporary>();

View File

@@ -14,7 +14,7 @@ namespace Cryville.Crtr.Event {
internal class MotionCachePool : CategorizedPool<Identifier, MotionCache> { internal class MotionCachePool : CategorizedPool<Identifier, MotionCache> {
private class Bucket : ObjectPool<MotionCache> { private class Bucket : ObjectPool<MotionCache> {
readonly MotionRegistry _reg; readonly MotionRegistry _reg;
public Bucket(string name, int capacity) : base(capacity) { public Bucket(Identifier name, int capacity) : base(capacity) {
_reg = ChartPlayer.motionRegistry[name]; _reg = ChartPlayer.motionRegistry[name];
} }
protected override MotionCache Construct() { protected override MotionCache Construct() {

View File

@@ -6,7 +6,7 @@ namespace Cryville.Crtr.Event {
internal class RMVPool : CategorizedPool<Identifier, RealtimeMotionValue> { internal class RMVPool : CategorizedPool<Identifier, RealtimeMotionValue> {
private class Bucket : ObjectPool<RealtimeMotionValue> { private class Bucket : ObjectPool<RealtimeMotionValue> {
readonly MotionRegistry _reg; readonly MotionRegistry _reg;
public Bucket(string name, int capacity) : base(capacity) { public Bucket(Identifier name, int capacity) : base(capacity) {
_reg = ChartPlayer.motionRegistry[name]; _reg = ChartPlayer.motionRegistry[name];
} }
protected override RealtimeMotionValue Construct() { protected override RealtimeMotionValue Construct() {

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: dbc046e7cabacbb4fbf74520399a7340 guid: b35ffffce02252548a66e18cf98050e2
folderAsset: yes folderAsset: yes
DefaultImporter: DefaultImporter:
externalObjects: {} externalObjects: {}

View File

@@ -0,0 +1,107 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using UnityEngine.Scripting;
namespace Cryville.Crtr.Extension {
[Preserve]
public static class RefTypes {
[Preserve]
public static void PreserveEnumerable() {
IEnumerable<object> p = Enumerable.Empty<object>();
p.All(i => false);
p.Any();
p.Any(i => false);
p.Cast<object>();
p.Concat(Enumerable.Empty<object>());
p.Contains(null);
p.Count();
p.Count(i => false);
p.DefaultIfEmpty();
p.DefaultIfEmpty(null);
p.Distinct();
p.ElementAt(0);
p.ElementAtOrDefault(0);
p.First();
p.First(i => false);
p.FirstOrDefault();
p.FirstOrDefault(i => false);
p.GetEnumerator();
p.Last();
p.Last(i => false);
p.LastOrDefault();
p.LastOrDefault(i => false);
p.LongCount();
p.LongCount(i => false);
p.OrderBy(i => i).ThenBy(i => i);
p.OrderByDescending(i => i).ThenByDescending(i => i);
p.Reverse();
p.Select(i => i);
p.Select((i, j) => false);
p.SequenceEqual(p);
p.Single();
p.Single(i => false);
p.SingleOrDefault();
p.SingleOrDefault(i => false);
p.Skip(0);
p.SkipLast(0);
p.SkipWhile(i => false);
p.SkipWhile((i, j) => false);
p.Take(0);
p.TakeLast(0);
p.TakeWhile(i => false);
p.TakeWhile((i, j) => false);
p.ToArray();
p.ToDictionary(i => new object());
p.ToDictionary(i => new object(), i => new object());
p.ToHashSet();
p.ToList();
p.Where(i => false);
p.Where((i, j) => false);
}
[Preserve]
public static void PreserveBinaryReader() {
BinaryReader p = new BinaryReader(null);
p.Close();
p.Dispose();
p.PeekChar();
p.Read();
p.ReadBoolean();
p.ReadByte();
p.ReadBytes(0);
p.ReadChar();
p.ReadChars(0);
p.ReadDouble();
p.ReadInt16();
p.ReadInt32();
p.ReadInt64();
p.ReadSByte();
p.ReadSingle();
p.ReadUInt16();
p.ReadUInt32();
p.ReadUInt64();
}
[Preserve]
public static void PreserveStreamReader() {
object _;
StreamReader p = new StreamReader((Stream)null);
p.Close();
_ = p.CurrentEncoding;
p.DiscardBufferedData();
p.Dispose();
_ = p.EndOfStream;
p.Peek();
p.Read();
p.ReadBlock(null, 0, 0);
p.ReadLine();
p.ReadToEnd();
}
[Preserve]
public static void PreserveConvert() {
Convert.ChangeType(0, typeof(byte));
Convert.ChangeType(0, typeof(byte), CultureInfo.InvariantCulture);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 29a6376ce10b77e4099d2613876f9549
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,189 +0,0 @@
using Cryville.Common;
using Cryville.Common.Math;
using Cryville.Crtr.Browsing;
using Newtonsoft.Json;
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 = { ".bestdori" };
public override string[] GetSupportedFormats() {
return SUPPORTED_FORMATS;
}
public override IEnumerable<Resource> ConvertFrom(FileInfo file) {
List<Resource> result = new List<Resource>();
List<BestdoriChartEvent> src;
using (var reader = new StreamReader(file.FullName)) {
src = JsonConvert.DeserializeObject<List<BestdoriChartEvent>>(reader.ReadToEnd());
}
var group = new Chart.Group() {
tracks = new List<Chart.Track>(),
notes = new List<Chart.Note>(),
motions = new List<Chart.Motion>(),
};
Chart chart = new Chart {
format = 2,
time = new BeatTime(0, 0, 1),
ruleset = "bang_dream_girls_band_party",
sigs = new List<Chart.Signature>(),
sounds = new List<Chart.Sound>(),
motions = new List<Chart.Motion>(),
groups = new List<Chart.Group> { group },
};
var tm = new BeatTimeTimingModel();
string bgm = null;
double endbeat = 0;
foreach (var ev in src) {
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;
bgm = StringUtils.TrimExt(tev.data);
var name = "bang_dream_girls_band_party__" + bgm;
result.Add(new SongResource(name, new FileInfo(Path.Combine(file.Directory.FullName, tev.data))));
chart.sounds.Add(new Chart.Sound { time = ToBeatTime(tev.beat), id = name });
}
else if (ev is BestdoriChartEvent.BPM) {
var tev = (BestdoriChartEvent.BPM)ev;
tm.BPM = tev.bpm;
chart.sigs.Add(new Chart.Signature { time = ToBeatTime(tev.beat), tempo = (float)tev.bpm });
}
else if (ev is BestdoriChartEvent.Single) {
var tev = (BestdoriChartEvent.Single)ev;
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(CultureInfo.InvariantCulture) } },
});
}
else if (ev is BestdoriChartEvent.Long) {
var tev = (BestdoriChartEvent.Long)ev;
var c1 = tev.connections[tev.connections.Count - 1];
var note = new Chart.Note {
time = ToBeatTime(tev.connections[0].beat),
endtime = ToBeatTime(c1.beat),
judges = new List<Chart.Judge>(),
};
for (int i = 0; i < tev.connections.Count; i++) {
BestdoriChartEvent.Connection c = tev.connections[i];
var motion = new Chart.Motion { motion = "track:" + c.lane.ToString(CultureInfo.InvariantCulture) };
if (i == 0) {
note.judges.Add(new Chart.Judge { name = "single" });
note.motions.Add(motion);
}
else {
var cbeat = motion.endtime = ToBeatTime(c.beat);
if (i > 1) motion.time = ToBeatTime(tev.connections[i - 1].beat);
note.motions.Add(motion);
if (i == tev.connections.Count - 1)
note.judges.Add(new Chart.Judge { time = cbeat, name = c.flick ? "longend_flick" : "longend" });
else if (!c.hidden)
note.judges.Add(new Chart.Judge { time = cbeat, name = "longnode" });
}
}
if (c1.beat > endbeat) endbeat = c1.beat;
group.notes.Add(note);
}
else throw new NotImplementedException("Unsupported event: " + ev.type);
}
if (bgm == null) throw new FormatException("Chart contains no song");
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)tm.Time,
song = new SongMetaInfo {
name = bgm,
author = "©BanG Dream! Project ©Craft Egg Inc. ©bushiroad",
}
}));
return result;
}
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);
}
#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; } }
}
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;
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);
}
}
}
}
}

View File

@@ -1,27 +0,0 @@
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(),
};
}
}
}

View File

@@ -1,9 +0,0 @@
fileFormatVersion: 2
guid: dfd44d1c0681e4842a1f031556519042
folderAsset: yes
timeCreated: 1637936550
licenseType: Free
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,225 +0,0 @@
using Cryville.Crtr.Browsing;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
namespace Cryville.Crtr.Extensions.Malody {
public class MalodyChartConverter : ResourceConverter {
static readonly string[] SUPPORTED_FORMATS = { ".mc", ".mcz" };
static readonly string[] MODES = { "key", "step", "dj", "catch", "pad", "taiko", "ring", "slide", "live" };
public override string[] GetSupportedFormats() {
return SUPPORTED_FORMATS;
}
public override IEnumerable<Resource> ConvertFrom(FileInfo file) {
List<Resource> result = new List<Resource>();
MalodyChart src;
if (file.Extension != ".mc") throw new NotImplementedException("mcz file is not supported yet");
using (var reader = new StreamReader(file.FullName)) {
src = JsonConvert.DeserializeObject<MalodyChart>(reader.ReadToEnd());
}
if (src.meta.mode != 0) throw new NotImplementedException(string.Format("{0} mode is not supported yet", MODES[src.meta.mode]));
var ruleset = "malody!" + MODES[src.meta.mode];
if (src.meta.mode == 0) {
ruleset += "." + src.meta.mode_ext.column.ToString(CultureInfo.InvariantCulture) + "k";
}
ChartMeta meta = new ChartMeta() {
name = src.meta.version,
author = src.meta.creator,
song = new SongMetaInfo() {
name = src.meta.song.titleorg != null ? src.meta.song.titleorg : src.meta.song.title,
author = src.meta.song.artistorg != null ? src.meta.song.artistorg : src.meta.song.artist,
},
ruleset = ruleset,
};
Chart chart = new Chart {
format = 2,
time = new BeatTime(-4, 0, 1),
ruleset = ruleset,
sigs = new List<Chart.Signature>(),
sounds = new List<Chart.Sound>(),
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);
int col = src.meta.mode_ext.column;
IEnumerable<MalodyChart.IEvent> events = src.time.Cast<MalodyChart.IEvent>();
if (src.effect != null) events = events.Concat(src.effect.Cast<MalodyChart.IEvent>());
events = events.Concat(src.note.Cast<MalodyChart.IEvent>());
List<MalodyChart.IEvent> endEvents = new List<MalodyChart.IEvent>();
foreach (var ev in events)
if (ev.endbeat != null)
endEvents.Add(new MalodyChart.EndEvent {
beat = ev.endbeat,
StartEvent = ev,
});
events = events.Concat(endEvents)
.OrderBy(e => e.beat[0] + (float)e.beat[1] / e.beat[2])
.ThenBy(e => e.Priority);
Dictionary<MalodyChart.IEvent, StartEventState> longEvents
= new Dictionary<MalodyChart.IEvent, StartEventState>();
float? baseBpm = null;
var tm = new FractionalBeatTimeTimingModel();
foreach (var ev in events) {
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;
tm.BPM = tev.bpm;
chart.sigs.Add(new Chart.Signature {
time = beat,
tempo = tev.bpm,
});
chart.motions.Add(new Chart.Motion {
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 = beat,
motion = "svm:" + tev.scroll.Value.ToString(CultureInfo.InvariantCulture)
});
}
else if (ev is MalodyChart.Note) {
var tev = (MalodyChart.Note)ev;
if (tev.type == 1) {
if (tev.beat[0] == 0 && tev.beat[1] == 0) {
var res = new SongResource(meta.song.name, new FileInfo(file.DirectoryName + "/" + tev.sound));
result.Add(res);
chart.sounds.Add(new Chart.Sound {
time = new BeatTime(0, 0, 1),
id = res.Name,
offset = -tev.offset / 1000f,
});
}
else throw new NotImplementedException("Key sounds are not supported yet");
}
else {
var rn = new Chart.Note() {
time = beat,
motions = new List<Chart.Motion> {
new Chart.Motion() { motion = "track:" + tev.column.ToString(CultureInfo.InvariantCulture) }
},
};
if (tev.endbeat != null) {
rn.endtime = new BeatTime(tev.endbeat[0], tev.endbeat[1], tev.endbeat[2]);
longEvents.Add(ev, new StartEventState {
Destination = rn,
Time = tm.Time,
});
}
group.notes.Add(rn);
}
}
else if (ev is MalodyChart.EndEvent) {
var tev = (MalodyChart.EndEvent)ev;
if (tev.StartEvent is MalodyChart.Note) {
var sev = tev.StartEvent;
longEvents.Remove(sev);
}
else throw new NotSupportedException("Unrecognized long event");
}
else throw new NotSupportedException("Unrecognized event");
}
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) {
meta.cover = src.meta.background;
}
result.Add(new RawChartResource(chartName, chart, meta));
return result;
}
struct StartEventState {
public double Time { get; set; }
public ChartEvent Destination { get; set; }
}
#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;
}
public string background;
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; } }
}
}
#pragma warning restore IDE1006
}
}

View File

@@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: b3624013a6911ba45933085332724ff1
timeCreated: 1637936498
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,26 +0,0 @@
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;
}
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 3c9beaff62143a2468e18ad4642232c0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,153 +0,0 @@
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; } }
}
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: b073cac7ce0d41a4f8ca589845678aa2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,24 +0,0 @@
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;
}
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 68bacf7746cbeea42a78a7d55cfdbea0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,56 +0,0 @@
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;
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 5c4a1fab8f53dd742ba6501d682eb7f6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: b9bd9e24d7c553341a2a12391843542f guid: 3fe9f91db8da80f459bcf70ff680644f
folderAsset: yes folderAsset: yes
DefaultImporter: DefaultImporter:
externalObjects: {} externalObjects: {}

View File

@@ -1,9 +1,10 @@
using Newtonsoft.Json; using Cryville.Crtr.Extension;
using Newtonsoft.Json;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text; using System.Text;
namespace Cryville.Crtr.Browsing { namespace Cryville.Crtr.Extensions.Umg {
public class ChartResourceImporter : ResourceConverter { public class ChartResourceImporter : ResourceConverter {
static readonly string[] SUPPORTED_FORMATS = { ".umgc" }; static readonly string[] SUPPORTED_FORMATS = { ".umgc" };
public override string[] GetSupportedFormats() { public override string[] GetSupportedFormats() {
@@ -19,4 +20,13 @@ namespace Cryville.Crtr.Browsing {
} }
} }
} }
public class ChartResource : FileResource {
public ChartResource(string name, FileInfo master) : base(name, master) {
using (var reader = new StreamReader(master.FullName)) {
var meta = JsonConvert.DeserializeObject<ChartMeta>(reader.ReadToEnd());
Attachments.Add(new FileInfo(Path.Combine(master.Directory.FullName, meta.data + ".json")));
if (meta.cover != null) Attachments.Add(new FileInfo(Path.Combine(master.Directory.FullName, meta.cover)));
}
}
}
} }

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 168366bb891392b42a1d0a6bfa068ff3 guid: bfcd614ec96fbe543aa2b2f1630aac73
MonoImporter: MonoImporter:
externalObjects: {} externalObjects: {}
serializedVersion: 2 serializedVersion: 2

View File

@@ -0,0 +1,18 @@
using Cryville.Crtr.Extension;
using System.Collections.Generic;
namespace Cryville.Crtr.Extensions.Umg {
public class Extension : ExtensionInterface {
public override IEnumerable<ResourceConverter> GetResourceConverters() {
return new ResourceConverter[] {
new ChartResourceImporter(),
new RulesetResourceImporter(),
new SkinResourceImporter(),
};
}
public override IEnumerable<LocalResourceFinder> GetResourceFinders() {
return null;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 323b670cbdea58644ac9ba20fc4c1a89
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,9 +1,10 @@
using Newtonsoft.Json; using Cryville.Crtr.Extension;
using Newtonsoft.Json;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text; using System.Text;
namespace Cryville.Crtr.Browsing { namespace Cryville.Crtr.Extensions.Umg {
public class RulesetResourceImporter : ResourceConverter { public class RulesetResourceImporter : ResourceConverter {
static readonly string[] SUPPORTED_FORMATS = { ".umgr" }; static readonly string[] SUPPORTED_FORMATS = { ".umgr" };
public override string[] GetSupportedFormats() { public override string[] GetSupportedFormats() {
@@ -17,4 +18,12 @@ namespace Cryville.Crtr.Browsing {
} }
} }
} }
public class RulesetResource : FileResource {
public RulesetResource(string name, FileInfo master) : base(name, master) {
using (var reader = new StreamReader(master.FullName)) {
var meta = JsonConvert.DeserializeObject<Ruleset>(reader.ReadToEnd());
Attachments.Add(new FileInfo(Path.Combine(master.Directory.FullName, meta.data + ".pdt")));
}
}
}
} }

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: f2c1531e76f19a647865f7ec335561cd guid: 9e856b78a468f644191d62ab489ae089
MonoImporter: MonoImporter:
externalObjects: {} externalObjects: {}
serializedVersion: 2 serializedVersion: 2

View File

@@ -0,0 +1,34 @@
using Cryville.Crtr.Extension;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace Cryville.Crtr.Extensions.Umg {
public class SkinResourceImporter : ResourceConverter {
static readonly string[] SUPPORTED_FORMATS = { ".umgs" };
public override string[] GetSupportedFormats() {
return SUPPORTED_FORMATS;
}
public override IEnumerable<Resource> ConvertFrom(FileInfo file) {
using (StreamReader reader = new StreamReader(file.FullName, Encoding.UTF8)) {
var data = JsonConvert.DeserializeObject<Skin>(reader.ReadToEnd());
return new Resource[] { new SkinResource(data.name, file) };
}
}
}
public class SkinResource : FileResource {
public string RulesetName { get; private set; }
public SkinResource(string name, FileInfo master) : base(name, master) {
using (var reader = new StreamReader(master.FullName)) {
var meta = JsonConvert.DeserializeObject<Skin>(reader.ReadToEnd());
RulesetName = meta.ruleset;
Attachments.Add(new FileInfo(Path.Combine(master.Directory.FullName, meta.data + ".pdt")));
foreach (var frame in meta.frames) {
Attachments.Add(new FileInfo(Path.Combine(master.Directory.FullName, frame)));
}
}
}
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 9904b4c21758c5046afc341fe2fa8845 guid: 2afd6abf146c2ee45ab749477b8c7fda
MonoImporter: MonoImporter:
externalObjects: {} externalObjects: {}
serializedVersion: 2 serializedVersion: 2

View File

@@ -1,383 +0,0 @@
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.05;
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>();
bool ftc = false;
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 NotImplementedException("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, ref ftc, section, line);
}
}
if (meta.ruleset == "osu!mania") {
chart.ruleset = meta.ruleset += "." + diff.CircleSize.ToString(CultureInfo.InvariantCulture) + "k";
}
if (!ftc) throw new InvalidOperationException("Unconvertible chart: no timing point is present in this beatmap");
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 { time = tm.FractionalBeatTime, 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, ref bool ftc, 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, ref ftc, 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 NotImplementedException("osu!standard mode is not supported yet");
case 1: /*ruleset += "taiko";*/ throw new NotImplementedException("osu!taiko mode is not supported yet");
case 2: /*ruleset += "catch";*/ throw new NotImplementedException("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, ref bool ftc, 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");
var ev = new osuEvent.TimingChange { StartTime = time, BeatLength = beatLength, TimeSignature = timeSignature };
if (!ftc) {
ftc = true;
ev.StartTime = time % beatLength - beatLength;
}
evs.Add(ev);
}
// 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
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 82838dd8639c2244caf3c830edfbc59c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,24 +0,0 @@
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;
}
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 365d879536c05284fa2335a7676c6cf4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -24,7 +24,7 @@ namespace Cryville.Crtr {
get; get;
private set; private set;
} }
public readonly static string FileProtocolPrefix public static readonly string FileProtocolPrefix
#if UNITY_STANDALONE_WIN #if UNITY_STANDALONE_WIN
= "file:///"; = "file:///";
#elif UNITY_ANDROID #elif UNITY_ANDROID
@@ -37,9 +37,9 @@ namespace Cryville.Crtr {
public static SimpleSequencerSource AudioSequencer; public static SimpleSequencerSource AudioSequencer;
public static SimpleSequencerSession AudioSession; public static SimpleSequencerSession AudioSession;
public static InputManager InputManager; public static InputManager InputManager;
public readonly static NetworkTaskWorker NetworkTaskWorker = new NetworkTaskWorker(); public static readonly NetworkTaskWorker NetworkTaskWorker = new NetworkTaskWorker();
public readonly static JsonSerializerSettings GlobalJsonSerializerSettings public static readonly JsonSerializerSettings GlobalJsonSerializerSettings
= new JsonSerializerSettings() { = new JsonSerializerSettings() {
DefaultValueHandling = DefaultValueHandling.Ignore, DefaultValueHandling = DefaultValueHandling.Ignore,
}; };
@@ -104,16 +104,16 @@ namespace Cryville.Crtr {
} }
ChartPlayer.motionRegistry = new Dictionary<Identifier, MotionRegistry> { ChartPlayer.motionRegistry = new Dictionary<Identifier, MotionRegistry> {
{ "pt" , new MotionRegistry(typeof(VecPt)) }, { new Identifier("pt") , new MotionRegistry(typeof(VecPt)) },
{ "dir" , new MotionRegistry(typeof(Vec3)) }, { new Identifier("dir") , new MotionRegistry(typeof(Vec3)) },
{ "normal" , new MotionRegistry(typeof(Vec3)) }, { new Identifier("normal") , new MotionRegistry(typeof(Vec3)) },
{ "sv" , new MotionRegistry(new VecPtComp(0f, 0f), new VecPtComp(0f, 1f)) }, { new Identifier("sv") , new MotionRegistry(new VecPtComp(0f, 0f), new VecPtComp(0f, 1f)) },
{ "svm" , new MotionRegistry(new Vec1m(1f)) }, { new Identifier("svm") , new MotionRegistry(new Vec1m(1f)) },
{ "dist" , new MotionRegistry(new VecPtComp(0f, 0f), new VecPtComp(0f, float.PositiveInfinity)) }, { new Identifier("dist") , new MotionRegistry(new VecPtComp(0f, 0f), new VecPtComp(0f, float.PositiveInfinity)) },
{ "corner" , new MotionRegistry(typeof(VecI1)) }, { new Identifier("corner") , new MotionRegistry(typeof(VecI1)) },
{ "ctrl0" , new MotionRegistry(typeof(VecCtrl)) }, { new Identifier("ctrl0") , new MotionRegistry(typeof(VecCtrl)) },
{ "ctrl1" , new MotionRegistry(typeof(VecCtrl)) }, { new Identifier("ctrl1") , new MotionRegistry(typeof(VecCtrl)) },
{ "track" , new MotionRegistry(typeof(Vec1)) }, { new Identifier("track") , new MotionRegistry(typeof(Vec1)) },
}; };
var dir = new DirectoryInfo(Settings.Default.GameDataPath + "/charts"); var dir = new DirectoryInfo(Settings.Default.GameDataPath + "/charts");

View File

@@ -18,11 +18,13 @@ namespace Cryville.Crtr {
public static void LoadDefault() { public static void LoadDefault() {
if (loaded) return; if (loaded) return;
Components.Add("anim", typeof(SkinAnimation));
Components.Add("image", typeof(SpritePlane)); Components.Add("image", typeof(SpritePlane));
Components.Add("mesh", typeof(MeshBase)); Components.Add("mesh", typeof(MeshBase));
Components.Add("polysec", typeof(PolygonSGO)); Components.Add("polysec", typeof(PolygonSGO));
Components.Add("rect", typeof(SpriteRect)); Components.Add("rect", typeof(SpriteRect));
Components.Add("scale3", typeof(SpriteScale3)); Components.Add("scale3", typeof(SpriteScale3));
Components.Add("sec", typeof(SectionalGameObject));
Components.Add("sprite", typeof(SpriteBase)); Components.Add("sprite", typeof(SpriteBase));
Components.Add("text", typeof(SpriteText)); Components.Add("text", typeof(SpriteText));
@@ -31,6 +33,9 @@ namespace Cryville.Crtr {
Materials.Add("-SpriteMat", Resources.Load<Material>("Materials/SpriteMat")); Materials.Add("-SpriteMat", Resources.Load<Material>("Materials/SpriteMat"));
Shaders.Add("default", Shader.Find("Sprites/Default"));
Shaders.Add("additive", Shader.Find("Sprites/Additive"));
loaded = true; loaded = true;
} }
} }

View File

@@ -4,7 +4,8 @@ using Cryville.Common.Unity.Input;
using Cryville.Crtr.Config; using Cryville.Crtr.Config;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using System.Runtime.Serialization;
using RVector3 = UnityEngine.Vector3;
namespace Cryville.Crtr { namespace Cryville.Crtr {
public class InputProxy : IDisposable { public class InputProxy : IDisposable {
@@ -12,18 +13,17 @@ namespace Cryville.Crtr {
readonly PdtRuleset _ruleset; readonly PdtRuleset _ruleset;
readonly Judge _judge; readonly Judge _judge;
public InputProxy(PdtRuleset ruleset, Judge judge) { public InputProxy(PdtRuleset ruleset, Judge judge) {
unsafe { for (int i = 0; i <= MAX_DEPTH; i++) {
fixed (byte* ptr = _vecbuf) { var vecsrc = new InputVectorSrc();
*(int*)(ptr + 3 * sizeof(float)) = PdtInternalType.Number; _vecsrcs[i] = vecsrc;
} _vecops[i] = new InputVectorOp(vecsrc);
} }
_vecsrc = new PropSrc.Arbitrary(PdtInternalType.Vector, _vecbuf);
_etor = ChartPlayer.etor; _etor = ChartPlayer.etor;
_ruleset = ruleset; _ruleset = ruleset;
_judge = judge; _judge = judge;
foreach (var i in ruleset.inputs) { foreach (var i in ruleset.inputs) {
_use.Add(i.Key, 0); _use.Add(i.Key, 0);
_rev.Add(i.Key, new List<string>()); _rev.Add(i.Key, new List<Identifier>());
} }
foreach (var i in ruleset.inputs) { foreach (var i in ruleset.inputs) {
if (i.Value.pass != null) { if (i.Value.pass != null) {
@@ -33,15 +33,15 @@ namespace Cryville.Crtr {
} }
} }
#region Settings #region Settings
readonly Dictionary<string, InputProxyEntry> _tproxies = new Dictionary<string, InputProxyEntry>(); readonly Dictionary<Identifier, InputProxyEntry> _tproxies = new Dictionary<Identifier, InputProxyEntry>();
readonly Dictionary<InputSource, InputProxyEntry> _sproxies = new Dictionary<InputSource, InputProxyEntry>(); readonly Dictionary<InputSource, InputProxyEntry> _sproxies = new Dictionary<InputSource, InputProxyEntry>();
readonly Dictionary<string, int> _use = new Dictionary<string, int>(); readonly Dictionary<Identifier, int> _use = new Dictionary<Identifier, int>();
readonly Dictionary<string, List<string>> _rev = new Dictionary<string, List<string>>(); readonly Dictionary<Identifier, List<Identifier>> _rev = new Dictionary<Identifier, List<Identifier>>();
public event EventHandler<ProxyChangedEventArgs> ProxyChanged; public event EventHandler<ProxyChangedEventArgs> ProxyChanged;
public void LoadFrom(Dictionary<string, RulesetConfig.InputEntry> config) { public void LoadFrom(Dictionary<string, RulesetConfig.InputEntry> config) {
foreach (var cfg in config) { foreach (var cfg in config) {
Set(new InputProxyEntry { Set(new InputProxyEntry {
Target = cfg.Key, Target = new Identifier(cfg.Key),
Source = new InputSource { Source = new InputSource {
Handler = Game.InputManager.GetHandler(cfg.Value.handler), Handler = Game.InputManager.GetHandler(cfg.Value.handler),
Type = cfg.Value.type Type = cfg.Value.type
@@ -52,7 +52,7 @@ namespace Cryville.Crtr {
public void SaveTo(Dictionary<string, RulesetConfig.InputEntry> config) { public void SaveTo(Dictionary<string, RulesetConfig.InputEntry> config) {
config.Clear(); config.Clear();
foreach (var p in _tproxies) { foreach (var p in _tproxies) {
config.Add(p.Key, new RulesetConfig.InputEntry { config.Add((string)p.Key.Name, new RulesetConfig.InputEntry {
handler = ReflectionHelper.GetNamespaceQualifiedName(p.Value.Source.Value.Handler.GetType()), handler = ReflectionHelper.GetNamespaceQualifiedName(p.Value.Source.Value.Handler.GetType()),
type = p.Value.Source.Value.Type type = p.Value.Source.Value.Type
}); });
@@ -81,14 +81,16 @@ namespace Cryville.Crtr {
public bool IsUsed(InputSource src) { public bool IsUsed(InputSource src) {
return _sproxies.ContainsKey(src); return _sproxies.ContainsKey(src);
} }
public bool IsCompleted { public bool IsCompleted() {
get { foreach (var i in _use)
foreach (var i in _use) if (!IsCompleted(i.Key)) return false;
if (i.Value == 0 && !_tproxies.ContainsKey(i.Key)) return false; return true;
return true;
}
} }
void IncrementUseRecursive(string name) { bool IsCompleted(Identifier name) {
return name.Key == _var_pause || _use[name] != 0 || _tproxies.ContainsKey(name);
}
static readonly int _var_pause = IdentifierManager.SharedInstance.Request("pause");
void IncrementUseRecursive(Identifier name) {
BroadcastProxyChanged(name); BroadcastProxyChanged(name);
var passes = _ruleset.inputs[name].pass; var passes = _ruleset.inputs[name].pass;
if (passes != null) { if (passes != null) {
@@ -98,14 +100,14 @@ namespace Cryville.Crtr {
} }
} }
} }
void IncrementReversedUseRecursive(string name) { void IncrementReversedUseRecursive(Identifier name) {
foreach (var p in _rev[name]) { foreach (var p in _rev[name]) {
_use[p]++; _use[p]++;
BroadcastProxyChanged(p); BroadcastProxyChanged(p);
IncrementReversedUseRecursive(p); IncrementReversedUseRecursive(p);
} }
} }
void DecrementUseRecursive(string name) { void DecrementUseRecursive(Identifier name) {
BroadcastProxyChanged(name); BroadcastProxyChanged(name);
var passes = _ruleset.inputs[name].pass; var passes = _ruleset.inputs[name].pass;
if (passes != null) { if (passes != null) {
@@ -115,20 +117,20 @@ namespace Cryville.Crtr {
} }
} }
} }
void DecrementReversedUseRecursive(string name) { void DecrementReversedUseRecursive(Identifier name) {
foreach (var p in _rev[name]) { foreach (var p in _rev[name]) {
_use[p]--; _use[p]--;
BroadcastProxyChanged(p); BroadcastProxyChanged(p);
DecrementReversedUseRecursive(p); DecrementReversedUseRecursive(p);
} }
} }
void BroadcastProxyChanged(string name) { void BroadcastProxyChanged(Identifier name) {
var del = ProxyChanged; var del = ProxyChanged;
if (del != null) del(this, this[name]); if (del != null) del(this, this[name]);
} }
public ProxyChangedEventArgs this[string name] { public ProxyChangedEventArgs this[Identifier name] {
get { get {
return new ProxyChangedEventArgs(name, _tproxies.ContainsKey(name) ? _tproxies[name].Source : null, _use[name] > 0); return new ProxyChangedEventArgs(name, _tproxies.ContainsKey(name) ? _tproxies[name].Source : null, _use[name] > 0, !IsCompleted(name));
} }
} }
#endregion #endregion
@@ -164,22 +166,66 @@ namespace Cryville.Crtr {
protected void Dispose(bool disposing) { protected void Dispose(bool disposing) {
if (disposing) { if (disposing) {
Deactivate(); Deactivate();
foreach (var proxy in _tproxies.Values) { foreach (var proxy in _tproxies) {
proxy.Source.Value.Handler.OnInput -= OnInput; proxy.Value.Source.Value.Handler.OnInput -= OnInput;
} }
} }
} }
readonly object _lock = new object(); readonly object _lock = new object();
static readonly int _var_value = IdentifierManager.SharedInstance.Request("value"); static readonly int _var_value = IdentifierManager.SharedInstance.Request("value");
static readonly PropOp.Arbitrary _arbop = new PropOp.Arbitrary(); const int MAX_DEPTH = 15;
readonly byte[] _vecbuf = new byte[3 * sizeof(float) + sizeof(int)]; const int MAX_DIMENSION = 3;
readonly PropSrc.Arbitrary _vecsrc; readonly InputVectorSrc[] _vecsrcs = new InputVectorSrc[MAX_DEPTH + 1];
readonly InputVectorOp[] _vecops = new InputVectorOp[MAX_DEPTH + 1];
unsafe class InputVectorSrc : PropSrc.FixedBuffer {
public InputVectorSrc() : base(PdtInternalType.Vector, MAX_DIMENSION * sizeof(float) + sizeof(int)) {
fixed (byte* ptr = buf) {
*(int*)(ptr + MAX_DIMENSION * sizeof(float)) = PdtInternalType.Number;
}
}
public bool IsNull { get; set; }
public void Set(RVector3 vec) {
fixed (byte* _ptr = buf) {
*(RVector3*)_ptr = vec;
}
Invalidate();
}
}
class InputVectorOp : PropOp {
readonly InputVectorSrc _src;
public InputVectorOp(InputVectorSrc src) {
_src = src;
}
protected override void Execute() {
var op = GetOperand(0);
if (op.Type == PdtInternalType.Null) {
_src.IsNull = true;
}
else {
var vec = new RVector3();
int dim;
if (op.Type == PdtInternalType.Number) dim = 1;
else if (op.Type == PdtInternalType.Vector) {
int arrtype, _;
op.GetArraySuffix(out arrtype, out _);
if (arrtype != PdtInternalType.Number)
throw new InvalidCastException("Not a vector of numbers");
dim = Math.Min(3, (op.Length - sizeof(int)) / sizeof(float));
}
else throw new InvalidCastException("Invalid vector");
for (int i = 0; i < dim; i++) {
vec[i] = op.AsNumber(i * sizeof(float));
}
_src.IsNull = false;
_src.Set(vec);
}
}
}
readonly Dictionary<InputHandler, double> _timeOrigins = new Dictionary<InputHandler, double>(); readonly Dictionary<InputHandler, double> _timeOrigins = new Dictionary<InputHandler, double>();
readonly Dictionary<InputSource, int> _activeCounts = new Dictionary<InputSource, int>(); readonly Dictionary<InputSource, int> _activeCounts = new Dictionary<InputSource, int>();
readonly Dictionary<InputIdentifier, float> _vect = new Dictionary<InputIdentifier, float>(); readonly Dictionary<InputIdentifier, float> _vect = new Dictionary<InputIdentifier, float>();
readonly Dictionary<ProxiedInputIdentifier, PropSrc> _vecs = new Dictionary<ProxiedInputIdentifier, PropSrc>(); readonly Dictionary<ProxiedInputIdentifier, PropSrc> _vecs = new Dictionary<ProxiedInputIdentifier, PropSrc>();
static readonly PropSrc.Arbitrary _nullsrc = new PropSrc.Arbitrary(PdtInternalType.Null, new byte[0]);
double? _lockTime = null; double? _lockTime = null;
unsafe void OnInput(InputIdentifier id, InputVector vec) { unsafe void OnInput(InputIdentifier id, InputVector vec) {
lock (_lock) { lock (_lock) {
@@ -189,15 +235,12 @@ namespace Cryville.Crtr {
float ft, tt = (float)(_lockTime != null ? _lockTime.Value : (vec.Time - _timeOrigins[id.Source.Handler])); float ft, tt = (float)(_lockTime != null ? _lockTime.Value : (vec.Time - _timeOrigins[id.Source.Handler]));
if (!_vect.TryGetValue(id, out ft)) ft = tt; if (!_vect.TryGetValue(id, out ft)) ft = tt;
if (vec.IsNull) { if (vec.IsNull) {
_etor.ContextCascadeUpdate(_var_value, _nullsrc); _etor.ContextCascadeUpdate(_var_value, PropSrc.Null);
OnInput(id, proxy.Target, ft, tt, true); OnInput(id, proxy.Target, ft, tt, true);
} }
else { else {
fixed (byte* ptr = _vecbuf) { _vecsrcs[0].Set(vec.Vector);
*(Vector3*)ptr = vec.Vector; _etor.ContextCascadeUpdate(_var_value, _vecsrcs[0]);
}
_vecsrc.Invalidate();
_etor.ContextCascadeUpdate(_var_value, _vecsrc);
OnInput(id, proxy.Target, ft, tt, false); OnInput(id, proxy.Target, ft, tt, false);
} }
_vect[id] = tt; _vect[id] = tt;
@@ -207,21 +250,27 @@ namespace Cryville.Crtr {
} }
static readonly int _var_fv = IdentifierManager.SharedInstance.Request("fv"); static readonly int _var_fv = IdentifierManager.SharedInstance.Request("fv");
static readonly int _var_tv = IdentifierManager.SharedInstance.Request("tv"); static readonly int _var_tv = IdentifierManager.SharedInstance.Request("tv");
unsafe void OnInput(InputIdentifier id, Identifier target, float ft, float tt, bool nullflag) { unsafe void OnInput(InputIdentifier id, Identifier target, float ft, float tt, bool nullflag, int depth = 0) {
if (depth >= MAX_DEPTH) throw new InputProxyException("Input propagation limit reached\nThe ruleset has invalid input definitions");
var def = _ruleset.inputs[target]; var def = _ruleset.inputs[target];
if (def.pass != null) { if (def.pass != null) {
foreach (var p in def.pass) { foreach (var p in def.pass) {
_etor.ContextCascadeInsert(); _etor.ContextCascadeInsert();
_arbop.Name = _var_value; bool newNullFlag = nullflag;
if (!nullflag) _etor.Evaluate(_arbop, p.Value); if (!newNullFlag) {
OnInput(id, p.Key, ft, tt, nullflag); ChartPlayer.etor.Evaluate(_vecops[depth + 1], p.Value);
newNullFlag = _vecsrcs[depth + 1].IsNull;
if (newNullFlag) ChartPlayer.etor.ContextCascadeUpdate(_var_value, PropSrc.Null);
else ChartPlayer.etor.ContextCascadeUpdate(_var_value, _vecsrcs[depth + 1]);
}
OnInput(id, p.Key, ft, tt, newNullFlag, depth + 1);
_etor.ContextCascadeDiscard(); _etor.ContextCascadeDiscard();
} }
} }
else { else {
var pid = new ProxiedInputIdentifier { Source = id, Target = target }; var pid = new ProxiedInputIdentifier { Source = id, Target = target };
PropSrc fv, tv = _etor.ContextCascadeLookup(_var_value); PropSrc fv, tv = _etor.ContextCascadeLookup(_var_value);
if (!_vecs.TryGetValue(pid, out fv)) fv = _nullsrc; if (!_vecs.TryGetValue(pid, out fv)) fv = PropSrc.Null;
if (fv.Type != PdtInternalType.Null || tv.Type != PdtInternalType.Null) { if (fv.Type != PdtInternalType.Null || tv.Type != PdtInternalType.Null) {
if (fv.Type == PdtInternalType.Null) _activeCounts[id.Source]++; if (fv.Type == PdtInternalType.Null) _activeCounts[id.Source]++;
_etor.ContextCascadeInsert(); _etor.ContextCascadeInsert();
@@ -236,13 +285,14 @@ namespace Cryville.Crtr {
} }
} }
public void SyncTime(double time) { public void SyncTime(double time) {
foreach (var s in _sproxies.Keys) { foreach (var s in _sproxies) {
var h = s.Handler; var h = s.Key.Handler;
_timeOrigins[h] = h.GetCurrentTimestamp() - time; _timeOrigins[h] = h.GetCurrentTimestamp() - time;
} }
} }
public void ForceTick() { public void ForceTick() {
foreach (var src in _sproxies.Keys) { foreach (var s in _sproxies) {
var src = s.Key;
if (_activeCounts[src] == 0) { if (_activeCounts[src] == 0) {
OnInput(new InputIdentifier { Source = src, Id = 0 }, new InputVector(_lockTime != null ? _lockTime.Value : src.Handler.GetCurrentTimestamp())); OnInput(new InputIdentifier { Source = src, Id = 0 }, new InputVector(_lockTime != null ? _lockTime.Value : src.Handler.GetCurrentTimestamp()));
} }
@@ -250,7 +300,8 @@ namespace Cryville.Crtr {
} }
public double GetTimestampAverage() { public double GetTimestampAverage() {
double result = 0; double result = 0;
foreach (var src in _sproxies.Keys) { foreach (var s in _sproxies) {
var src = s.Key;
result += src.Handler.GetCurrentTimestamp() - _timeOrigins[src.Handler]; result += src.Handler.GetCurrentTimestamp() - _timeOrigins[src.Handler];
} }
return result / _sproxies.Count; return result / _sproxies.Count;
@@ -261,19 +312,21 @@ namespace Cryville.Crtr {
} }
public class ProxyChangedEventArgs : EventArgs { public class ProxyChangedEventArgs : EventArgs {
public string Name { get; private set; } public Identifier Name { get; private set; }
public InputSource? Proxy { get; private set; } public InputSource? Proxy { get; private set; }
public bool Used { get; private set; } public bool Used { get; private set; }
public ProxyChangedEventArgs(string name, InputSource? src, bool used) { public bool Required { get; private set; }
public ProxyChangedEventArgs(Identifier name, InputSource? src, bool used, bool required) {
Name = name; Name = name;
Proxy = src; Proxy = src;
Used = used; Used = used;
Required = required;
} }
} }
public class InputProxyEntry { public class InputProxyEntry {
public InputSource? Source { get; set; } public InputSource? Source { get; set; }
public string Target { get; set; } public Identifier Target { get; set; }
public byte[] Mapping { get; private set; } public byte[] Mapping { get; private set; }
} }
@@ -300,4 +353,12 @@ namespace Cryville.Crtr {
return !lhs.Equals(rhs); return !lhs.Equals(rhs);
} }
} }
[Serializable]
public class InputProxyException : Exception {
public InputProxyException() { }
public InputProxyException(string message) : base(message) { }
public InputProxyException(string message, Exception inner) : base(message, inner) { }
protected InputProxyException(SerializationInfo info, StreamingContext context) : base(info, context) { }
}
} }

View File

@@ -4,6 +4,7 @@ using Cryville.Common.Pdt;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.Runtime.Serialization;
using System.Text.Formatting; using System.Text.Formatting;
namespace Cryville.Crtr { namespace Cryville.Crtr {
@@ -42,11 +43,12 @@ namespace Cryville.Crtr {
_numsrc3 = new PropSrc.Float(() => _numbuf3); _numsrc3 = new PropSrc.Float(() => _numbuf3);
_numsrc4 = new PropSrc.Float(() => _numbuf4); _numsrc4 = new PropSrc.Float(() => _numbuf4);
_rs.judges.TryGetValue(new Identifier(_var_pause), out _judgePause); _rs.judges.TryGetValue(new Identifier(_var_pause), out _judgePause);
foreach (var i in rs.inputs.Keys) { foreach (var i in rs.inputs) {
var id = i.Key;
var l = new List<JudgeEvent>(); var l = new List<JudgeEvent>();
evs.Add(i, l); evs.Add(id, l);
activeEvs.Add(i, new List<JudgeEvent>()); activeEvs.Add(id, new List<JudgeEvent>());
if (_judgePause != null && i.Key == _var_pause) { if (_judgePause != null && id.Key == _var_pause) {
l.Add(new JudgeEvent { l.Add(new JudgeEvent {
StartTime = double.NegativeInfinity, EndTime = double.PositiveInfinity, StartTime = double.NegativeInfinity, EndTime = double.PositiveInfinity,
StartClip = double.NegativeInfinity, EndClip = double.PositiveInfinity, StartClip = double.NegativeInfinity, EndClip = double.PositiveInfinity,
@@ -82,8 +84,9 @@ namespace Cryville.Crtr {
#region Judge #region Judge
internal readonly Dictionary<int, int> judgeMap = new Dictionary<int, int>(); internal readonly Dictionary<int, int> judgeMap = new Dictionary<int, int>();
void InitJudges() { void InitJudges() {
foreach (var i in _rs.judges.Keys) { foreach (var i in _rs.judges) {
judgeMap.Add(i.Key, IdentifierManager.SharedInstance.Request("judge_" + i.Name)); var id = i.Key;
judgeMap.Add(id.Key, IdentifierManager.SharedInstance.Request("judge_" + id.Name));
} }
} }
static bool _flag; static bool _flag;
@@ -132,7 +135,7 @@ namespace Cryville.Crtr {
if (actlist.Count > 0) { if (actlist.Count > 0) {
_numbuf3 = ft; _numsrc3.Invalidate(); _etor.ContextCascadeUpdate(_var_ft, _numsrc3); _numbuf3 = ft; _numsrc3.Invalidate(); _etor.ContextCascadeUpdate(_var_ft, _numsrc3);
_numbuf4 = tt; _numsrc4.Invalidate(); _etor.ContextCascadeUpdate(_var_tt, _numsrc4); _numbuf4 = tt; _numsrc4.Invalidate(); _etor.ContextCascadeUpdate(_var_tt, _numsrc4);
var index = 0; int index = 0, iter = 0;
while (index >= 0 && index < actlist.Count) { while (index >= 0 && index < actlist.Count) {
var ev = actlist[index]; var ev = actlist[index];
_numbuf1 = (float)ev.StartTime; _numsrc1.Invalidate(); _etor.ContextCascadeUpdate(_var_fn, _numsrc1); _numbuf1 = (float)ev.StartTime; _numsrc1.Invalidate(); _etor.ContextCascadeUpdate(_var_fn, _numsrc1);
@@ -152,19 +155,21 @@ namespace Cryville.Crtr {
if (index < 0) index = ~index; if (index < 0) index = ~index;
} }
else index++; else index++;
if (iter++ >= 16) throw new JudgePropagationException();
} }
else index++; else index++;
} }
} }
} }
bool Pass(JudgeEvent ev, float time, Identifier[] ids) { bool Pass(JudgeEvent ev, float time, Identifier[] ids, int depth = 0) {
if (depth >= 16) throw new JudgePropagationException();
foreach (var i in ids) { foreach (var i in ids) {
var def = _rs.judges[i]; var def = _rs.judges[i];
if (def.hit != null) _etor.Evaluate(_flagop, def.hit); if (def.hit != null) _etor.Evaluate(_flagop, def.hit);
else _flag = true; else _flag = true;
if (_flag) { if (_flag) {
if (def.scores != null) UpdateScore(def.scores); if (def.scores != null) UpdateScore(def.scores);
if (def.pass != null) Pass(ev, time, def.pass); if (def.pass != null) Pass(ev, time, def.pass, depth + 1);
ev.Handler.ReportJudge(ev, time, i); ev.Handler.ReportJudge(ev, time, i);
return true; return true;
} }
@@ -247,9 +252,10 @@ namespace Cryville.Crtr {
public TargetString GetFullFormattedScoreString() { public TargetString GetFullFormattedScoreString() {
bool flag = false; bool flag = false;
scoreFullBuf.Clear(); scoreFullBuf.Clear();
foreach (var s in scores.Keys) { foreach (var s in scores) {
scoreFullBuf.AppendFormat(flag ? "\n{0}: " : "{0}: ", (string)IdentifierManager.SharedInstance.Retrieve(s)); var id = s.Key;
scoreFullBuf.AppendFormat(scoreFormatCache[s], scores[s]); scoreFullBuf.AppendFormat(flag ? "\n{0}: " : "{0}: ", (string)IdentifierManager.SharedInstance.Retrieve(id));
scoreFullBuf.AppendFormat(scoreFormatCache[id], scores[id]);
flag = true; flag = true;
} }
scoreFullStr.Length = scoreFullBuf.Count; scoreFullStr.Length = scoreFullBuf.Count;
@@ -320,4 +326,12 @@ namespace Cryville.Crtr {
public string format = ""; public string format = "";
} }
#endregion #endregion
[Serializable]
public class JudgePropagationException : Exception {
public JudgePropagationException() : base("Judge propagation limit reached\nThe ruleset has invalid judge definitions") { }
public JudgePropagationException(string message) : base(message) { }
public JudgePropagationException(string message, Exception inner) : base(message, inner) { }
protected JudgePropagationException(SerializationInfo info, StreamingContext context) : base(info, context) { }
}
} }

View File

@@ -26,10 +26,8 @@ namespace Cryville.Crtr {
get; get;
private set; private set;
} }
public Material NewMaterial { public static Material NewMaterial() {
get { return Material.Instantiate(GenericResources.Materials["-SpriteMat"]);
return Material.Instantiate(GenericResources.Materials["-SpriteMat"]);
}
} }
public void Init(Transform parent) { public void Init(Transform parent) {
MeshObject = new GameObject("__mesh__"); MeshObject = new GameObject("__mesh__");
@@ -41,12 +39,10 @@ namespace Cryville.Crtr {
MeshObject.AddComponent<MeshRenderer>(); MeshObject.AddComponent<MeshRenderer>();
MeshFilter = MeshObject.GetComponent<MeshFilter>(); MeshFilter = MeshObject.GetComponent<MeshFilter>();
Renderer = MeshObject.GetComponent<Renderer>(); Renderer = MeshObject.GetComponent<Renderer>();
Renderer.material = NewMaterial;
Initialized = true; Initialized = true;
} }
public void Destroy() { public void Destroy() {
Mesh.Destroy(Mesh); Mesh.Destroy(Mesh);
if (Renderer.material != null) Material.Destroy(Renderer.material);
GameObject.Destroy(MeshObject); GameObject.Destroy(MeshObject);
} }
} }

View File

@@ -360,8 +360,8 @@ namespace Cryville.Crtr {
public abstract void LerpWith(Vector start, float lerpedTime, ref Vector result); public abstract void LerpWith(Vector start, float lerpedTime, ref Vector result);
public abstract float DelerpWith(Vector start, Vector value); public abstract float DelerpWith(Vector start, Vector value);
public abstract bool IsZero(); public abstract bool IsZero();
public override abstract string ToString(); public abstract override string ToString();
public abstract float[] ToArray(); public abstract unsafe void ToArray(float* arr);
public Vector Clone() { public Vector Clone() {
return (Vector)MemberwiseClone(); return (Vector)MemberwiseClone();
@@ -442,8 +442,8 @@ namespace Cryville.Crtr {
return Value.ToString(CultureInfo.InvariantCulture); return Value.ToString(CultureInfo.InvariantCulture);
} }
public override float[] ToArray() { public override unsafe void ToArray(float* arr) {
return new float[] { Value }; arr[0] = Value;
} }
} }
@@ -504,8 +504,8 @@ namespace Cryville.Crtr {
return Value.ToString(CultureInfo.InvariantCulture); return Value.ToString(CultureInfo.InvariantCulture);
} }
public override float[] ToArray() { public override unsafe void ToArray(float* arr) {
return new float[] { Value }; arr[0] = Value;
} }
} }
@@ -566,8 +566,8 @@ namespace Cryville.Crtr {
return Value.ToString(CultureInfo.InvariantCulture); return Value.ToString(CultureInfo.InvariantCulture);
} }
public override float[] ToArray() { public override unsafe void ToArray(float* arr) {
return new float[] { Value }; arr[0] = Value;
} }
} }
@@ -610,8 +610,8 @@ namespace Cryville.Crtr {
} }
} }
} }
w = aw ? rw : (float?)null; w = aw ? rw : null;
h = ah ? rh : (float?)null; h = ah ? rh : null;
} }
public static VecPtComp Parse(string s) { public static VecPtComp Parse(string s) {
@@ -669,8 +669,9 @@ namespace Cryville.Crtr {
return ToString(w, h); return ToString(w, h);
} }
public override float[] ToArray() { public override unsafe void ToArray(float* arr) {
return new float[] { w.Value, h.Value }; arr[0] = w.Value;
arr[1] = h.Value;
} }
} }
@@ -764,8 +765,10 @@ namespace Cryville.Crtr {
); );
} }
public override float[] ToArray() { public override unsafe void ToArray(float* arr) {
return new float[] { x.Value, y.Value, z.Value }; arr[0] = x.Value;
arr[1] = y.Value;
arr[2] = z.Value;
} }
} }
@@ -845,8 +848,11 @@ namespace Cryville.Crtr {
return VecPtComp.ToString(xw, xh) + "," + VecPtComp.ToString(yw, yh); return VecPtComp.ToString(xw, xh) + "," + VecPtComp.ToString(yw, yh);
} }
public override float[] ToArray() { public override unsafe void ToArray(float* arr) {
return new float[] { xw.Value, xh.Value, yw.Value, yh.Value }; arr[0] = xw.Value;
arr[1] = xh.Value;
arr[2] = yw.Value;
arr[3] = yh.Value;
} }
} }
@@ -936,40 +942,31 @@ namespace Cryville.Crtr {
return VecPtComp.ToString(xw, xh) + "," + VecPtComp.ToString(yw, yh) + "," + (z != null ? z.Value.ToString(CultureInfo.InvariantCulture) : ""); return VecPtComp.ToString(xw, xh) + "," + VecPtComp.ToString(yw, yh) + "," + (z != null ? z.Value.ToString(CultureInfo.InvariantCulture) : "");
} }
public override float[] ToArray() { public override unsafe void ToArray(float* arr) {
return new float[] { xw.Value, xh.Value, yw.Value, yh.Value, z.Value }; arr[0] = xw.Value;
arr[1] = xh.Value;
arr[2] = yw.Value;
arr[3] = yh.Value;
arr[4] = z.Value;
} }
} }
public abstract class VectorSrc : PropSrc { public unsafe class VectorSrc : PropSrc.FixedBuffer {
const int MAX_DIMENSION = 8;
protected readonly Func<Vector> _cb; protected readonly Func<Vector> _cb;
public VectorSrc(Func<Vector> cb, int type) : base(type) { _cb = cb; } public VectorSrc(Func<Vector> cb) : base(PdtInternalType.Vector, MAX_DIMENSION * sizeof(float) + sizeof(int)) {
public static VectorSrc Construct(Func<Vector> cb) { _cb = cb;
if (cb().Dimension == 1) return new INumber(cb); fixed (byte* rptr = buf) {
else return new IVector(cb); var ptr = (float*)rptr;
} *(int*)(ptr + MAX_DIMENSION) = PdtInternalType.Number;
class INumber : VectorSrc {
public INumber(Func<Vector> cb) : base(cb, PdtInternalType.Number) { }
protected override unsafe void InternalGet() {
var arr = _cb().ToArray();
buf = new byte[sizeof(float)];
fixed (byte* ptr = buf) {
*(float*)ptr = arr[0];
}
} }
} }
class IVector : VectorSrc { protected override void InternalGet() {
public IVector(Func<Vector> cb) : base(cb, PdtInternalType.Vector) { } var v = _cb();
protected override unsafe void InternalGet() { if (v.Dimension > MAX_DIMENSION) throw new NotSupportedException("Vector dimension too large");
var arr = _cb().ToArray(); fixed (byte* rptr = buf) {
buf = new byte[sizeof(float) * arr.Length + sizeof(int)]; var ptr = (float*)rptr;
fixed (byte* rptr = buf) { v.ToArray(ptr);
var ptr = (float*)rptr;
for (int i = 0; i < arr.Length; i++, ptr++) {
*ptr = arr[i];
}
*(int*)ptr = PdtInternalType.Number;
}
} }
} }
} }
@@ -977,7 +974,7 @@ namespace Cryville.Crtr {
public class VectorOp : PropOp { public class VectorOp : PropOp {
readonly Action<float[]> _cb; readonly Action<float[]> _cb;
public VectorOp(Action<float[]> cb) { _cb = cb; } public VectorOp(Action<float[]> cb) { _cb = cb; }
protected unsafe override void Execute() { protected override unsafe void Execute() {
var op = GetOperand(0); var op = GetOperand(0);
float[] values; float[] values;
if (op.Type == PdtInternalType.Number) { if (op.Type == PdtInternalType.Number) {
@@ -988,7 +985,7 @@ namespace Cryville.Crtr {
op.GetArraySuffix(out type, out _); op.GetArraySuffix(out type, out _);
if (type != PdtInternalType.Number) if (type != PdtInternalType.Number)
throw new InvalidOperationException("Not a vector of numbers"); throw new InvalidOperationException("Not a vector of numbers");
values = new float[op.Length - sizeof(int)]; values = new float[(op.Length - sizeof(int)) / sizeof(float)];
fixed (float* ptr = values) { fixed (float* ptr = values) {
op.CopyTo((byte*)ptr, 0, op.Length - sizeof(int)); op.CopyTo((byte*)ptr, 0, op.Length - sizeof(int));
} }

View File

@@ -57,8 +57,8 @@ namespace Cryville.Crtr {
} }
public override void Init() { public override void Init() {
base.Init(); base.Init();
sgos = gogroup.GetComponentsInChildren<SectionalGameObject>(); sgos = RootTransform.GetComponentsInChildren<SectionalGameObject>();
foreach (var judge in judges.Values) judge.InitPropSrcs(); foreach (var judge in judges) judge.Value.InitPropSrcs();
} }
public override void StartPhysicalUpdate(ContainerState s) { public override void StartPhysicalUpdate(ContainerState s) {
@@ -67,10 +67,10 @@ namespace Cryville.Crtr {
TransformAwake(s); TransformAwake(s);
} }
} }
public override void StartGraphicalUpdate(ContainerState s) { protected override void StartGraphicalUpdate(ContainerState s) {
base.StartGraphicalUpdate(s); base.StartGraphicalUpdate(s);
TransformAwake(s); TransformAwake(s);
if (gogroup) { if (RootTransform) {
if (Event.IsLong) { if (Event.IsLong) {
foreach (var i in sgos) { foreach (var i in sgos) {
i.Reset(); i.Reset();
@@ -79,10 +79,10 @@ namespace Cryville.Crtr {
} }
else { else {
#if UNITY_5_6_OR_NEWER #if UNITY_5_6_OR_NEWER
gogroup.SetPositionAndRotation(Position, Rotation); RootTransform.SetPositionAndRotation(Position, Rotation);
#else #else
gogroup.position = Position; RootTransform.position = Position;
gogroup.rotation = Rotation; RootTransform.rotation = Rotation;
#endif #endif
} }
} }
@@ -96,7 +96,7 @@ namespace Cryville.Crtr {
if (s.CloneType <= 2) { if (s.CloneType <= 2) {
Position = GetFramePoint(s.Parent, s.Track); Position = GetFramePoint(s.Parent, s.Track);
Rotation = GetFrameRotation(s.Parent, s.Track); Rotation = GetFrameRotation(s.Parent, s.Track);
if (s.CloneType == 2 && gogroup && Event.IsLong) { if (s.CloneType == 2 && RootTransform && Event.IsLong) {
foreach (var i in sgos) foreach (var i in sgos)
i.AppendPoint(Position, Rotation); i.AppendPoint(Position, Rotation);
} }
@@ -127,8 +127,8 @@ namespace Cryville.Crtr {
else base.Update(s, ev); else base.Update(s, ev);
} }
public override void EndGraphicalUpdate(ContainerState s) { protected override void EndGraphicalUpdate(ContainerState s) {
if (gogroup) { if (RootTransform) {
foreach (var i in sgos) i.Seal(); foreach (var i in sgos) i.Seal();
} }
base.EndGraphicalUpdate(s); base.EndGraphicalUpdate(s);

Some files were not shown because too many files have changed in this diff Show More