118 Commits

Author SHA1 Message Date
d510fec57b Update version. 2023-03-23 19:11:24 +08:00
c5214dd477 Update gitignore. 2023-03-17 18:08:11 +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
92 changed files with 2690 additions and 918 deletions

1
.gitignore vendored
View File

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

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c4ef48e4a4983de4e9c31483df2a918e
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 9ec674235c0dd6744af2dab2b58dd53c
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

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

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

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

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

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

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

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

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

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;
}
public override TableDirectory GetSubTable(UInt32 item) {
var i = (UInt32)item;
var i = item;
return new TableDirectory(Reader, i);
}
}

View File

@@ -2,6 +2,7 @@
namespace Cryville.Common {
public struct Identifier : IEquatable<Identifier> {
public static Identifier Empty = new Identifier(0);
public int Key { get; private set; }
public object Name { get { return IdentifierManager.SharedInstance.Retrieve(Key); } }
public Identifier(int key) {
@@ -24,11 +25,11 @@ namespace Cryville.Common {
if (Key == 0) return "";
return Name.ToString();
}
public static implicit operator Identifier(string identifier) {
return new Identifier(identifier);
public static bool operator ==(Identifier lhs, Identifier rhs) {
return lhs.Equals(rhs);
}
public static implicit operator string(Identifier identifier) {
return identifier.ToString();
public static bool operator !=(Identifier lhs, Identifier rhs) {
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="n">The numerator.</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) {
if (value < 0.0)
throw new ArgumentOutOfRangeException("value", "Must be >= 0.");
if (error <= 0.0 || error >= 1.0)
throw new ArgumentOutOfRangeException("accuracy", "Must be > 0 and < 1.");
if (error <= 0.0 || error > 1.0)
throw new ArgumentOutOfRangeException("error", "Must be > 0 and <= 1.");
int num = (int)System.Math.Floor(value);
value -= num;

View File

@@ -5,7 +5,7 @@ namespace Cryville.Common.Pdt {
/// Indicates that the attributed member is an element list.
/// </summary>
/// <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>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class ElementListAttribute : Attribute { }
@@ -14,7 +14,7 @@ namespace Cryville.Common.Pdt {
/// Indicates that the attributed member is a property list.
/// </summary>
/// <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>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class PropertyListAttribute : Attribute { }

View File

@@ -186,7 +186,7 @@ namespace Cryville.Common.Pdt {
protected abstract PdtOperator GetOperator(PdtOperatorSignature sig);
unsafe void Operate(PdtOperator op, int pc, bool noset = false) {
fixed (byte* pmem = _mem) {
op.Begin(this);
op.Begin(this, pc);
for (int i = 0; i < pc; i++) {
var frame = _stack[--_framecount];
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 {
readonly static Dictionary<char, int> OP_PRIORITY = new Dictionary<char, int> {
static readonly Dictionary<char, int> OP_PRIORITY = new Dictionary<char, int> {
{ '@', 7 },
{ '*', 6 }, { '/', 6 }, { '%', 6 },
{ '+', 5 }, { '-', 5 },
@@ -103,7 +103,7 @@ namespace Cryville.Common.Pdt {
{ ',', 0 },
{ '$', -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 },
@@ -115,7 +115,7 @@ namespace Cryville.Common.Pdt {
{ '$', -1 },
};
readonly static PdtExpression _emptyexp;
static readonly PdtExpression _emptyexp;
static PdtInterpreter() {
var ins = new LinkedList<PdtInstruction>();
ins.AddLast(new PdtInstruction.PushConstant(
@@ -143,7 +143,7 @@ namespace Cryville.Common.Pdt {
public override string ToString() {
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,
Value = "$",
};

View File

@@ -6,30 +6,30 @@
/// <summary>
/// Error type.
/// </summary>
public readonly static int Error = 0x00525245;
public const int Error = 0x00525245;
/// <summary>
/// Array of a same variable-length type, with a suffix indicating the element count and the element type.
/// </summary>
public readonly static int Array = 0x00525241;
public const int Array = 0x00525241;
/// <summary>
/// Null type.
/// </summary>
public readonly static int Null = 0x4c4c554e;
public const int Null = 0x4c4c554e;
/// <summary>
/// IEEE 754 32-bit floating-point number.
/// </summary>
public readonly static int Number = 0x004d554e;
public const int Number = 0x004d554e;
/// <summary>
/// A sequence of UTF-16 code units, with a prefix indicating the number of the code units.
/// </summary>
public readonly static int String = 0x00525453;
public const int String = 0x00525453;
/// <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.
/// </summary>
public readonly static int Undefined = 0x00444e55;
public const int Undefined = 0x00444e55;
/// <summary>
/// Vector of a same constant-length type, with a suffix indicating the element type.
/// </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.Generic;
using System.Linq;
@@ -27,7 +28,7 @@ namespace Cryville.Common.Pdt {
/// <item><term><c>0x1000</c></term><description>End of Key</description></item>
/// </list>
/// </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
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,
@@ -54,15 +55,14 @@ namespace Cryville.Common.Pdt {
/// <param name="binder">The binder.</param>
/// <returns>The interpreted object.</returns>
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>
/// The source string.
/// </summary>
public string Source { get; private set; }
readonly Type _type;
readonly Binder _binder;
Binder _binder;
/// <summary>
/// The current position in the string being parsed by the interpreter.
/// </summary>
@@ -167,23 +167,27 @@ namespace Cryville.Common.Pdt {
/// Creates an instance of the <see cref="PdtInterpreter" /> class.
/// </summary>
/// <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>
public PdtInterpreter(string src, Type type, Binder binder) {
public PdtInterpreter(string src, Binder binder) {
Source = src;
_type = type;
_binder = binder;
if (_binder == null)
_binder = BinderAttribute.CreateBinderOfType(_type);
}
int[] m_formatVersion;
public int[] GetFormatVersion() {
if (m_formatVersion == null) InterpretDirectives();
return m_formatVersion;
}
/// <summary>
/// Interprets the source to an object.
/// </summary>
/// <param name="type">The output type.</param>
/// <returns>The interpreted object.</returns>
public object Interpret() {
public object Interpret(Type type) {
try {
InterpretDirectives();
return InterpretObject(_type);
if (m_formatVersion == null) InterpretDirectives();
if (_binder == null)
_binder = BinderAttribute.CreateBinderOfType(type);
return InterpretObject(type);
}
catch (Exception ex) {
throw new PdtParsingException(this, ex);
@@ -201,7 +205,10 @@ namespace Cryville.Common.Pdt {
break;
case "format":
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");
flag = true;
break;
@@ -226,6 +233,10 @@ namespace Cryville.Common.Pdt {
while (true) {
try { ws(); }
catch (IndexOutOfRangeException) { return result; }
if (cc == '}') {
GetChar();
return result;
}
object pkey = InterpretKey(type);
char c = GetChar();
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));
Type ptype = ReflectionHelper.GetMemberType(prop);
if (flag) {
if (!typeof(IDictionary).IsAssignableFrom(ptype))
throw new InvalidOperationException("Internal error: Element list is not a dictionary");
var ktype = ptype.GetGenericArguments()[0];
var vtype = ptype.GetGenericArguments()[1];
object key = _binder.ChangeType(pkey, ktype, null);
object value = InterpretObject(vtype);
((IDictionary)ReflectionHelper.GetValue(prop, result)).Add(key, value);
using (var collection = new PairCollection(ReflectionHelper.GetValue(prop, result))) {
var ktype = ptype.GetGenericArguments()[0];
var vtype = ptype.GetGenericArguments()[1];
object key = _binder.ChangeType(pkey, ktype, null);
object value = InterpretObject(vtype);
collection.Add(key, value);
}
}
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));
var ptype = ReflectionHelper.GetMemberType(prop);
if (flag) {
if (!typeof(IDictionary).IsAssignableFrom(ptype))
throw new InvalidOperationException("Internal error: Property list is not a dictionary");
var ktype = ptype.GetGenericArguments()[0];
var vtype = ptype.GetGenericArguments()[1];
object key = _binder.ChangeType(pkey, ktype, null);
object value = _binder.ChangeType(exp, vtype, null);
((IDictionary)ReflectionHelper.GetValue(prop, result)).Add(key, value);
using (var collection = new PairCollection(ReflectionHelper.GetValue(prop, result))) {
var ktype = ptype.GetGenericArguments()[0];
var vtype = ptype.GetGenericArguments()[1];
object key = _binder.ChangeType(pkey, ktype, null);
object value = _binder.ChangeType(exp, vtype, null);
collection.Add(key, value);
}
}
else {
object value = _binder.ChangeType(exp, ptype, null);
@@ -288,8 +299,6 @@ namespace Cryville.Common.Pdt {
}
}
break;
case '}':
return result;
default:
throw new InvalidOperationException("Internal error: Invalid key interpretation");
}

View File

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

View File

@@ -3,6 +3,6 @@ using UnityEngine;
namespace Cryville.Common.Unity.UI {
public abstract class SetParameterBehaviour : StateMachineBehaviour {
[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

@@ -9,11 +9,11 @@ namespace Cryville.Crtr.Browsing {
public override object Value {
get {
float s_value = GetDisplayValue();
return IntegerMode ? (object)(int)s_value : (object)s_value;
return IntegerMode ? (int)s_value : (object)s_value;
}
set {
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();
m_text.text = s_value.ToString();
if (Range != null && MaxStep == 0) {

View File

@@ -6,6 +6,7 @@ using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
using UnsafeIL;
namespace Cryville.Crtr {
[JsonConverter(typeof(BeatTimeConverter))]
@@ -154,6 +155,10 @@ namespace Cryville.Crtr {
protected ChartEvent() {
PropSrcs = new Dictionary<int, PropSrc>();
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("time", new PropSrc.BeatTime(() => time.Value));
SubmitPropSrc("endtime", new PropSrc.BeatTime(() => endtime.Value));
@@ -320,7 +325,7 @@ namespace Cryville.Crtr {
else {
AbsoluteValue = Vector.Construct(registry.Type, m.Groups[11].Value);
}
SubmitPropSrc("value", VectorSrc.Construct(() => {
SubmitPropSrc("value", new VectorSrc(() => {
if (RelativeNode != null) return RelativeNode.Value;
else return AbsoluteValue;
}));

View File

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

View File

@@ -1,12 +1,21 @@
using System;
using UnityEngine;
namespace Cryville.Crtr.Components {
[DisallowMultipleComponent]
public abstract class MeshBase : SkinComponent {
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));
}
protected MeshWrapper mesh = new MeshWrapper();
protected Material[] materials;
short _zindex;
public short ZIndex {
@@ -22,9 +31,36 @@ namespace Cryville.Crtr.Components {
}
protected void UpdateZIndex() {
if (!mesh.Initialized) return;
foreach (var mat in mesh.Renderer.materials) {
foreach (var mat in materials) {
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() {
SubmitProperty("partial", new PropOp.Boolean(v => part = Part.idle));
SubmitProperty("part", new PropOp.Enum<Part>(v => part = v, v => (Part)v), 2);
}
protected override void OnDestroy() {
mesh.Destroy();
SubmitProperty("part", new PropOp.Enum<Part>(v => part = v, v => (Part)v), 1);
}
public override void Init() {
@@ -67,7 +63,7 @@ namespace Cryville.Crtr.Components {
SubmitProperty("head", new PropOp.String(v => head.FrameName = v));
SubmitProperty("body", new PropOp.String(v => body.FrameName = v));
SubmitProperty("tail", new PropOp.String(v => tail.FrameName = v));
SubmitProperty("shape", new op_set_shape(this), 2);
SubmitProperty("shape", new op_set_shape(this), 1);
}
#pragma warning disable IDE1006
@@ -76,7 +72,7 @@ namespace Cryville.Crtr.Components {
public op_set_shape(PolygonSGO self) : base(1) {
_self = self;
}
protected unsafe override void Execute() {
protected override unsafe void Execute() {
var o = GetOperand(0);
if (o.Type != PdtInternalType.Vector) throw new ArgumentException("Not a vector");
_self._shapeLength = (o.Length - sizeof(int)) / sizeof(Vector2);
@@ -103,7 +99,6 @@ namespace Cryville.Crtr.Components {
public SpriteInfo body = new SpriteInfo();
public SpriteInfo tail = new SpriteInfo();
Material[] mats;
List<Vector3> vertices;
List<float> lengths;
float sumLength = 0;
@@ -112,23 +107,25 @@ namespace Cryville.Crtr.Components {
base.Init();
mesh.Init(transform);
mats = mesh.Renderer.materials = new Material[] { mesh.NewMaterial, mesh.NewMaterial, mesh.NewMaterial };
head.Bind(mats[0]);
body.Bind(mats[1]);
tail.Bind(mats[2]);
mesh.Renderer.sharedMaterials = materials = new Material[] {
MeshWrapper.NewMaterial(),
MeshWrapper.NewMaterial(),
MeshWrapper.NewMaterial(),
};
head.Bind(materials[0]);
body.Bind(materials[1]);
tail.Bind(materials[2]);
UpdateZIndex();
}
protected override void OnDestroy() {
base.OnDestroy();
Reset();
foreach (var m in mats) Material.Destroy(m);
if (_shape != null) _shapePool.Return(_shape);
if (vertices != null) {
_ptPool.Return(vertices);
_lPool.Return(lengths);
}
base.OnDestroy();
}
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>
/// <param name="name">The name of the property.</param>
/// <param name="property">The property.</param>
protected void SubmitProperty(string name, PdtOperator property, int uct = 1) {
Properties.Add(IdentifierManager.SharedInstance.Request(name), new SkinProperty(property, uct));
protected void SubmitProperty(string name, PdtOperator property, int udl = 0) {
Properties.Add(IdentifierManager.SharedInstance.Request(name), new SkinProperty(property, udl));
}
/// <summary>
@@ -26,14 +26,16 @@ namespace Cryville.Crtr.Components {
}
public virtual void Init() { }
public virtual void Rewind(double time, Transform target) { }
public virtual void Tick(SkinContainer c, double time) { }
protected abstract void OnDestroy();
}
public struct SkinProperty {
public PdtOperator Operator { get; set; }
public int UpdateCloneType { get; set; }
public SkinProperty(PdtOperator op, int uct = 1) {
public int UpdateDynamicLevel { get; set; }
public SkinProperty(PdtOperator op, int udl = 0) {
Operator = op;
UpdateCloneType = uct;
UpdateDynamicLevel = udl;
}
}
}

View File

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

View File

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

View File

@@ -2,22 +2,7 @@
namespace Cryville.Crtr.Components {
public class SpriteRect : SpriteBase {
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);
}
public SpriteRect() { }
protected override Vector3 BaseScale {
get { return Vector3.one; }
@@ -25,7 +10,6 @@ namespace Cryville.Crtr.Components {
public override void Init() {
InternalInit();
OnColorUpdate();
}
}
}

View File

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

View File

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

View File

@@ -1,4 +1,5 @@
using Cryville.Common.Unity;
using Cryville.Common;
using Cryville.Common.Unity;
using Cryville.Common.Unity.Input;
using System.Collections.Generic;
using UnityEngine;
@@ -26,10 +27,10 @@ namespace Cryville.Crtr.Config {
SimpleInputConsumer _consumer;
public InputProxy proxy;
readonly Dictionary<string, InputConfigPanelEntry> _entries = new Dictionary<string, InputConfigPanelEntry>();
readonly Dictionary<Identifier, InputConfigPanelEntry> _entries = new Dictionary<Identifier, InputConfigPanelEntry>();
string _sel;
public void OpenDialog(string entry) {
Identifier _sel;
public void OpenDialog(Identifier entry) {
_sel = entry;
m_inputDialog.SetActive(true);
CallHelper.Purge(m_deviceList);
@@ -85,9 +86,21 @@ namespace Cryville.Crtr.Config {
if (_recvsrcs.Contains(src)) return;
_recvsrcs.Add(src);
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>();
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(() => {
CloseDialog(src);
});

View File

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

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

View File

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

View File

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

View File

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

View File

@@ -1,24 +1,45 @@
using Cryville.Common;
using Cryville.Crtr.Browsing;
using Microsoft.Win32;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace Cryville.Crtr.Extensions.Malody {
public class MalodyChartFinder : LocalResourceFinder {
public override string Name { get { return "Malody beatmaps"; } }
public override string GetRootPath() {
var malodyDataPath = GetMalodyDataPath();
var malodyConfigPath = Path.Combine(malodyDataPath, "config.json");
if (File.Exists(malodyConfigPath)) {
using (var reader = new StreamReader(malodyConfigPath, Encoding.UTF8)) {
var config = JsonConvert.DeserializeObject<Dictionary<string, object>>(reader.ReadToEnd());
object userPath;
if (config.TryGetValue("user_chart_path", out userPath)) {
var strUserPath = userPath as string;
if (!string.IsNullOrEmpty(strUserPath)) {
return strUserPath;
}
}
}
}
return Path.Combine(malodyDataPath, "beatmap");
}
string GetMalodyDataPath() {
switch (Environment.OSVersion.Platform) {
case PlatformID.Unix:
return "/storage/emulated/0/data/malody/beatmap";
return "/storage/emulated/0/data/malody";
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");
return new FileInfo(StringUtils.GetProcessPathFromCommand(path)).Directory.FullName;
default: return null;
}
}

View File

@@ -60,7 +60,7 @@ namespace Cryville.Crtr.Extensions.Quaver {
evs.Sort();
var longevs = new Dictionary<EventWrapper, ChartEvent>();
var tm = new TimeTimingModel(src.TimingPoints[0].StartTime / 1e3);
var tm = new TimeTimingModel(src.TimingPoints[0].StartTime / 1e3, 2e-3);
foreach (var ev in evs) {
tm.ForwardTo(ev.StartTime / 1e3);
if (ev is EventWrapper.HitObject) {
@@ -84,6 +84,7 @@ namespace Cryville.Crtr.Extensions.Quaver {
else if (ev is EventWrapper.TimingPoint) {
var tev = (EventWrapper.TimingPoint)ev;
tm.BPM = tev.Event.Bpm;
tm.ForceSnap();
chart.sigs.Add(new Chart.Signature {
time = tm.FractionalBeatTime,
tempo = tev.Event.Bpm,

View File

@@ -42,15 +42,24 @@ namespace Cryville.Crtr.Extensions {
}
}
public class TimeTimingModel : TimingModel {
public TimeTimingModel(double offset = 0) : base(offset) { }
public readonly double InputTimeAccuracy;
public TimeTimingModel(double offset = 0, double accuracy = 2e-3) : base(offset) {
if (accuracy <= 0) throw new ArgumentOutOfRangeException("accuracy");
InputTimeAccuracy = accuracy;
}
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);
FractionUtils.ToFraction(BeatTime, Math.Min(1, InputTimeAccuracy * BPM / 60), out n, out d);
FractionalBeatTime = new BeatTime(n, d);
Time = t;
}
public void ForceSnap() {
var alignedBeat = (int)Math.Round(BeatTime);
BeatTime = alignedBeat;
FractionalBeatTime = new BeatTime(alignedBeat, 1);
}
}
}

View File

@@ -10,7 +10,7 @@ namespace Cryville.Crtr.Extensions.osu {
public class osuChartConverter : ResourceConverter {
#pragma warning restore IDE1006
static readonly string[] SUPPORTED_FORMATS = { ".osu" };
const double OFFSET = 0.05;
const double OFFSET = 0.011;
public override string[] GetSupportedFormats() {
return SUPPORTED_FORMATS;
@@ -108,10 +108,11 @@ namespace Cryville.Crtr.Extensions.osu {
else if (ev is osuEvent.TimingChange) {
var tev = (osuEvent.TimingChange)ev;
if (tm == null) {
tm = new TimeTimingModel(tev.StartTime / 1e3);
tm = new TimeTimingModel(tev.StartTime / 1e3, 2e-3);
bgmEv.offset = (float)(tev.StartTime / 1e3 + OFFSET);
}
tm.BeatLength = tev.BeatLength / 1e3;
tm.ForceSnap();
chart.sigs.Add(new Chart.Signature {
time = tm.FractionalBeatTime,
tempo = (float)tm.BPM,

View File

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

View File

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

View File

@@ -4,7 +4,8 @@ using Cryville.Common.Unity.Input;
using Cryville.Crtr.Config;
using System;
using System.Collections.Generic;
using UnityEngine;
using System.Runtime.Serialization;
using RVector3 = UnityEngine.Vector3;
namespace Cryville.Crtr {
public class InputProxy : IDisposable {
@@ -12,18 +13,17 @@ namespace Cryville.Crtr {
readonly PdtRuleset _ruleset;
readonly Judge _judge;
public InputProxy(PdtRuleset ruleset, Judge judge) {
unsafe {
fixed (byte* ptr = _vecbuf) {
*(int*)(ptr + 3 * sizeof(float)) = PdtInternalType.Number;
}
for (int i = 0; i <= MAX_DEPTH; i++) {
var vecsrc = new InputVectorSrc();
_vecsrcs[i] = vecsrc;
_vecops[i] = new InputVectorOp(vecsrc);
}
_vecsrc = new PropSrc.Arbitrary(PdtInternalType.Vector, _vecbuf);
_etor = ChartPlayer.etor;
_ruleset = ruleset;
_judge = judge;
foreach (var i in ruleset.inputs) {
_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) {
if (i.Value.pass != null) {
@@ -33,15 +33,15 @@ namespace Cryville.Crtr {
}
}
#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<string, int> _use = new Dictionary<string, int>();
readonly Dictionary<string, List<string>> _rev = new Dictionary<string, List<string>>();
readonly Dictionary<Identifier, int> _use = new Dictionary<Identifier, int>();
readonly Dictionary<Identifier, List<Identifier>> _rev = new Dictionary<Identifier, List<Identifier>>();
public event EventHandler<ProxyChangedEventArgs> ProxyChanged;
public void LoadFrom(Dictionary<string, RulesetConfig.InputEntry> config) {
foreach (var cfg in config) {
Set(new InputProxyEntry {
Target = cfg.Key,
Target = new Identifier(cfg.Key),
Source = new InputSource {
Handler = Game.InputManager.GetHandler(cfg.Value.handler),
Type = cfg.Value.type
@@ -52,7 +52,7 @@ namespace Cryville.Crtr {
public void SaveTo(Dictionary<string, RulesetConfig.InputEntry> config) {
config.Clear();
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()),
type = p.Value.Source.Value.Type
});
@@ -81,14 +81,16 @@ namespace Cryville.Crtr {
public bool IsUsed(InputSource src) {
return _sproxies.ContainsKey(src);
}
public bool IsCompleted {
get {
foreach (var i in _use)
if (i.Value == 0 && !_tproxies.ContainsKey(i.Key)) return false;
return true;
}
public bool IsCompleted() {
foreach (var i in _use)
if (!IsCompleted(i.Key)) return false;
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);
var passes = _ruleset.inputs[name].pass;
if (passes != null) {
@@ -98,14 +100,14 @@ namespace Cryville.Crtr {
}
}
}
void IncrementReversedUseRecursive(string name) {
void IncrementReversedUseRecursive(Identifier name) {
foreach (var p in _rev[name]) {
_use[p]++;
BroadcastProxyChanged(p);
IncrementReversedUseRecursive(p);
}
}
void DecrementUseRecursive(string name) {
void DecrementUseRecursive(Identifier name) {
BroadcastProxyChanged(name);
var passes = _ruleset.inputs[name].pass;
if (passes != null) {
@@ -115,20 +117,20 @@ namespace Cryville.Crtr {
}
}
}
void DecrementReversedUseRecursive(string name) {
void DecrementReversedUseRecursive(Identifier name) {
foreach (var p in _rev[name]) {
_use[p]--;
BroadcastProxyChanged(p);
DecrementReversedUseRecursive(p);
}
}
void BroadcastProxyChanged(string name) {
void BroadcastProxyChanged(Identifier name) {
var del = ProxyChanged;
if (del != null) del(this, this[name]);
}
public ProxyChangedEventArgs this[string name] {
public ProxyChangedEventArgs this[Identifier name] {
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
@@ -164,22 +166,66 @@ namespace Cryville.Crtr {
protected void Dispose(bool disposing) {
if (disposing) {
Deactivate();
foreach (var proxy in _tproxies.Values) {
proxy.Source.Value.Handler.OnInput -= OnInput;
foreach (var proxy in _tproxies) {
proxy.Value.Source.Value.Handler.OnInput -= OnInput;
}
}
}
readonly object _lock = new object();
static readonly int _var_value = IdentifierManager.SharedInstance.Request("value");
static readonly PropOp.Arbitrary _arbop = new PropOp.Arbitrary();
readonly byte[] _vecbuf = new byte[3 * sizeof(float) + sizeof(int)];
readonly PropSrc.Arbitrary _vecsrc;
const int MAX_DEPTH = 15;
const int MAX_DIMENSION = 3;
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<InputSource, int> _activeCounts = new Dictionary<InputSource, int>();
readonly Dictionary<InputIdentifier, float> _vect = new Dictionary<InputIdentifier, float>();
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;
unsafe void OnInput(InputIdentifier id, InputVector vec) {
lock (_lock) {
@@ -189,15 +235,12 @@ namespace Cryville.Crtr {
float ft, tt = (float)(_lockTime != null ? _lockTime.Value : (vec.Time - _timeOrigins[id.Source.Handler]));
if (!_vect.TryGetValue(id, out ft)) ft = tt;
if (vec.IsNull) {
_etor.ContextCascadeUpdate(_var_value, _nullsrc);
_etor.ContextCascadeUpdate(_var_value, PropSrc.Null);
OnInput(id, proxy.Target, ft, tt, true);
}
else {
fixed (byte* ptr = _vecbuf) {
*(Vector3*)ptr = vec.Vector;
}
_vecsrc.Invalidate();
_etor.ContextCascadeUpdate(_var_value, _vecsrc);
_vecsrcs[0].Set(vec.Vector);
_etor.ContextCascadeUpdate(_var_value, _vecsrcs[0]);
OnInput(id, proxy.Target, ft, tt, false);
}
_vect[id] = tt;
@@ -207,21 +250,27 @@ namespace Cryville.Crtr {
}
static readonly int _var_fv = IdentifierManager.SharedInstance.Request("fv");
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];
if (def.pass != null) {
foreach (var p in def.pass) {
_etor.ContextCascadeInsert();
_arbop.Name = _var_value;
if (!nullflag) _etor.Evaluate(_arbop, p.Value);
OnInput(id, p.Key, ft, tt, nullflag);
bool newNullFlag = nullflag;
if (!newNullFlag) {
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();
}
}
else {
var pid = new ProxiedInputIdentifier { Source = id, Target = target };
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) _activeCounts[id.Source]++;
_etor.ContextCascadeInsert();
@@ -236,13 +285,14 @@ namespace Cryville.Crtr {
}
}
public void SyncTime(double time) {
foreach (var s in _sproxies.Keys) {
var h = s.Handler;
foreach (var s in _sproxies) {
var h = s.Key.Handler;
_timeOrigins[h] = h.GetCurrentTimestamp() - time;
}
}
public void ForceTick() {
foreach (var src in _sproxies.Keys) {
foreach (var s in _sproxies) {
var src = s.Key;
if (_activeCounts[src] == 0) {
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() {
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];
}
return result / _sproxies.Count;
@@ -261,19 +312,21 @@ namespace Cryville.Crtr {
}
public class ProxyChangedEventArgs : EventArgs {
public string Name { get; private set; }
public Identifier Name { get; private set; }
public InputSource? Proxy { 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;
Proxy = src;
Used = used;
Required = required;
}
}
public class InputProxyEntry {
public InputSource? Source { get; set; }
public string Target { get; set; }
public Identifier Target { get; set; }
public byte[] Mapping { get; private set; }
}
@@ -300,4 +353,12 @@ namespace Cryville.Crtr {
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.Collections.Generic;
using System.Globalization;
using System.Runtime.Serialization;
using System.Text.Formatting;
namespace Cryville.Crtr {
@@ -42,11 +43,12 @@ namespace Cryville.Crtr {
_numsrc3 = new PropSrc.Float(() => _numbuf3);
_numsrc4 = new PropSrc.Float(() => _numbuf4);
_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>();
evs.Add(i, l);
activeEvs.Add(i, new List<JudgeEvent>());
if (_judgePause != null && i.Key == _var_pause) {
evs.Add(id, l);
activeEvs.Add(id, new List<JudgeEvent>());
if (_judgePause != null && id.Key == _var_pause) {
l.Add(new JudgeEvent {
StartTime = double.NegativeInfinity, EndTime = double.PositiveInfinity,
StartClip = double.NegativeInfinity, EndClip = double.PositiveInfinity,
@@ -82,8 +84,9 @@ namespace Cryville.Crtr {
#region Judge
internal readonly Dictionary<int, int> judgeMap = new Dictionary<int, int>();
void InitJudges() {
foreach (var i in _rs.judges.Keys) {
judgeMap.Add(i.Key, IdentifierManager.SharedInstance.Request("judge_" + i.Name));
foreach (var i in _rs.judges) {
var id = i.Key;
judgeMap.Add(id.Key, IdentifierManager.SharedInstance.Request("judge_" + id.Name));
}
}
static bool _flag;
@@ -132,7 +135,7 @@ namespace Cryville.Crtr {
if (actlist.Count > 0) {
_numbuf3 = ft; _numsrc3.Invalidate(); _etor.ContextCascadeUpdate(_var_ft, _numsrc3);
_numbuf4 = tt; _numsrc4.Invalidate(); _etor.ContextCascadeUpdate(_var_tt, _numsrc4);
var index = 0;
int index = 0, iter = 0;
while (index >= 0 && index < actlist.Count) {
var ev = actlist[index];
_numbuf1 = (float)ev.StartTime; _numsrc1.Invalidate(); _etor.ContextCascadeUpdate(_var_fn, _numsrc1);
@@ -152,19 +155,21 @@ namespace Cryville.Crtr {
if (index < 0) index = ~index;
}
else index++;
if (iter++ >= 16) throw new JudgePropagationException();
}
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) {
var def = _rs.judges[i];
if (def.hit != null) _etor.Evaluate(_flagop, def.hit);
else _flag = true;
if (_flag) {
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);
return true;
}
@@ -247,9 +252,10 @@ namespace Cryville.Crtr {
public TargetString GetFullFormattedScoreString() {
bool flag = false;
scoreFullBuf.Clear();
foreach (var s in scores.Keys) {
scoreFullBuf.AppendFormat(flag ? "\n{0}: " : "{0}: ", (string)IdentifierManager.SharedInstance.Retrieve(s));
scoreFullBuf.AppendFormat(scoreFormatCache[s], scores[s]);
foreach (var s in scores) {
var id = s.Key;
scoreFullBuf.AppendFormat(flag ? "\n{0}: " : "{0}: ", (string)IdentifierManager.SharedInstance.Retrieve(id));
scoreFullBuf.AppendFormat(scoreFormatCache[id], scores[id]);
flag = true;
}
scoreFullStr.Length = scoreFullBuf.Count;
@@ -320,4 +326,12 @@ namespace Cryville.Crtr {
public string format = "";
}
#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;
private set;
}
public Material NewMaterial {
get {
return Material.Instantiate(GenericResources.Materials["-SpriteMat"]);
}
public static Material NewMaterial() {
return Material.Instantiate(GenericResources.Materials["-SpriteMat"]);
}
public void Init(Transform parent) {
MeshObject = new GameObject("__mesh__");
@@ -41,12 +39,10 @@ namespace Cryville.Crtr {
MeshObject.AddComponent<MeshRenderer>();
MeshFilter = MeshObject.GetComponent<MeshFilter>();
Renderer = MeshObject.GetComponent<Renderer>();
Renderer.material = NewMaterial;
Initialized = true;
}
public void Destroy() {
Mesh.Destroy(Mesh);
if (Renderer.material != null) Material.Destroy(Renderer.material);
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 float DelerpWith(Vector start, Vector value);
public abstract bool IsZero();
public override abstract string ToString();
public abstract float[] ToArray();
public abstract override string ToString();
public abstract unsafe void ToArray(float* arr);
public Vector Clone() {
return (Vector)MemberwiseClone();
@@ -442,8 +442,8 @@ namespace Cryville.Crtr {
return Value.ToString(CultureInfo.InvariantCulture);
}
public override float[] ToArray() {
return new float[] { Value };
public override unsafe void ToArray(float* arr) {
arr[0] = Value;
}
}
@@ -504,8 +504,8 @@ namespace Cryville.Crtr {
return Value.ToString(CultureInfo.InvariantCulture);
}
public override float[] ToArray() {
return new float[] { Value };
public override unsafe void ToArray(float* arr) {
arr[0] = Value;
}
}
@@ -566,8 +566,8 @@ namespace Cryville.Crtr {
return Value.ToString(CultureInfo.InvariantCulture);
}
public override float[] ToArray() {
return new float[] { Value };
public override unsafe void ToArray(float* arr) {
arr[0] = Value;
}
}
@@ -610,8 +610,8 @@ namespace Cryville.Crtr {
}
}
}
w = aw ? rw : (float?)null;
h = ah ? rh : (float?)null;
w = aw ? rw : null;
h = ah ? rh : null;
}
public static VecPtComp Parse(string s) {
@@ -669,8 +669,9 @@ namespace Cryville.Crtr {
return ToString(w, h);
}
public override float[] ToArray() {
return new float[] { w.Value, h.Value };
public override unsafe void ToArray(float* arr) {
arr[0] = w.Value;
arr[1] = h.Value;
}
}
@@ -764,8 +765,10 @@ namespace Cryville.Crtr {
);
}
public override float[] ToArray() {
return new float[] { x.Value, y.Value, z.Value };
public override unsafe void ToArray(float* arr) {
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);
}
public override float[] ToArray() {
return new float[] { xw.Value, xh.Value, yw.Value, yh.Value };
public override unsafe void ToArray(float* arr) {
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) : "");
}
public override float[] ToArray() {
return new float[] { xw.Value, xh.Value, yw.Value, yh.Value, z.Value };
public override unsafe void ToArray(float* arr) {
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;
public VectorSrc(Func<Vector> cb, int type) : base(type) { _cb = cb; }
public static VectorSrc Construct(Func<Vector> cb) {
if (cb().Dimension == 1) return new INumber(cb);
else return new IVector(cb);
}
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];
}
public VectorSrc(Func<Vector> cb) : base(PdtInternalType.Vector, MAX_DIMENSION * sizeof(float) + sizeof(int)) {
_cb = cb;
fixed (byte* rptr = buf) {
var ptr = (float*)rptr;
*(int*)(ptr + MAX_DIMENSION) = PdtInternalType.Number;
}
}
class IVector : VectorSrc {
public IVector(Func<Vector> cb) : base(cb, PdtInternalType.Vector) { }
protected override unsafe void InternalGet() {
var arr = _cb().ToArray();
buf = new byte[sizeof(float) * arr.Length + sizeof(int)];
fixed (byte* rptr = buf) {
var ptr = (float*)rptr;
for (int i = 0; i < arr.Length; i++, ptr++) {
*ptr = arr[i];
}
*(int*)ptr = PdtInternalType.Number;
}
protected override void InternalGet() {
var v = _cb();
if (v.Dimension > MAX_DIMENSION) throw new NotSupportedException("Vector dimension too large");
fixed (byte* rptr = buf) {
var ptr = (float*)rptr;
v.ToArray(ptr);
}
}
}
@@ -977,7 +974,7 @@ namespace Cryville.Crtr {
public class VectorOp : PropOp {
readonly Action<float[]> _cb;
public VectorOp(Action<float[]> cb) { _cb = cb; }
protected unsafe override void Execute() {
protected override unsafe void Execute() {
var op = GetOperand(0);
float[] values;
if (op.Type == PdtInternalType.Number) {
@@ -988,7 +985,7 @@ namespace Cryville.Crtr {
op.GetArraySuffix(out type, out _);
if (type != PdtInternalType.Number)
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) {
op.CopyTo((byte*)ptr, 0, op.Length - sizeof(int));
}

View File

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

View File

@@ -0,0 +1,91 @@
using Cryville.Common;
using Cryville.Common.Pdt;
using System;
using System.Globalization;
using System.Text.RegularExpressions;
using SIdentifier = Cryville.Common.Identifier;
namespace Cryville.Crtr {
public class PdtBinder : EmptyBinder {
public override object ChangeType(object value, Type type, CultureInfo culture) {
if (value is PdtExpression) {
var exp = (PdtExpression)value;
if (type.Equals(typeof(bool))) {
bool result = false;
ChartPlayer.etor.Evaluate(new PropOp.Boolean(r => result = r), exp);
return result;
}
else if (type.Equals(typeof(int))) {
int result = 0;
ChartPlayer.etor.Evaluate(new PropOp.Integer(r => result = r), exp);
return result;
}
else if (type.Equals(typeof(float))) {
float result = 0;
ChartPlayer.etor.Evaluate(new PropOp.Float(r => result = r), exp);
return result;
}
else if (type.Equals(typeof(string))) {
string result = default(string);
ChartPlayer.etor.Evaluate(new PropOp.String(r => result = r), exp);
return result;
}
else if (type.Equals(typeof(Clip))) {
Clip result = default(Clip);
ChartPlayer.etor.Evaluate(new PropOp.Clip(r => result = r), exp);
return result;
}
else if (type.Equals(typeof(Identifier))) {
Identifier result = default(Identifier);
ChartPlayer.etor.Evaluate(new pop_identstr(r => result = r), exp);
return result;
}
else if (type.Equals(typeof(Identifier[]))) {
Identifier[] result = null;
ChartPlayer.etor.Evaluate(new pop_identstrarr(r => result = r), exp);
return result;
}
}
else if (value is string) {
var exp = (string)value;
if (type.Equals(typeof(Identifier))) {
return new Identifier(exp);
}
else if (type == typeof(ScoreOperation)) {
var m = Regex.Match(exp, @"^(\S+)\s*?(\S+)?$");
var name = new Identifier(m.Groups[1].Value);
if (!m.Groups[2].Success) return new ScoreOperation { name = name };
var op = new Identifier(m.Groups[2].Value);
return new ScoreOperation { name = name, op = op };
}
}
return base.ChangeType(value, type, culture);
}
#pragma warning disable IDE1006
class pop_identstr : PropOp {
readonly Action<SIdentifier> _cb;
public pop_identstr(Action<SIdentifier> cb) { _cb = cb; }
protected override void Execute() {
var op = GetOperand(0);
if (op.Type == PdtInternalType.Undefined) _cb(new SIdentifier(op.AsIdentifier()));
else if (op.Type == PdtInternalType.String) _cb(new SIdentifier(op.AsString()));
else throw new InvalidCastException("Not an identifier or string");
}
}
class pop_identstrarr : PdtOperator {
readonly Action<SIdentifier[]> _cb;
public pop_identstrarr(Action<SIdentifier[]> cb) : base(16) { _cb = cb; }
protected override void Execute() {
var result = new SIdentifier[LoadedOperandCount];
for (int i = 0; i < LoadedOperandCount; i++) {
var op = GetOperand(i);
if (op.Type != PdtInternalType.Undefined)
throw new InvalidCastException("Not an identifier");
result[i] = new SIdentifier(op.AsIdentifier());
}
_cb(result);
}
}
#pragma warning restore IDE1006
}
}

View File

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

View File

@@ -1,4 +1,5 @@
using Cryville.Common;
using Cryville.Common.Math;
using Cryville.Common.Pdt;
using Cryville.Crtr.Event;
using System;
@@ -13,32 +14,40 @@ namespace Cryville.Crtr {
static readonly byte[] _nullbuf = new byte[0];
readonly byte[] _numbuf = new byte[4];
readonly PropSrc _vecsrc;
Vector _vec;
static readonly int _var_w = IdentifierManager.SharedInstance.Request("w");
static readonly int _var_h = IdentifierManager.SharedInstance.Request("h");
static readonly int _var_current_time = IdentifierManager.SharedInstance.Request("current_time");
static readonly int _var_inf = IdentifierManager.SharedInstance.Request("inf");
static readonly int _var_true = IdentifierManager.SharedInstance.Request("true");
static readonly int _var_false = IdentifierManager.SharedInstance.Request("false");
static readonly int _var_null = IdentifierManager.SharedInstance.Request("null");
static readonly int _var_current_time = IdentifierManager.SharedInstance.Request("current_time");
protected override void GetVariable(int name, bool forced, out int type, out byte[] value) {
if (name == _var_w) { LoadNum(ChartPlayer.hitRect.width); type = PdtInternalType.Number; value = _numbuf; }
else if (name == _var_h) { LoadNum(ChartPlayer.hitRect.height); type = PdtInternalType.Number; value = _numbuf; }
else if (name == _var_inf) { LoadNum(float.PositiveInfinity); type = PdtInternalType.Number; value = _numbuf; }
else if (name == _var_true) { LoadNum(1); type = PdtInternalType.Number; value = _numbuf; }
else if (name == _var_false) { LoadNum(0); type = PdtInternalType.Number; value = _numbuf; }
else if (name == _var_null) { LoadIdent(0); type = PdtInternalType.Undefined; value = _numbuf; }
else {
var id = new Identifier(name);
PropSrc prop;
PropSrc prop; SkinVariable variable;
if (ContextEvent != null && ContextEvent.PropSrcs.TryGetValue(name, out prop)) {
prop.Get(out type, out value);
}
else if (ContextState != null && ChartPlayer.motionRegistry.ContainsKey(id)) {
var vec = ContextState.GetRawValue(id);
VectorSrc.Construct(() => vec).Get(out type, out value);
_vec = ContextState.GetRawValue(id);
_vecsrc.Invalidate();
_vecsrc.Get(out type, out value);
}
else if (ContextState != null && ContextState.Handler.PropSrcs.TryGetValue(name, out prop)) {
prop.Get(out type, out value);
RevokePotentialConstant();
}
else if (ContextSkinContainer != null && ContextSkinContainer.Variables.TryGetValue(name, out variable)) {
variable.Src.Get(out type, out value);
}
else if (ContextJudge != null && ContextJudge.TryGetScoreSrc(name, out prop)) {
prop.Get(out type, out value);
RevokePotentialConstant();
@@ -98,12 +107,20 @@ namespace Cryville.Crtr {
else throw new KeyNotFoundException(string.Format("Undefined collapse operator {0}", IdentifierManager.SharedInstance.Retrieve(name)));
}
public ChartEvent ContextEvent { private get; set; }
public ContainerState ContextState { private get; set; }
public Transform ContextTransform { private get; set; }
public Judge ContextJudge { private get; set; }
public PropSrc ContextSelfValue { private get; set; }
public ChartEvent ContextEvent { get; set; }
public ContainerState ContextState { get; set; }
public SkinContainer ContextSkinContainer { get; set; }
public Transform ContextTransform { get; set; }
public Judge ContextJudge { get; set; }
public PropSrc ContextSelfValue { get; set; }
readonly Stack<int> ContextCascadeBlocks = new Stack<int>();
public void ContextCascadeInsertBlock() {
ContextCascadeBlocks.Push(_cascadeHeight);
}
public void ContextCascadeDiscardBlock() {
ContextCascadeBlocks.Pop();
}
readonly Dictionary<int, PropSrc>[] ContextCascade = new Dictionary<int, PropSrc>[256];
int _cascadeHeight;
public void ContextCascadeInsert() {
@@ -118,7 +135,7 @@ namespace Cryville.Crtr {
}
public PropSrc ContextCascadeLookup(int name) {
PropSrc result;
for (int i = _cascadeHeight - 1; i >= 0; i--) {
for (int i = _cascadeHeight - 1; i >= ContextCascadeBlocks.Peek(); i--) {
Dictionary<int, PropSrc> cas = ContextCascade[i];
if (cas.TryGetValue(name, out result)) {
return result;
@@ -131,7 +148,9 @@ namespace Cryville.Crtr {
}
public PdtEvaluator() {
ContextCascadeBlocks.Push(0);
for (int i = 0; i < ContextCascade.Length; i++) ContextCascade[i] = new Dictionary<int, PropSrc>();
_vecsrc = new VectorSrc(() => _vec);
_ctxops.Add(IdentifierManager.SharedInstance.Request("screen_edge"), new func_screen_edge(() => ContextTransform));
_ctxops.Add(IdentifierManager.SharedInstance.Request("int"), new func_int(() => ContextSelfValue));
@@ -139,6 +158,12 @@ namespace Cryville.Crtr {
_ctxops.Add(IdentifierManager.SharedInstance.Request("min"), new func_min(() => ContextSelfValue));
_ctxops.Add(IdentifierManager.SharedInstance.Request("max"), new func_max(() => ContextSelfValue));
_ctxops.Add(IdentifierManager.SharedInstance.Request("abs"), new func_abs(() => ContextSelfValue));
_ctxops.Add(IdentifierManager.SharedInstance.Request("anim"), new func_anim(() => ContextSelfValue));
_ctxops.Add(IdentifierManager.SharedInstance.Request("cubic_bezier"), new func_cubic_bezier(() => ContextSelfValue));
_ctxops.Add(IdentifierManager.SharedInstance.Request("ease"), new func_cubic_bezier_fixed(0.25f, 0.1f, 0.25f, 1f, () => ContextSelfValue));
_ctxops.Add(IdentifierManager.SharedInstance.Request("ease_in"), new func_cubic_bezier_fixed(0.42f, 0f, 1f, 1f, () => ContextSelfValue));
_ctxops.Add(IdentifierManager.SharedInstance.Request("ease_out"), new func_cubic_bezier_fixed(0f, 0f, 0.58f, 1f, () => ContextSelfValue));
_ctxops.Add(IdentifierManager.SharedInstance.Request("ease_in_out"), new func_cubic_bezier_fixed(0.42f, 0f, 0.58f, 1f, () => ContextSelfValue));
Func<int, PropSrc> cccb = k => ContextCascadeLookup(k);
_ctxops.Add(IdentifierManager.SharedInstance.Request("attack_timing"), new func_attack_timing(cccb));
@@ -255,6 +280,7 @@ namespace Cryville.Crtr {
protected override void Execute() {
var o0 = GetOperand(0);
int type = o0.Type;
if (type == PdtInternalType.Error) throw new InvalidOperationException("Error");
int len = o0.Length;
bool blit = !IsBlittable(type);
for (var i = 1; i < LoadedOperandCount; i++) {
@@ -478,6 +504,85 @@ namespace Cryville.Crtr {
ret.SetNumber(Mathf.Abs(arg));
}
}
class func_anim : PdtOperator {
readonly Func<PropSrc> _ctxcb;
public func_anim(Func<PropSrc> ctxcb) : base(3) {
_ctxcb = ctxcb;
}
protected override unsafe void Execute() {
var op1 = GetOperand(0);
var op2 = GetOperand(1);
var dim1 = GetDimension(op1);
var dim2 = GetDimension(op2);
var dim0 = Math.Min(dim1, dim2);
float time;
switch (LoadedOperandCount) {
case 2: time = oputil.AsNumber(_ctxcb()); break;
case 3: time = GetOperand(2).AsNumber(); break;
default: throw new ArgumentException("Argument count not 2 or 3");
}
if (dim0 == 1) {
GetReturnFrame(PdtInternalType.Number, sizeof(float))
.SetNumber(op1.AsNumber() * (1 - time) + op2.AsNumber() * time);
}
else {
var ret = GetReturnFrame(PdtInternalType.Vector, dim0 * sizeof(float) + sizeof(int));
for (int i = 0; i < dim0 * sizeof(float); i += sizeof(float)) {
ret.SetNumber(op1.AsNumber(i) * (1 - time) + op2.AsNumber(i) * time, i);
}
ret.SetArraySuffix(PdtInternalType.Number);
}
}
static int GetDimension(PdtVariableMemory op) {
switch (op.Type) {
case PdtInternalType.Number: return 1;
case PdtInternalType.Vector:
int arrtype, _;
op.GetArraySuffix(out arrtype, out _);
if (arrtype != PdtInternalType.Number)
throw new ArgumentException("Not animatable");
return (op.Length - sizeof(int)) / sizeof(float);
default: throw new ArgumentException("Not animatable");
}
}
}
class func_cubic_bezier : PdtOperator {
readonly Func<PropSrc> _ctxcb;
public func_cubic_bezier(Func<PropSrc> ctxcb) : base(5) {
_ctxcb = ctxcb;
}
protected override unsafe void Execute() {
float x1 = GetOperand(0).AsNumber(), y1 = GetOperand(1).AsNumber();
float x2 = GetOperand(2).AsNumber(), y2 = GetOperand(3).AsNumber();
float time;
switch (LoadedOperandCount) {
case 4: time = oputil.AsNumber(_ctxcb()); break;
case 5: time = GetOperand(4).AsNumber(); break;
default: throw new ArgumentException("Argument count not 4 or 5");
}
GetReturnFrame(PdtInternalType.Number, sizeof(float))
.SetNumber(CubicBezier.Evaluate(time, x1, y1, x2, y2, 1e-5f));
}
}
class func_cubic_bezier_fixed : PdtOperator {
readonly float x1, y1, x2, y2;
readonly Func<PropSrc> _ctxcb;
public func_cubic_bezier_fixed(float x1, float y1, float x2, float y2, Func<PropSrc> ctxcb) : base(1) {
this.x1 = x1; this.y1 = y1;
this.x2 = x2; this.y2 = y2;
_ctxcb = ctxcb;
}
protected override void Execute() {
float time;
switch (LoadedOperandCount) {
case 0: time = oputil.AsNumber(_ctxcb()); break;
case 1: time = GetOperand(0).AsNumber(); break;
default: throw new ArgumentException("Argument count not 0 or 1");
}
GetReturnFrame(PdtInternalType.Number, sizeof(float))
.SetNumber(CubicBezier.Evaluate(time, x1, y1, x2, y2, 1e-5f));
}
}
#endregion
#region Judge Functions
static readonly int _var_fn = IdentifierManager.SharedInstance.Request("fn");
@@ -546,12 +651,12 @@ namespace Cryville.Crtr {
}
}
#endregion
unsafe static class oputil {
static unsafe class oputil {
public static float AsNumber(PropSrc src) {
if (src == null) throw new ArgumentNullException("src");
int type; byte[] value;
src.Get(out type, out value);
if (type != PdtInternalType.Number)
if (type != PdtInternalType.Number && type != PdtInternalType.Vector)
throw new ArgumentException("Not a number");
fixed (byte* ptr = value) {
return *(float*)ptr;

View File

@@ -60,6 +60,24 @@ namespace Cryville.Crtr {
_cb(GetOperand(0).AsString());
}
}
public class StringArray : PropOp {
readonly Action<string[]> _cb;
public StringArray(Action<string[]> cb) { _cb = cb; }
protected override unsafe void Execute() {
var op = GetOperand(0);
int arrtype; int len;
op.GetArraySuffix(out arrtype, out len);
if (arrtype != PdtInternalType.String) throw new InvalidCastException("Not an array of strings");
var result = new string[len];
int o = 0;
for (int i = 0; i < len; i++) {
string v = op.AsString(o);
o += v.Length * sizeof(char) + sizeof(int);
result[i] = v;
}
_cb(result);
}
}
public class TargetString : PropOp {
readonly Func<RTargetString> _cb;
public TargetString(Func<RTargetString> cb) { _cb = cb; }
@@ -82,22 +100,25 @@ namespace Cryville.Crtr {
}
}
public class Enum<T> : PropOp {
readonly static Dictionary<int, int> _cache = new Dictionary<int, int>();
static readonly Dictionary<int, int> _cache = new Dictionary<int, int>();
readonly Action<T> _cb;
readonly Func<int, T> _caster;
public Enum(Action<T> cb, Func<int, T> caster) {
static Enum() {
if (!typeof(T).IsEnum)
throw new ArgumentException("Type is not enum");
var names = typeof(T).GetFields(BindingFlags.Public | BindingFlags.Static);
for (int i = 0; i < names.Length; i++)
_cache[IdentifierManager.SharedInstance.Request(names[i].Name)] = Convert.ToInt32(names[i].GetValue(null));
}
public Enum(Action<T> cb, Func<int, T> caster) {
_cb = cb;
_caster = caster;
}
protected override void Execute() {
int result = 0;
for (int i = 0; i < LoadedOperandCount; i++)
result |= _cache[GetOperand(0).AsIdentifier()];
result |= _cache[GetOperand(i).AsIdentifier()];
_cb(_caster(result));
}
}

View File

@@ -43,6 +43,7 @@ namespace Cryville.Crtr {
buf[0] = _cb() ? (byte)1 : (byte)0;
}
}
public static readonly PropSrc Error = new Arbitrary(PdtInternalType.Error, new byte[0]);
public class Float : FixedBuffer {
readonly Func<float> _cb;
public Float(Func<float> cb) : base(PdtInternalType.Number, 4) { _cb = cb; }
@@ -53,6 +54,7 @@ namespace Cryville.Crtr {
}
}
}
public static readonly PropSrc Null = new Arbitrary(PdtInternalType.Null, new byte[0]);
public class String : PropSrc {
readonly Func<string> _cb;
public String(Func<string> cb) : base(PdtInternalType.String) { _cb = cb; }

View File

@@ -1,14 +1,12 @@
using Cryville.Common;
using Cryville.Common.Collections.Generic;
using Cryville.Common.Pdt;
using Cryville.Crtr.Browsing;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using SIdentifier = Cryville.Common.Identifier;
namespace Cryville.Crtr {
public class Ruleset : MetaInfo {
@@ -25,35 +23,38 @@ namespace Cryville.Crtr {
public void LoadPdt(DirectoryInfo dir) {
using (StreamReader pdtreader = new StreamReader(dir.FullName + "/" + data + ".pdt", Encoding.UTF8)) {
var src = pdtreader.ReadToEnd();
Root = (PdtRuleset)new RulesetInterpreter(src, null).Interpret();
Root = (PdtRuleset)new RulesetInterpreter(src, null).Interpret(typeof(PdtRuleset));
}
}
}
[Binder(typeof(PdtRulesetBinder))]
[Binder(typeof(PdtBinder))]
public class PdtRuleset {
public Dictionary<Identifier, InputDefinition> inputs;
public Dictionary<Identifier, JudgeDefinition> judges;
public Dictionary<Identifier, ScoreDefinition> scores;
public Constraint constraints;
public void Optimize(PdtEvaluatorBase etor) {
foreach (var i in inputs.Values) {
if (i.pass != null) foreach (var e in i.pass.Values) {
etor.Optimize(e);
foreach (var i in inputs) {
var input = i.Value;
if (input.pass != null) foreach (var e in input.pass) {
etor.Optimize(e.Value);
}
}
foreach (var j in judges.Values) {
if (j.hit != null) etor.Optimize(j.hit);
if (j.scores != null) {
foreach (var s in j.scores) {
foreach (var j in judges) {
var judge = j.Value;
if (judge.hit != null) etor.Optimize(judge.hit);
if (judge.scores != null) {
foreach (var s in judge.scores) {
if (s.Key.op != default(Identifier))
etor.PatchCompound(s.Key.name.Key, s.Key.op.Key, s.Value);
etor.Optimize(s.Value);
}
}
}
foreach (var s in scores.Values) {
if (s.value != null) etor.Optimize(s.value);
foreach (var s in scores) {
var score = s.Value;
if (score.value != null) etor.Optimize(score.value);
}
constraints.Optimize(etor);
}
@@ -64,12 +65,12 @@ namespace Cryville.Crtr {
public class Constraint {
static readonly PropOp.Arbitrary _arbop = new PropOp.Arbitrary();
[ElementList]
public Dictionary<RulesetSelectors, Constraint> Elements = new Dictionary<RulesetSelectors, Constraint>();
public PairList<RulesetSelectors, Constraint> Elements = new PairList<RulesetSelectors, Constraint>();
[PropertyList]
public Dictionary<PropertyKey, PdtExpression> Properties = new Dictionary<PropertyKey, PdtExpression>();
public PairList<PropertyKey, PdtExpression> Properties = new PairList<PropertyKey, PdtExpression>();
public void Optimize(PdtEvaluatorBase etor) {
foreach (var e in Properties.Values) {
etor.Optimize(e);
foreach (var e in Properties) {
etor.Optimize(e.Value);
}
foreach (var e in Elements) {
e.Key.Optimize(etor);
@@ -126,88 +127,6 @@ namespace Cryville.Crtr {
Property,
Variable,
}
public class PdtRulesetBinder : EmptyBinder {
public override object ChangeType(object value, Type type, CultureInfo culture) {
if (value is PdtExpression) {
var exp = (PdtExpression)value;
if (type.Equals(typeof(bool))) {
bool result = false;
ChartPlayer.etor.Evaluate(new PropOp.Boolean(r => result = r), exp);
return result;
}
else if (type.Equals(typeof(int))) {
int result = 0;
ChartPlayer.etor.Evaluate(new PropOp.Integer(r => result = r), exp);
return result;
}
else if (type.Equals(typeof(float))) {
float result = 0;
ChartPlayer.etor.Evaluate(new PropOp.Float(r => result = r), exp);
return result;
}
else if (type.Equals(typeof(string))) {
string result = default(string);
ChartPlayer.etor.Evaluate(new PropOp.String(r => result = r), exp);
return result;
}
else if (type.Equals(typeof(Clip))) {
Clip result = default(Clip);
ChartPlayer.etor.Evaluate(new PropOp.Clip(r => result = r), exp);
return result;
}
else if (type.Equals(typeof(Identifier))) {
Identifier result = default(Identifier);
ChartPlayer.etor.Evaluate(new pop_identstr(r => result = r), exp);
return result;
}
else if (type.Equals(typeof(Identifier[]))) {
Identifier[] result = null;
ChartPlayer.etor.Evaluate(new pop_identstrarr(r => result = r), exp);
return result;
}
}
else if (value is string) {
var exp = (string)value;
if (type.Equals(typeof(Identifier))) {
return (Identifier)exp;
}
else if (type == typeof(ScoreOperation)) {
var m = Regex.Match(exp, @"^(\S+)\s*?(\S+)?$");
var name = new Identifier(m.Groups[1].Value);
if (!m.Groups[2].Success) return new ScoreOperation { name = name };
var op = new Identifier(m.Groups[2].Value);
return new ScoreOperation { name = name, op = op };
}
}
return base.ChangeType(value, type, culture);
}
#pragma warning disable IDE1006
class pop_identstr : PropOp {
readonly Action<SIdentifier> _cb;
public pop_identstr(Action<SIdentifier> cb) { _cb = cb; }
protected override void Execute() {
var op = GetOperand(0);
if (op.Type == PdtInternalType.Undefined) _cb(new SIdentifier(op.AsIdentifier()));
else if (op.Type == PdtInternalType.String) _cb(new SIdentifier(op.AsString()));
else throw new InvalidCastException("Not an identifier or string");
}
}
class pop_identstrarr : PdtOperator {
readonly Action<SIdentifier[]> _cb;
public pop_identstrarr(Action<SIdentifier[]> cb) : base(16) { _cb = cb; }
protected override void Execute() {
var result = new SIdentifier[LoadedOperandCount];
for (int i = 0; i < LoadedOperandCount; i++) {
var op = GetOperand(i);
if (op.Type != PdtInternalType.Undefined)
throw new InvalidCastException("Not an identifier");
result[i] = new SIdentifier(op.AsIdentifier());
}
_cb(result);
}
}
#pragma warning restore IDE1006
}
public class RulesetViolationException : Exception {
public RulesetViolationException() { }
public RulesetViolationException(string message) : base(message) { }

View File

@@ -5,7 +5,7 @@ using System.Reflection;
namespace Cryville.Crtr {
internal class RulesetInterpreter : PdtInterpreter {
public RulesetInterpreter(string src, Binder binder) : base(src, typeof(PdtRuleset), binder) { }
public RulesetInterpreter(string src, Binder binder) : base(src, binder) { }
readonly List<RulesetSelector> s = new List<RulesetSelector>();
readonly List<string> a = new List<string>();

View File

@@ -6,7 +6,7 @@ using RangeAttribute = Cryville.Common.ComponentModel.RangeAttribute;
namespace Cryville.Crtr {
public class Settings {
[Category("graphics")]
[LogarithmicScale][Step(0.5f)][Precision(1e-2)]
[LogarithmicScale][Range(0.01f, 20f)][Step(0.5f)][Precision(1e-2)]
public float BackwardClippingDistance {
get {
return PlayerPrefs.GetFloat("BackwardClippingDistance", 0.2f);
@@ -62,8 +62,7 @@ namespace Cryville.Crtr {
}
[Category("gameplay")]
[Step(0.01f)]
[Precision(1e-3)]
[Step(0.01f)][Precision(1e-3)]
public float GraphicalOffset {
get {
return PlayerPrefs.GetFloat("GraphicalOffset", 0);
@@ -132,7 +131,7 @@ namespace Cryville.Crtr {
}
[Category("graphics")]
[LogarithmicScale][Step(0.5f)][Precision(1e-1)]
[LogarithmicScale][Range(0.1f, 200f)][Step(0.5f)][Precision(1e-1)]
public float RenderDistance {
get {
return PlayerPrefs.GetFloat("RenderDistance", 4);
@@ -166,8 +165,8 @@ namespace Cryville.Crtr {
}
[Browsable(false)]
[Category("gameplay")]
[Description("(Not implemented yet)")]
[Category("debug")]
[Range(0, float.PositiveInfinity)][Step(10f)][Precision(1e-1)]
public float StartOffset {
get {
return PlayerPrefs.GetFloat("StartOffset", 0);

View File

@@ -1,6 +1,9 @@
using Cryville.Common;
using Cryville.Common.Collections.Generic;
using Cryville.Common.Pdt;
using Cryville.Crtr.Browsing;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
@@ -25,21 +28,57 @@ namespace Cryville.Crtr {
public void LoadPdt(DirectoryInfo dir) {
using (StreamReader pdtreader = new StreamReader(dir.FullName + "/" + data + ".pdt", Encoding.UTF8)) {
var src = pdtreader.ReadToEnd();
Root = (PdtSkin)new SkinInterpreter(src, null).Interpret();
var interpreter = new SkinInterpreter(src, null);
var format = interpreter.GetFormatVersion();
if (format.Length == 1) {
Root = new PdtSkin();
Root.elements = (SkinElement)new SkinInterpreter(src, new PdtBinder()).Interpret(typeof(SkinElement));
}
else {
switch (format[1]) {
case 1:
Root = (PdtSkin)new SkinInterpreter(src, new PdtBinder()).Interpret(typeof(PdtSkin));
break;
default: throw new NotSupportedException("Unsupported skin format");
}
}
}
}
}
public class PdtSkin : SkinElement { }
public class PdtSkin {
public Dictionary<Identifier, AnimationSpan> animations
= new Dictionary<Identifier, AnimationSpan>();
public Dictionary<Identifier, EffectDefinition> effects
= new Dictionary<Identifier, EffectDefinition>();
public SkinElement elements;
public void Optimize(PdtEvaluator etor) {
foreach (var a in animations) {
a.Value.Optimize(etor);
}
foreach (var e in effects) {
var effect = e.Value;
etor.ContextCascadeInsert();
etor.ContextCascadeUpdate(EffectInstance._VAR_EFFECT_INDEX, PropSrc.Error);
foreach(var s in effect.states) {
etor.Optimize(s.Value.duration);
}
effect.elements.Optimize(etor);
etor.ContextCascadeDiscard();
}
elements.Optimize(etor);
}
}
public class SkinElement {
[ElementList]
public Dictionary<SkinSelectors, SkinElement> elements
= new Dictionary<SkinSelectors, SkinElement>();
public PairList<SkinSelectors, SkinElement> elements
= new PairList<SkinSelectors, SkinElement>();
[PropertyList]
public Dictionary<SkinPropertyKey, PdtExpression> properties
= new Dictionary<SkinPropertyKey, PdtExpression>();
public PairList<SkinPropertyKey, PdtExpression> properties
= new PairList<SkinPropertyKey, PdtExpression>();
public bool IsDynamic {
get;
@@ -48,9 +87,9 @@ namespace Cryville.Crtr {
public void Optimize(PdtEvaluatorBase etor) {
IsDynamic = true;
foreach (var e in properties.Values) {
etor.Optimize(e);
if (!e.IsConstant)
foreach (var e in properties) {
etor.Optimize(e.Value);
if (!e.Value.IsConstant)
IsDynamic = true;
}
foreach (var e in elements) {
@@ -61,4 +100,48 @@ namespace Cryville.Crtr {
}
}
}
public class EffectDefinition {
static Identifier _ident_init = new Identifier("init");
#pragma warning disable IDE1006
public PdtExpression duration {
set {
EffectState s;
if (!states.TryGetValue(_ident_init, out s))
throw new InvalidOperationException("Cannot set duration and states at the same time");
s.duration = value;
}
}
#pragma warning restore IDE1006
public Identifier init = _ident_init;
public Dictionary<Identifier, EffectState> states = new Dictionary<Identifier, EffectState> {
{ _ident_init, new EffectState() { rewind = _ident_init } }
};
public SkinElement elements;
}
public class EffectState {
public PdtExpression duration;
public Identifier rewind;
public Identifier next;
}
public class AnimationSpan {
[ElementList]
public PairList<Clip, AnimationSpan> spans
= new PairList<Clip, AnimationSpan>();
[PropertyList]
public PairList<SkinPropertyKey, PdtExpression> properties
= new PairList<SkinPropertyKey, PdtExpression>();
public void Optimize(PdtEvaluator etor) {
foreach (var p in properties) {
etor.Optimize(p.Value);
}
foreach (var e in spans) {
e.Value.Optimize(etor);
}
}
}
}

View File

@@ -1,13 +1,16 @@
using Cryville.Common.Pdt;
using Cryville.Crtr.Event;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Profiling;
namespace Cryville.Crtr {
public class SkinContainer {
readonly PdtSkin skin;
readonly ISkinnableGroup _group;
readonly SkinElement _rootElement;
readonly DynamicStack[] _stacks = new DynamicStack[2];
readonly HashSet<SkinPropertyKey> _once = new HashSet<SkinPropertyKey>();
public readonly Dictionary<int, SkinVariable> Variables = new Dictionary<int, SkinVariable>();
class DynamicStack {
public readonly List<DynamicProperty> Properties = new List<DynamicProperty>();
public readonly List<DynamicElement> Elements = new List<DynamicElement>();
@@ -26,25 +29,26 @@ namespace Cryville.Crtr {
public SkinSelectors Selectors { get; set; }
public SkinElement Element { get; set; }
}
public SkinContainer(PdtSkin _skin) {
skin = _skin;
public SkinContainer(ISkinnableGroup group, SkinElement rootElement) {
_group = group;
_rootElement = rootElement;
for (int i = 0; i < _stacks.Length; i++) _stacks[i] = new DynamicStack();
_rtimeSrc = new PropSrc.Float(() => _rtime);
}
public void MatchStatic(ContainerState state) {
public void MatchStatic() {
var stack = _stacks[0];
stack.Clear();
ChartPlayer.etor.ContextState = state;
ChartPlayer.etor.ContextEvent = state.Container;
MatchStatic(skin, state, stack, new RuntimeSkinContext(state.Handler.SkinContext));
ChartPlayer.etor.ContextEvent = null;
ChartPlayer.etor.ContextState = null;
MatchStatic(_rootElement, stack, new RuntimeSkinContext(_group.SkinContext));
}
void MatchStatic(SkinElement rel, ContainerState state, DynamicStack stack, RuntimeSkinContext ctx) {
void MatchStatic(SkinElement rel, DynamicStack stack, RuntimeSkinContext ctx) {
var rc = ctx.ReadContext;
ChartPlayer.etor.ContextTransform = rc.Transform;
if (rc.PropSrcs != null) ChartPlayer.etor.ContextCascadeInsert(rc.PropSrcs);
foreach (var p in rel.properties) {
p.Key.ExecuteStatic(state, ctx, p.Value);
try {
p.Key.ExecuteStatic(_group, ctx, p.Value, Variables);
}
catch (EvaluationFailureException) { }
if (p.Key.IsValueRequired && !p.Value.IsConstant) stack.Properties.Add(
new DynamicProperty { Context = ctx, Key = p.Key, Value = p.Value }
);
@@ -52,13 +56,13 @@ namespace Cryville.Crtr {
ChartPlayer.etor.ContextTransform = null;
foreach (var e in rel.elements) {
try {
var nctxs = e.Key.MatchStatic(state, rc);
var nctxs = e.Key.MatchStatic(_group, rc);
if (nctxs != null) {
var roflag = e.Key.annotations.Contains("if");
var woflag = e.Key.annotations.Contains("then");
foreach (var nctx in nctxs) {
var nrctx = new RuntimeSkinContext(nctx, ctx, roflag, woflag);
MatchStatic(e.Value, state, stack, nrctx);
MatchStatic(e.Value, stack, nrctx);
}
}
}
@@ -70,17 +74,19 @@ namespace Cryville.Crtr {
}
if (rc.PropSrcs != null) ChartPlayer.etor.ContextCascadeDiscard();
}
public void MatchDynamic(ContainerState state) {
var stack = _stacks[state.CloneType >> 1];
var nstack = (state.CloneType >> 1) + 1 < _stacks.Length ? _stacks[(state.CloneType >> 1) + 1] : null;
if (nstack != null) nstack.Clear();
public void MatchDynamic(int dl, bool recursive = false) {
var stack = _stacks[dl];
if (stack.Properties.Count == 0 && stack.Elements.Count == 0) return;
var nstack = dl + 1 < _stacks.Length ? _stacks[dl + 1] : null;
if (nstack != null) nstack.Clear();
Profiler.BeginSample("SkinContainer.MatchDynamic");
ChartPlayer.etor.ContextState = state;
ChartPlayer.etor.ContextEvent = state.Container;
if (!recursive) ChartPlayer.etor.ContextSkinContainer = this;
for (int i = 0; i < stack.Properties.Count; i++) {
DynamicProperty p = stack.Properties[i];
p.Key.ExecuteDynamic(state, p.Context, p.Value);
p.Key.ExecuteDynamic(_group, p.Context, p.Value, Variables, dl);
if (p.Key.annotations.Contains("once")) {
stack.Properties.RemoveAt(i--);
}
}
for (int i = 0; i < stack.Elements.Count; i++) {
DynamicElement e = stack.Elements[i];
@@ -88,33 +94,44 @@ namespace Cryville.Crtr {
if (psrcs != null) ChartPlayer.etor.ContextCascadeInsert(psrcs);
SkinContext nctx = null;
try {
nctx = e.Selectors.MatchDynamic(state, e.Context.ReadContext);
nctx = e.Selectors.MatchDynamic(_group, e.Context.ReadContext);
}
catch (SelectorNotAvailableException) {
if (nstack == null) throw;
nstack.Elements.Add(e);
}
if (nctx != null) MatchDynamic(e.Element, state, nstack, new RuntimeSkinContext(
nctx, e.Context, e.Selectors.annotations.Contains("if"), e.Selectors.annotations.Contains("then")
));
if (nctx != null) {
MatchDynamic(e.Element, dl, nstack, new RuntimeSkinContext(
nctx, e.Context, e.Selectors.annotations.Contains("if"), e.Selectors.annotations.Contains("then")
));
if (e.Selectors.annotations.Contains("once")) {
stack.Elements.RemoveAt(i--);
}
}
if (psrcs != null) ChartPlayer.etor.ContextCascadeDiscard();
}
ChartPlayer.etor.ContextEvent = null;
ChartPlayer.etor.ContextState = null;
if (!recursive) ChartPlayer.etor.ContextSkinContainer = null;
Profiler.EndSample();
}
void MatchDynamic(SkinElement rel, ContainerState state, DynamicStack stack, RuntimeSkinContext ctx) {
void MatchDynamic(SkinElement rel, int dl, DynamicStack stack, RuntimeSkinContext ctx) {
var rc = ctx.ReadContext;
ChartPlayer.etor.ContextTransform = rc.Transform;
if (rc.PropSrcs != null) ChartPlayer.etor.ContextCascadeInsert(rc.PropSrcs);
foreach (var p in rel.properties) {
p.Key.ExecuteDynamic(state, ctx, p.Value);
if (p.Key.annotations.Contains("once")) {
if (_once.Contains(p.Key)) continue;
p.Key.ExecuteDynamic(_group, ctx, p.Value, Variables, dl);
_once.Add(p.Key);
}
else {
p.Key.ExecuteDynamic(_group, ctx, p.Value, Variables, dl);
}
}
ChartPlayer.etor.ContextTransform = null;
foreach (var e in rel.elements) {
if (e.Key.IsUpdatable(state)) {
SkinContext nctx = e.Key.MatchDynamic(state, rc);
if (nctx != null) MatchDynamic(e.Value, state, stack, new RuntimeSkinContext(
if (e.Key.IsUpdatable(_group, dl)) {
SkinContext nctx = e.Key.MatchDynamic(_group, rc);
if (nctx != null) MatchDynamic(e.Value, dl, stack, new RuntimeSkinContext(
nctx, ctx, e.Key.annotations.Contains("if"), e.Key.annotations.Contains("then")
));
}
@@ -127,6 +144,26 @@ namespace Cryville.Crtr {
}
if (rc.PropSrcs != null) ChartPlayer.etor.ContextCascadeDiscard();
}
float _rtime;
readonly PropSrc _rtimeSrc;
public void MatchAnimation(AnimationSpan span, float rtime, RuntimeSkinContext ctx) {
ChartPlayer.etor.ContextSkinContainer = this;
ChartPlayer.etor.ContextSelfValue = _rtimeSrc;
MatchAnimationInternal(span, rtime, ctx);
ChartPlayer.etor.ContextSelfValue = null;
ChartPlayer.etor.ContextSkinContainer = null;
}
void MatchAnimationInternal(AnimationSpan span, float rtime, RuntimeSkinContext ctx) {
_rtime = rtime;
_rtimeSrc.Invalidate();
foreach (var p in span.properties) {
p.Key.ExecuteDynamic(_group, ctx, p.Value, Variables, 0);
}
foreach (var s in span.spans) {
if (rtime < s.Key.Behind || rtime >= s.Key.Ahead) continue;
MatchAnimationInternal(s.Value, (rtime - s.Key.Behind) / (s.Key.Ahead - s.Key.Behind), ctx);
}
}
}
public class SkinContext {
public Transform Transform { get; private set; }
@@ -162,4 +199,25 @@ namespace Cryville.Crtr {
}
}
}
public interface ISkinnableGroup {
string TypeName { get; }
SkinContext SkinContext { get; }
int OpenedAnchorName { get; }
bool TryGetAnchorsByName(int name, out IReadOnlyCollection<Anchor> result);
void RegisterAnchor(int name);
void PushAnchorEvent(double time, int name);
}
public class SkinVariable {
float _value;
public PropOp Op { get; private set; }
public PropSrc Src { get; private set; }
public SkinVariable() {
Op = new PropOp.Float(Set);
Src = new PropSrc.Float(() => _value);
}
void Set(float value) {
_value = value;
Src.Invalidate();
}
}
}

View File

@@ -1,18 +1,24 @@
using Cryville.Common;
using Cryville.Common.Pdt;
using Cryville.Crtr.Components;
using Cryville.Common.Pdt;
using System;
using System.Collections.Generic;
using System.Reflection;
namespace Cryville.Crtr {
public class SkinInterpreter : PdtInterpreter {
public SkinInterpreter(string src, Binder binder) : base(src, typeof(PdtSkin), binder) { }
public SkinInterpreter(string src, Binder binder) : base(src, binder) { }
readonly List<SkinSelector> s = new List<SkinSelector>();
readonly HashSet<string> a = new HashSet<string>();
readonly List<string> k = new List<string>(2);
protected override object InterpretKey(Type type) {
if (typeof(SkinElement).IsAssignableFrom(type))
return InterpretSkinElementKey();
else if (typeof(AnimationSpan).IsAssignableFrom(type))
return InterpretAnimationSpanKey();
else
return base.InterpretKey(type);
}
object InterpretSkinElementKey() {
s.Clear(); a.Clear(); k.Clear();
bool invalidKeyFlag = false, compKeyFlag = false;
while (true) {
@@ -50,39 +56,11 @@ namespace Cryville.Crtr {
case ';':
case ':':
if (invalidKeyFlag) throw new FormatException("Invalid key format");
if (a.Contains("has")) {
if (k.Count != 1) throw new FormatException("Invalid anchor name");
return new SkinPropertyKey.CreateAnchor {
Name = IdentifierManager.SharedInstance.Request(k[0])
};
}
else if (a.Contains("at")) {
if (k.Count != 1) throw new FormatException("Invalid anchor name");
return new SkinPropertyKey.SetAnchor {
Name = IdentifierManager.SharedInstance.Request(k[0])
};
}
switch (k.Count) {
case 1:
if (compKeyFlag) return new SkinPropertyKey.CreateComponent {
Component = GetComponentByName(k[0])
};
else return new SkinPropertyKey.SetProperty {
Component = typeof(TransformInterface),
Name = IdentifierManager.SharedInstance.Request(k[0])
};
case 2:
return new SkinPropertyKey.SetProperty {
Component = GetComponentByName(k[0]),
Name = IdentifierManager.SharedInstance.Request(k[1])
};
default:
throw new FormatException("Unknown error"); // Unreachable
}
return SkinPropertyKey.Construct(a, k, compKeyFlag);
case '{':
return new SkinSelectors(s, a);
case '}':
return null;
throw new FormatException("Invalid token");
case '*':
GetChar();
compKeyFlag = true;
@@ -100,10 +78,45 @@ namespace Cryville.Crtr {
if (Position == pp) throw new FormatException("Invalid selector or key format");
}
}
static Type GetComponentByName(string name) {
Type result;
if (GenericResources.Components.TryGetValue(name, out result)) return result;
throw new ArgumentException(string.Format("Component type \"{0}\" not found", name));
object InterpretAnimationSpanKey() {
if ((ct & 0x0040) != 0 || cc == ',') {
float start = 0, end = 1;
if (cc != ',') {
start = float.Parse(GetNumber());
ws(); if (cc != ',') throw new FormatException("Invalid span format");
}
GetChar(); ws();
if (cc != '{') end = float.Parse(GetNumber());
ws();
if (cc != '{') throw new FormatException("Invalid span format");
return new Clip(start, end);
}
a.Clear(); k.Clear();
while (true) {
int pp = Position;
switch (cc) {
case '.':
GetChar();
if (k.Count != 1)
throw new FormatException("Invalid key format");
k.Add(GetIdentifier());
break;
case ';':
case ':':
return SkinPropertyKey.Construct(a, k, false);
case '{':
throw new FormatException("Invalid token");
case '}':
throw new FormatException("Invalid token");
default:
if (k.Count != 0)
throw new FormatException("Invalid key format");
k.Add(GetIdentifier());
break;
}
ws();
if (Position == pp) throw new FormatException("Invalid selector or key format");
}
}
}
}

View File

@@ -1,42 +1,90 @@
using Cryville.Common;
using Cryville.Common.Pdt;
using Cryville.Crtr.Components;
using Cryville.Crtr.Event;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace Cryville.Crtr {
public abstract class SkinPropertyKey {
public static SkinPropertyKey Construct(HashSet<string> a, IReadOnlyList<string> k, bool compKeyFlag) {
if (a.Remove("has")) {
if (k.Count != 1) throw new FormatException("Invalid anchor name");
return new CreateAnchor(a, IdentifierManager.SharedInstance.Request(k[0]));
}
else if (a.Remove("at")) {
if (k.Count != 1) throw new FormatException("Invalid anchor name");
return new SetAnchor(a, IdentifierManager.SharedInstance.Request(k[0]));
}
else if (a.Remove("emit")) {
if (k.Count != 1) throw new FormatException("Invalid effect name");
return new EmitEffect(a, IdentifierManager.SharedInstance.Request(k[0]));
}
else if (a.Remove("emit_self")) {
if (k.Count != 1) throw new FormatException("Invalid effect name");
return new EmitEffect(a, IdentifierManager.SharedInstance.Request(k[0]), true);
}
else if (a.Remove("var")) {
if (k.Count != 1) throw new FormatException("Invalid variable name");
return new SetVariable(a, IdentifierManager.SharedInstance.Request(k[0]));
}
switch (k.Count) {
case 1:
if (compKeyFlag) return new CreateComponent(a, GetComponentByName(k[0]));
else return new SetProperty(a, typeof(TransformInterface), IdentifierManager.SharedInstance.Request(k[0]));
case 2:
return new SetProperty(a, GetComponentByName(k[0]), IdentifierManager.SharedInstance.Request(k[1]));
default:
throw new FormatException("Unknown error");
}
static Type GetComponentByName(string name) {
Type result;
if (GenericResources.Components.TryGetValue(name, out result)) return result;
throw new ArgumentException(string.Format("Component type \"{0}\" not found", name));
}
}
public readonly HashSet<string> annotations;
public SkinPropertyKey(IEnumerable<string> a) {
annotations = a.ToHashSet();
}
public abstract override string ToString();
public abstract bool IsValueRequired { get; }
public abstract void ExecuteStatic(ContainerState state, RuntimeSkinContext ctx, PdtExpression exp);
public abstract void ExecuteDynamic(ContainerState state, RuntimeSkinContext ctx, PdtExpression exp);
public abstract void ExecuteStatic(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, Dictionary<int, SkinVariable> vars);
public abstract void ExecuteDynamic(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, Dictionary<int, SkinVariable> vars, int dl);
public class CreateComponent : SkinPropertyKey {
public Type Component { get; set; }
public Type Component { get; private set; }
public CreateComponent(IEnumerable<string> a, Type component) : base(a) {
Component = component;
}
public override string ToString() {
return string.Format("*{0}", Component.Name);
}
public override bool IsValueRequired { get { return false; } }
public override void ExecuteStatic(ContainerState state, RuntimeSkinContext ctx, PdtExpression exp) {
public override void ExecuteStatic(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, Dictionary<int, SkinVariable> vars) {
ctx.WriteTransform.gameObject.AddComponent(Component);
}
public override void ExecuteDynamic(ContainerState state, RuntimeSkinContext ctx, PdtExpression exp) {
public override void ExecuteDynamic(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, Dictionary<int, SkinVariable> vars, int dl) {
throw new InvalidOperationException("Component creation in dynamic context is not allowed");
}
}
public class SetProperty : SkinPropertyKey {
public Type Component { get; set; }
public int Name { get; set; }
public Type Component { get; private set; }
public int Name { get; private set; }
public SetProperty(IEnumerable<string> a, Type component, int name) : base(a) {
Component = component;
Name = name;
}
public override string ToString() {
return string.Format("{0}.{1}", Component.Name, IdentifierManager.SharedInstance.Retrieve(Name));
}
public override bool IsValueRequired { get { return true; } }
public override void ExecuteStatic(ContainerState state, RuntimeSkinContext ctx, PdtExpression exp) {
public override void ExecuteStatic(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, Dictionary<int, SkinVariable> vars) {
Execute(ctx, GetPropOp(ctx.WriteTransform).Operator, exp);
}
public override void ExecuteDynamic(ContainerState state, RuntimeSkinContext ctx, PdtExpression exp) {
public override void ExecuteDynamic(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, Dictionary<int, SkinVariable> vars, int dl) {
var prop = GetPropOp(ctx.WriteTransform);
if (state.CloneType > prop.UpdateCloneType) return;
if (dl > prop.UpdateDynamicLevel) return;
Execute(ctx, prop.Operator, exp);
}
void Execute(RuntimeSkinContext ctx, PdtOperator op, PdtExpression exp) {
@@ -62,39 +110,88 @@ namespace Cryville.Crtr {
}
}
public class CreateAnchor : SkinPropertyKey {
public int Name { get; set; }
public int Name { get; private set; }
public CreateAnchor(IEnumerable<string> a, int name) : base(a) {
Name = name;
}
public override string ToString() {
return string.Format("@has {0}", IdentifierManager.SharedInstance.Retrieve(Name));
}
public override bool IsValueRequired { get { return false; } }
public override void ExecuteStatic(ContainerState state, RuntimeSkinContext ctx, PdtExpression exp) {
state.Handler.RegisterAnchor(Name, true);
public override void ExecuteStatic(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, Dictionary<int, SkinVariable> vars) {
group.RegisterAnchor(Name);
}
public override void ExecuteDynamic(ContainerState state, RuntimeSkinContext ctx, PdtExpression exp) {
public override void ExecuteDynamic(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, Dictionary<int, SkinVariable> vars, int dl) {
throw new InvalidOperationException("Anchor creation in dynamic context is not allowed");
}
}
public class SetAnchor : SkinPropertyKey {
public int Name { get; set; }
public SetAnchor() {
public int Name { get; private set; }
public SetAnchor(IEnumerable<string> a, int name) : base(a) {
Name = name;
_timeOp = new PropOp.Float(v => _time = v);
}
public override string ToString() {
return string.Format("@at {0}", IdentifierManager.SharedInstance.Retrieve(Name));
}
public override bool IsValueRequired { get { return true; } }
public override void ExecuteStatic(ContainerState state, RuntimeSkinContext ctx, PdtExpression exp) {
public override void ExecuteStatic(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, Dictionary<int, SkinVariable> vars) {
throw new InvalidOperationException("Setting anchor in static context is not allowed");
}
float _time;
readonly PropOp _timeOp;
public override void ExecuteDynamic(ContainerState state, RuntimeSkinContext ctx, PdtExpression exp) {
if (state.CloneType > 1) return;
public override void ExecuteDynamic(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, Dictionary<int, SkinVariable> vars, int dl) {
if (dl > 0) return;
var psrcs = ctx.ReadContext.PropSrcs;
if (psrcs != null) ChartPlayer.etor.ContextCascadeInsert(psrcs);
ChartPlayer.etor.Evaluate(_timeOp, exp);
if (psrcs != null) ChartPlayer.etor.ContextCascadeDiscard();
state.Handler.PushAnchorEvent(_time, Name);
group.PushAnchorEvent(_time, Name);
}
}
public class EmitEffect : SkinPropertyKey {
public int Name { get; private set; }
public bool IsSelf { get; private set; }
public EmitEffect(IEnumerable<string> a, int name, bool isSelf = false) : base(a) {
Name = name;
IsSelf = isSelf;
_op = new PropOp.Float(v => _index = v);
}
public override string ToString() {
return string.Format(IsSelf ? "@emit_self {0}" : "@emit {0}", IdentifierManager.SharedInstance.Retrieve(Name));
}
public override bool IsValueRequired { get { return true; } }
public override void ExecuteStatic(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, Dictionary<int, SkinVariable> vars) {
throw new InvalidOperationException("Emitting effect in static context is not allowed");
}
float _index;
readonly PropOp _op;
public override void ExecuteDynamic(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, Dictionary<int, SkinVariable> vars, int dl) {
ChartPlayer.etor.Evaluate(_op, exp);
if (IsSelf) ChartPlayer.effectManager.EmitSelf(Name, _index, ctx.WriteTransform);
else ChartPlayer.effectManager.Emit(Name, _index);
}
}
public class SetVariable : SkinPropertyKey {
public int Name { get; private set; }
public SetVariable(IEnumerable<string> a, int name) : base(a) {
Name = name;
}
public override string ToString() {
return string.Format("@var {0}", IdentifierManager.SharedInstance.Retrieve(Name));
}
public override bool IsValueRequired { get { return true; } }
public override void ExecuteStatic(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, Dictionary<int, SkinVariable> vars) {
SkinVariable v;
if (!vars.TryGetValue(Name, out v))
vars.Add(Name, v = new SkinVariable());
ChartPlayer.etor.Evaluate(v.Op, exp);
}
public override void ExecuteDynamic(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, Dictionary<int, SkinVariable> vars, int dl) {
SkinVariable v;
if (!vars.TryGetValue(Name, out v))
throw new InvalidOperationException(string.Format("Variable \"{0}\" not defined", IdentifierManager.SharedInstance.Retrieve(Name)));
ChartPlayer.etor.Evaluate(v.Op, exp);
}
}
}

View File

@@ -1,7 +1,6 @@
using Cryville.Common;
using Cryville.Common.Pdt;
using Cryville.Crtr.Components;
using Cryville.Crtr.Event;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -37,21 +36,21 @@ namespace Cryville.Crtr {
selectors[i].Optimize(etor);
}
}
public IEnumerable<SkinContext> MatchStatic(ContainerState h, SkinContext ctx) {
public IEnumerable<SkinContext> MatchStatic(ISkinnableGroup g, SkinContext ctx) {
IEnumerable<SkinContext> result = new SkinContext[] { ctx };
foreach (var s in selectors) {
result = result.SelectMany(l => s.MatchStatic(h, l));
result = result.SelectMany(l => s.MatchStatic(g, l));
}
return result;
}
public bool IsUpdatable(ContainerState h) {
public bool IsUpdatable(ISkinnableGroup g, int dl) {
foreach (var s in selectors)
if (!s.IsUpdatable(h)) return false;
if (!s.IsUpdatable(g, dl)) return false;
return true;
}
public SkinContext MatchDynamic(ContainerState h, SkinContext ctx) {
public SkinContext MatchDynamic(ISkinnableGroup g, SkinContext ctx) {
foreach (var s in selectors) {
ctx = s.MatchDynamic(h, ctx);
ctx = s.MatchDynamic(g, ctx);
if (ctx == null) return null;
}
return ctx;
@@ -63,16 +62,16 @@ namespace Cryville.Crtr {
public abstract override string ToString();
public virtual void Optimize(PdtEvaluatorBase etor) { }
public virtual IEnumerable<SkinContext> MatchStatic(ContainerState h, SkinContext c) { throw new SelectorNotAvailableException(); }
public virtual SkinContext MatchDynamic(ContainerState h, SkinContext c) { throw new SelectorNotAvailableException(); }
public virtual bool IsUpdatable(ContainerState h) {
public virtual IEnumerable<SkinContext> MatchStatic(ISkinnableGroup g, SkinContext c) { throw new SelectorNotAvailableException(); }
public virtual SkinContext MatchDynamic(ISkinnableGroup g, SkinContext c) { throw new SelectorNotAvailableException(); }
public virtual bool IsUpdatable(ISkinnableGroup g, int dl) {
return true;
}
public class CreateObject : SkinSelector {
public CreateObject() { }
public override string ToString() { return "$"; }
public override IEnumerable<SkinContext> MatchStatic(ContainerState h, SkinContext c) {
public override IEnumerable<SkinContext> MatchStatic(ISkinnableGroup g, SkinContext c) {
var obj = new GameObject("__obj__");
obj.transform.SetParent(c.Transform, false);
obj.AddComponent<TransformInterface>();
@@ -86,9 +85,9 @@ namespace Cryville.Crtr {
}
public override string ToString() { return string.Format(".{0}", IdentifierManager.SharedInstance.Retrieve(Name)); }
public override IEnumerable<SkinContext> MatchStatic(ContainerState h, SkinContext c) {
List<CAnchor> anchors;
if (h.Handler.Anchors.TryGetValue(Name, out anchors)) {
public override IEnumerable<SkinContext> MatchStatic(ISkinnableGroup g, SkinContext c) {
IReadOnlyCollection<CAnchor> anchors;
if (g.TryGetAnchorsByName(Name, out anchors)) {
return anchors.Select(a => a.SkinContext);
}
else return Enumerable.Empty<SkinContext>();
@@ -101,11 +100,11 @@ namespace Cryville.Crtr {
}
public override string ToString() { return string.Format("..{0}", IdentifierManager.SharedInstance.Retrieve(Name)); }
public override SkinContext MatchDynamic(ContainerState h, SkinContext c) {
return h.Handler.OpenedAnchor != null && h.Handler.OpenedAnchor.Name == Name ? c : null;
public override SkinContext MatchDynamic(ISkinnableGroup g, SkinContext c) {
return g.OpenedAnchorName == Name ? c : null;
}
public override bool IsUpdatable(ContainerState h) {
return h.CloneType >= 2;
public override bool IsUpdatable(ISkinnableGroup g, int dl) {
return dl >= 1;
}
}
public class Property : SkinSelector {
@@ -121,12 +120,12 @@ namespace Cryville.Crtr {
public override void Optimize(PdtEvaluatorBase etor) {
etor.Optimize(_exp);
}
public override IEnumerable<SkinContext> MatchStatic(ContainerState h, SkinContext c) {
public override IEnumerable<SkinContext> MatchStatic(ISkinnableGroup g, SkinContext c) {
var result = Match(c);
if (result != null) return new SkinContext[] { result };
else return Enumerable.Empty<SkinContext>();
}
public override SkinContext MatchDynamic(ContainerState h, SkinContext c) {
public override SkinContext MatchDynamic(ISkinnableGroup g, SkinContext c) {
return Match(c);
}
public SkinContext Match(SkinContext a) {
@@ -148,8 +147,8 @@ namespace Cryville.Crtr {
public ElementType(string type) { _type = type; }
public override string ToString() { return _type; }
public override IEnumerable<SkinContext> MatchStatic(ContainerState h, SkinContext c) {
return h.Handler.TypeName == _type ? new SkinContext[] { c } : Enumerable.Empty<SkinContext>();
public override IEnumerable<SkinContext> MatchStatic(ISkinnableGroup g, SkinContext c) {
return g.TypeName == _type ? new SkinContext[] { c } : Enumerable.Empty<SkinContext>();
}
}
}

View File

@@ -61,10 +61,9 @@ namespace Cryville.Crtr {
return new Vector2(Texture.width, Texture.height);
}
}
public void Init() {
if (Texture == null)
throw new InvalidOperationException("Missing texture");
public SpriteFrame(Texture2D tex) {
if (tex == null) throw new ArgumentNullException("tex");
Texture = tex;
m_frame = new Rect(Vector2.zero, Size);
var w = m_frame.width;
var h = m_frame.height;
@@ -75,10 +74,5 @@ namespace Cryville.Crtr {
if (m_rotated) UV = new Rect(x, y, tw, -th);
else UV = new Rect(x, y, tw, -th);
}
public SpriteFrame() { }
public SpriteFrame(Texture2D tex) {
Texture = tex;
}
}
}

View File

@@ -16,7 +16,7 @@ namespace Cryville.Crtr {
public override void Init() {
base.Init();
sgos = gogroup.GetComponentsInChildren<SectionalGameObject>();
sgos = RootTransform.GetComponentsInChildren<SectionalGameObject>();
}
SectionalGameObject[] sgos;
Vector3 bpos; Quaternion brot;
@@ -27,13 +27,13 @@ namespace Cryville.Crtr {
TransformAwake(s);
}
}
public override void StartPreGraphicalUpdate(ContainerState s) {
protected override void StartPreGraphicalUpdate(ContainerState s) {
base.StartPreGraphicalUpdate(s);
TransformAwake(s);
}
public override void StartGraphicalUpdate(ContainerState s) {
protected override void StartGraphicalUpdate(ContainerState s) {
base.StartGraphicalUpdate(s);
if (gogroup) {
if (RootTransform) {
TransformAwake(s);
var p = GetCurrentWorldPoint();
foreach (var i in sgos) {
@@ -82,7 +82,7 @@ namespace Cryville.Crtr {
ptime = s.Time;
if (!gogroup || s.CloneType == 3) return;
if (!RootTransform || s.CloneType == 3) return;
var p = GetCurrentWorldPoint();
foreach (var i in sgos)
i.AppendPoint(p, s.QuatDir);
@@ -105,7 +105,7 @@ namespace Cryville.Crtr {
spos = bpos - GetCurrentWorldPoint();
}
public override void EndGraphicalUpdate(ContainerState s) {
protected override void EndGraphicalUpdate(ContainerState s) {
base.EndGraphicalUpdate(s);
EndUpdatePosition(s);
var p = GetCurrentWorldPoint();

View File

@@ -15,6 +15,7 @@ using System.Diagnostics.CodeAnalysis;
[assembly: SuppressMessage("Style", "IDE0016")]
[assembly: SuppressMessage("Style", "IDE0029")]
[assembly: SuppressMessage("Style", "IDE0031")]
[assembly: SuppressMessage("Style", "IDE0270")]
[assembly: SuppressMessage("Style", "IDE1005")]
// Null compound assignment not supported

Binary file not shown.

View File

@@ -34,23 +34,25 @@ namespace System.Text.Formatting {
}
// Iteration 1: Split by semicolon
int specifierPositiveEnd = IndexOfSectionSeparator(specifier);
int specifierNegativeStart = 0, specifierNegativeEnd, specifierZeroStart = 0;
int specifierNegativeStart = 0, specifierNegativeEnd, specifierZeroStart = 0, specifierZeroEnd;
if (specifierPositiveEnd == -1) {
specifierPositiveEnd = specifierNegativeEnd = specifier.Length;
specifierPositiveEnd = specifierNegativeEnd = specifierZeroEnd = specifier.Length;
}
else {
specifierNegativeStart = specifierPositiveEnd + 1;
specifierNegativeEnd = IndexOfSectionSeparator(specifier, specifierNegativeStart);
if (specifierNegativeEnd == -1) {
specifierNegativeEnd = specifier.Length;
specifierZeroEnd = specifierPositiveEnd;
}
else {
specifierZeroStart = specifierNegativeEnd + 1;
specifierZeroEnd = specifier.Length;
}
}
// Special: Handle zero
if (IsZero(ref number)) {
FormatCustomFormatString(formatter, ref number, null, specifier, specifierZeroStart, specifier.Length, culture);
FormatCustomFormatString(formatter, ref number, null, specifier, specifierZeroStart, specifierZeroEnd, culture);
return;
}
// Iteration 2: Divide and round number
@@ -58,7 +60,7 @@ namespace System.Text.Formatting {
if (number.Sign == 0) ApplyDivisionAndPrecision(ref number, specifier, 0, specifierPositiveEnd);
else ApplyDivisionAndPrecision(ref number, specifier, specifierNegativeStart, specifierNegativeEnd);
// Iteration 3: Count; Iteration 4: Format
if (IsZero(ref number)) FormatCustomFormatString(formatter, ref number, null, specifier, specifierZeroStart, specifier.Length, culture);
if (IsZero(ref number)) FormatCustomFormatString(formatter, ref number, null, specifier, specifierZeroStart, specifierZeroEnd, culture);
else if (number.Sign == 0) FormatCustomFormatString(formatter, ref number, originalScale, specifier, 0, specifierPositiveEnd, culture);
else {
if (specifierNegativeStart == 0) formatter.Append(culture.NegativeSign);

View File

@@ -400,7 +400,7 @@ namespace System.Text.Formatting {
var segmentsLeft = false;
var prevArgIndex = 0;
do {
CheckCapacity((int)(end - curr));
CheckCapacity((int)(end - curr) + 1);
fixed (char* bufferPtr = &buffer[currentCount])
segmentsLeft = AppendSegment(ref curr, end, bufferPtr, ref prevArgIndex, ref args);
}
@@ -410,8 +410,16 @@ namespace System.Text.Formatting {
[MethodImpl(MethodImplOptions.AggressiveInlining)]
void CheckCapacity (int count) {
if (currentCount + count > buffer.Length)
Array.Resize(ref buffer, buffer.Length * 2);
int newCount = currentCount + count;
if (newCount > buffer.Length) {
int newCapacity = buffer.Length * 2;
if (newCapacity < newCount) newCapacity = newCount;
char[] newBuffer = new char[newCapacity];
fixed (void* nptr = newBuffer, ptr = buffer) {
Unsafe.CopyBlock(nptr, ptr, (uint)(currentCount * sizeof(char)));
}
buffer = newBuffer;
}
}
bool AppendSegment<T>(ref char* currRef, char* end, char* dest, ref int prevArgIndex, ref T args) where T : IArgSet {

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 9bd2dd8289f72d5479fc93154ddaf762
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,74 @@
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
Shader "Sprites/Additive"
{
Properties
{
[PerRendererData] _MainTex("Sprite Texture", 2D) = "white" {}
_Color("Tint", Color) = (1,1,1,1)
[MaterialToggle] PixelSnap("Pixel snap", Float) = 0
}
SubShader
{
Tags
{
"Queue" = "Transparent"
"IgnoreProjector" = "True"
"RenderType" = "Transparent"
"PreviewType" = "Plane"
"CanUseSpriteAtlas" = "True"
}
Cull Off
Lighting Off
ZWrite Off
Fog { Mode Off }
Blend SrcAlpha One
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile DUMMY PIXELSNAP_ON
#include "UnityCG.cginc"
struct appdata_t {
float4 vertex : POSITION;
float4 color : COLOR;
float2 texcoord : TEXCOORD0;
};
struct v2f {
float4 vertex : SV_POSITION;
fixed4 color : COLOR;
half2 texcoord : TEXCOORD0;
};
fixed4 _Color;
v2f vert(appdata_t IN) {
v2f OUT;
OUT.vertex = UnityObjectToClipPos(IN.vertex);
OUT.texcoord = IN.texcoord;
OUT.color = IN.color * _Color;
#ifdef PIXELSNAP_ON
OUT.vertex = UnityPixelSnap(OUT.vertex);
#endif
return OUT;
}
sampler2D _MainTex;
fixed4 frag(v2f IN) : SV_Target
{
fixed4 c = tex2D(_MainTex, IN.texcoord) * IN.color;
c.rgb *= c.a;
return c;
}
ENDCG
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 566d6ad96aab9ea4599b9595dc35f01d
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
preprocessorOverride: 0
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -22,14 +22,14 @@ body {
cursor: pointer;
}
.tgbtn-active {
background-color: lightblue;
}
.tgbtn:hover {
background-color: lightgray;
}
.tgbtn-active, .tgbtn-active:hover {
background-color: lightblue;
}
#toolbar .tgbtn {
min-width: 64px;
height: 100%;
@@ -45,29 +45,50 @@ body {
overflow: auto;
}
.t-list {
.t-list-container {
position: absolute;
max-width: 100vw;
max-height: 100vh;
overflow: auto;
background-color: floralwhite;
box-sizing: border-box;
border: solid 1px gray;
border-radius: 4px;
}
.t-list-composed {
max-width: 100vw;
max-height: 100vh;
}
.t-list {
padding: 2px;
margin: 0;
list-style: none;
}
.t-li {
list-style: none;
padding: 0 4px;
margin: 1px;
cursor: pointer;
break-before: avoid;
}
.t-li:hover {
background-color: lightblue;
}
.t-li-cat {
padding: 0 4px;
margin: 1px;
border-bottom: solid 1px dimgray;
color: dimgray;
font-size: small;
}
.t-li-cat-2 {
border-bottom-style: dashed;
font-size: x-small;
}
input {
border: none;
font-family: sans-serif;
@@ -116,17 +137,6 @@ input {
margin: 0 2px;
}
.btn:only-child {
height: 16px;
}
.btn.t-inline:only-child {
width: 16px;
}
.t-statement > .btn {
}
.t-node:hover > .btn {
transition: 0.25s;
height: 16px;
@@ -140,6 +150,14 @@ input {
border: solid 1px green;
}
.btn-add:only-child {
height: 16px;
}
.btn-add.t-inline:only-child {
width: 16px;
}
.mode-hide-add .btn-add {
display: none;
}
@@ -158,15 +176,39 @@ input {
.t-exp {
border-top: solid 1px gray;
vertical-align: top;
}
.t-exp.t-inline {
padding: 2px 4px;
margin: 0 2px;
padding: 2px 1px;
}
.t-exp .t-inline {
margin: 0 0 2px 0;
}
.mode-hide-delete .t-exp .t-inline {
margin-bottom: 0;
}
.mode-hide-delete .t-exp.t-inline {
padding-bottom: 0;
}
.t-exp > .t-statement {
margin: 0;
border-left: solid 1px orangered;
padding: 0 2px;
}
.t-exp:hover {
border-top: solid 3px gray;
}
.t-exp > .btn-add:not(:only-child) {
display: none;
}
.t-input {
display: inline-block;
@@ -226,7 +268,8 @@ input {
border-left-width: 5px;
}
.mode-sort .t-statement.t-inline {
.mode-sort .t-statement.t-inline,
.mode-sort .t-exp > .t-statement {
border-color: lightgray;
}
@@ -257,22 +300,26 @@ input {
background-color: black;
color: white;
}
.t-list {
.t-list-container {
background-color: darkslategray;
}
.t-li:hover {
background-color: darkblue;
}
.t-li-cat {
border-bottom-color: lightgray;
color: lightgray;
}
input {
background-color: black;
color: white;
}
.tgbtn-active {
background-color: darkslateblue;
}
.tgbtn:hover {
background-color: gray;
}
.tgbtn-active, .tgbtn-active:hover {
background-color: darkslateblue;
}
.t-internal {
background-color: dimgray;
}

View File

@@ -11,24 +11,26 @@ var cel;
var clist;
var blocklists = {
"block.element": ["statement.obj", "statement.select"],
"block.filter": ["statement.filter.type", "statement.filter.exp"],
"block.object": ["statement.comp", "statement.prop", "statement.filter"],
"block.element": ["statement.select", "statement.obj", "statement.comp", "statement.prop"],
"block.root": ["statement.select", "statement.define"],
"block.select": ["statement.select.type", "statement.select.exp"],
"block.select": ["statement.select.type", "statement.select.exp", "statement.select.anchor", "statement.select.atanchor"],
"block.exp.op.sep.vec": ["statement.exp.number"],
"block.exp.op.sep.arr": ["statement.exp.string"],
};
var ilid = 0;
var inputlists = {
"input.comp": ["image", "polysec", "rect", "scale3", "text"],
"input.comp": ["anim", "image", "polysec", "rect", "scale3", "text"],
"input.prop": [
"pos", "rot", "scale",
"image.fit", "image.frame", "image.opacity",
"polysec.body", "polysec.head", "polysec.shape", "polysec.tail", "polysec.transparent",
"rect.color",
"anim.delay", "anim.direction", "anim.duration", "anim.name", "anim.iteration",
"image.fit", "image.frame", "image.frames", "image.index", "image.shader",
"mesh.color", "mesh.opacity", "mesh.zindex",
"polysec.body", "polysec.head", "polysec.shape", "polysec.tail",
"scale3.border",
"sprite.bound", "sprite.pivot", "sprite.scale", "sprite.transparent", "sprite.ui", "sprite.zindex",
"text.frames", "text.opacity", "text.size", "text.spacing", "text.value",
"sec.part", "sec.partial",
"sprite.bound", "sprite.pivot", "sprite.scale", "sprite.ui",
"text.frames", "text.size", "text.spacing", "text.value",
],
"input.type": ["chart", "group", "track", "note"],
};
@@ -36,15 +38,103 @@ var inputlists = {
var statementlists = {
"statement.comp": ["input.comp"],
"statement.define": ["input.ident", "exp"],
"statement.filter": ["block.filter", "block.object"],
"statement.filter.exp": ["exp"],
"statement.filter.type": ["input.type"],
"statement.obj": ["block.object"],
"statement.exp.cast.vector2number": ["exp.vector"],
"statement.exp.const.w": [],
"statement.exp.const.h": [],
"statement.exp.const.inf": [],
"statement.exp.const.null": [],
"statement.exp.const.true": [],
"statement.exp.const.false": [],
"statement.exp.literal.ident": ["input.ident"],
"statement.exp.literal.identforced": ["input.ident"],
"statement.exp.literal.number": ["input.number"],
"statement.exp.literal.string": ["input.string"],
"statement.exp.op.add": ["exp.number", "exp.number"],
"statement.exp.op.sub": ["exp.number", "exp.number"],
"statement.exp.op.mul": ["exp.number", "exp.number"],
"statement.exp.op.div": ["exp.number", "exp.number"],
"statement.exp.op.mod": ["exp.number", "exp.number"],
"statement.exp.op.add1": ["exp.number"],
"statement.exp.op.sub1": ["exp.number"],
"statement.exp.op.not": ["exp.number"],
"statement.exp.op.at": ["exp.number_or_vector", "exp.number"],
"statement.exp.op.lt": ["exp.number", "exp.number"],
"statement.exp.op.eq": ["exp.number", "exp.number"],
"statement.exp.op.gt": ["exp.number", "exp.number"],
"statement.exp.op.and": ["exp", "exp"],
"statement.exp.op.or": ["exp", "exp"],
"statement.exp.op.sep.vec": ["block.exp.op.sep.vec"],
"statement.exp.op.sep.arr": ["block.exp.op.sep.arr"],
"statement.exp.func.frame_seq": ["exp.string", "exp.number", "exp.number"],
"statement.exp.func.int": ["exp.number"],
"statement.exp.func.clamp": ["exp.number", "exp.number", "exp.number"],
"statement.exp.func.min": ["exp.number", "exp.number"],
"statement.exp.func.max": ["exp.number", "exp.number"],
"statement.exp.func.abs": ["exp.number"],
"statement.exp.func.interval": ["exp.number", "exp.number", "exp.number"],
"statement.exp.func.is": ["exp", "exp"],
"statement.exp.func.cubic_bezier": ["exp.number", "exp.number", "exp.number", "exp.number", "exp.number"],
"statement.exp.func.ease": ["exp.number"],
"statement.exp.func.ease_in": ["exp.number"],
"statement.exp.func.ease_out": ["exp.number"],
"statement.exp.func.ease_in_out": ["exp.number"],
"statement.exp.func.attack_timing": ["exp.number", "exp.number"],
"statement.exp.func.enter_timing": ["exp.number"],
"statement.exp.func.release_timing": ["exp.number", "exp.number"],
"statement.exp.func.leave_timing": ["exp.number"],
"statement.exp.func.contact_timing": ["exp.number", "exp.number"],
"statement.exp.func.screen_edge": ["exp.number"],
"statement.exp.func.anim": ["exp.number_or_vector", "exp.number_or_vector", "exp.number"],
"statement.exp.number": ["exp.number"],
"statement.exp.string": ["exp.string"],
"statement.obj": ["block.element"],
"statement.prop": ["input.prop", "exp"],
"statement.select": ["block.select", "block.element"],
"statement.select.exp": ["exp"],
"statement.select.anchor": ["input.identanchor"],
"statement.select.atanchor": ["input.identanchor"],
"statement.select.exp": ["exp.number"],
"statement.select.type": ["input.type"],
}
};
var explists = {
"exp": ["#exp.number", "#exp.vector", "#exp.string", "#exp.array", "#exp.identifier", "#exp.any"],
"exp.number_or_vector": ["#exp.number", "#exp.vector", "#exp.any"],
"exp.any": [
"statement.exp.literal.ident", "statement.exp.literal.identforced",
"statement.exp.op.and", "statement.exp.op.or"
],
"exp.array": [
"statement.exp.op.sep.arr",
"statement.exp.func.frame_seq",
"#exp.any"
],
"exp.identifier": [
"statement.exp.const.null",
"#exp.any"
],
"exp.number": [
"statement.exp.literal.number", "statement.exp.cast.vector2number",
"-exp.const", "statement.exp.const.w", "statement.exp.const.h", "statement.exp.const.inf", "statement.exp.const.true", "statement.exp.const.false",
"-exp.op", "statement.exp.op.add", "statement.exp.op.sub", "statement.exp.op.mul", "statement.exp.op.div", "statement.exp.op.mod",
"-", "statement.exp.op.add1", "statement.exp.op.sub1", "statement.exp.op.not",
"-", "statement.exp.op.at", "statement.exp.op.lt", "statement.exp.op.eq", "statement.exp.op.gt",
"-exp.func", "statement.exp.func.interval", "statement.exp.func.is",
"-exp.func.ctx", "statement.exp.func.int", "statement.exp.func.clamp", "statement.exp.func.min", "statement.exp.func.max", "statement.exp.func.abs",
"-exp.func.anim", "statement.exp.func.cubic_bezier", "statement.exp.func.ease", "statement.exp.func.ease_in", "statement.exp.func.ease_out", "statement.exp.func.ease_in_out",
"-exp.func.judge", "statement.exp.func.attack_timing", "statement.exp.func.enter_timing", "statement.exp.func.release_timing", "statement.exp.func.leave_timing", "statement.exp.func.contact_timing",
"#exp.any"
],
"exp.string": [
"statement.exp.literal.string",
"#exp.any"
],
"exp.vector": [
"statement.exp.op.sep.vec",
"statement.exp.func.screen_edge",
"statement.exp.func.anim",
"#exp.any"
],
};
window.onload = function () {
lang = navigator.language.replace("-", "_");
@@ -56,12 +146,12 @@ window.onload = function () {
app.find("tbr").replaceWith(function () {
return msg($(this).text());
});
addAddButton(tree).on("click", function (event) {
addAddButton(tree).on("click", function () {
if (clist) clist.remove();
});
tv.on("mousemove", null, null, onMouseMove);
$(".tgbtn").on("click", function (event) {
$(".tgbtn").on("click", function () {
var btn = $(this);
btn.toggleClass("tgbtn-active");
onToggleButtonClick(btn.attr("id"), btn.hasClass("tgbtn-active"));
@@ -95,7 +185,7 @@ function onAddButtonClick(event) {
function onAddExpButtonClick(event) {
cel = el = event.data;
generateAddExpList(event);
generateAddExpList(event, el.attr("key"));
}
function onAddButtonLiteralClick(event) {
@@ -123,14 +213,16 @@ var tblist = {
"tb-hide-add": "mode-hide-add",
"tb-hide-delete": "mode-hide-delete",
"tb-sort": "mode-sort",
}
};
function onToggleButtonClick(id, state) {
var cls = tblist[id];
if (state) tv.addClass(cls);
else tv.removeClass(cls);
if (cls == "mode-sort") {
var il = tv.find(".t-input");
var sl = tv.find(".t-statement").not(".t-inline");
var sl = tv.find(".t-statement").not(".t-inline").not(function () {
return $(this).parent().is(".t-exp");
});
if (state) {
il.each(function (i) {
$(il[i]).children("input").attr("disabled", "");
@@ -216,30 +308,49 @@ function generateAddList(event, items) {
popup(event, ul);
}
function generateAddExpList(event, items) {
function generateAddExpList(event, item) {
event.stopPropagation();
if (clist) clist.remove();
var ul = $("<ul></ul>").addClass("t-list t-exp-list");
for (var i in items) {
var item = items[i];
ul.append($("<li></li>").addClass("t-li").attr("key", item).text(msg("list." + item)).on("click", null, item, onAddItemClick));
}
(function addExpRecursive(it, depth) {
if (depth > 0) {
ul.append($("<li></li>").addClass("t-li-cat t-li-cat-" + depth.toString()).text(msg("list.category." + it)));
}
var items = explists[it];
for (var i in items) {
var item = items[i];
if (item[0] == "#") {
if (depth == 0) addExpRecursive(item.substring(1), 1);
}
else if (item == "-")
ul.append($("<li></li>").addClass("t-li-br"));
else if (item[0] == "-")
ul.append($("<li></li>").addClass("t-li-cat t-li-cat-" + (depth + 1).toString()).text(msg("list.category." + item.substring(1))));
else
ul.append($("<li></li>").addClass("t-li").attr("key", item).text(msg("list." + item)).on("click", null, item, onAddItemClick));
}
})(item, 0);
popup(event, ul);
}
function popup(event, ul) {
clist = ul;
app.append(ul);
clist = $("<div></div>").addClass("t-list-container").append(ul);
app.append(clist);
ul.css("column-count", Math.max(1, Math.min(
Math.floor(0.6 * window.innerWidth / clist.outerWidth()),
Math.ceil((clist.outerHeight() + 256) / window.innerHeight)
)));
var left = event.pageX;
if (left + ul.outerWidth() > window.innerWidth)
left = Math.max(0, left - ul.outerWidth());
if (left + clist.outerWidth() > window.innerWidth)
left = Math.max(0, left - clist.outerWidth());
var top = event.pageY;
if (top + ul.outerHeight() > window.innerHeight)
top = Math.max(0, top - ul.outerHeight());
ul.css({
if (top + clist.outerHeight() > window.innerHeight)
top = Math.max(0, top - clist.outerHeight());
clist.css({
"left": left,
"top": top
});
clist.addClass("t-list-composed");
}
function generateInputList(el, key) {
@@ -349,10 +460,11 @@ function createExp(key) {
}
function createInput(key, target) {
var el = $("<input />").attr({
"type": "text",
"placeholder": msg(key + ".default")
});
var el = $("<input />").attr("placeholder", msg(key + ".default"));
switch (key) {
case "input.number": el.attr("type", "number"); break;
default: el.attr("type", "text"); break;
}
var r = $("<span></span>").attr({
"key": key,
"target": target.index()

View File

@@ -1,12 +1,13 @@
<!DOCTYPE HTML>
<head>
<meta charset="utf-8" />
<title>Skin Editor - Cosmo Resona</title>
<link type="text/css" rel="stylesheet" href="app.css"/>
<script type="text/javascript" src="jquery-3.6.0.min.js"></script>
<script type="text/javascript" src="stretchy.min.js"></script>
<script type="text/javascript" src="array_util.js"></script>
<script type="text/javascript" src="app.js"></script>
<script type="text/javascript" src="messages/en_US.js"></script>
<script type="text/javascript" src="messages/en_US.js" charset="UTF-8"></script>
<script type="text/javascript" src="messages/zh_CN.js" charset="UTF-8"></script>
</head>
<body>

View File

@@ -1,71 +1,183 @@
messages["en_US"] = {
"block.filter": "If {}",
"block.select": "Select {}",
"input.comp.default": "component",
"input.comp.image": "image sprite",
"input.comp.polysec": "polygon sectional mesh",
"input.comp.rect": "colored rectangle",
"input.comp.scale3": "scale3 sprite",
"input.comp.text": "text",
"input.ident.default": "variable",
"input.prop.default": "property",
"input.prop.image.fit": "image sprite: scale mode",
"input.prop.image.frame": "image sprite: image name",
"input.prop.image.opacity": "image sprite: opacity",
"input.prop.polysec.body": "polygon sectional mesh: body image name",
"input.prop.polysec.head": "polygon sectional mesh: head image name",
"input.prop.polysec.shape": "polygon sectional mesh: section shape",
"input.prop.polysec.tail": "polygon sectional mesh: tail image name",
"input.prop.polysec.transparent": "polygon sectional mesh: transparent mode",
"input.prop.pos": "position",
"input.prop.rect.color": "colored rectangle: color",
"input.prop.rot": "rotation",
"input.prop.scale": "scale",
"input.prop.scale3.border": "scale3 sprite: unstretched area ratios",
"input.prop.sprite.bound": "sprite: secondary anchor position",
"input.prop.sprite.pivot": "sprite: anchor",
"input.prop.sprite.scale": "sprite: scale",
"input.prop.sprite.transparent": "sprite: transparent mode",
"input.prop.sprite.ui": "sprite: ui mode",
"input.prop.sprite.zindex": "sprite: layer order",
"input.prop.text.frames": "text: image mapping",
"input.prop.text.opacity": "text: opacity",
"input.prop.text.size": "text: font size",
"input.prop.text.spacing": "text: character spacing",
"input.prop.text.value": "text: content",
"input.type.chart": "chart",
"input.type.default": "element",
"input.type.group": "track group",
"input.type.note": "note",
"input.type.track": "track",
"list.statement.comp": "Attach a component",
"list.statement.define": "Define a variable",
"list.statement.filter": "Filter element",
"list.statement.filter.exp": "Filter expression",
"list.statement.filter.type": "Filter element type",
"list.statement.obj": "Create a container",
"list.statement.prop": "Set property",
"list.statement.select": "Select elements",
"list.statement.select.exp": "Filter expression",
"list.statement.select.type": "Filter element type",
"literal.block.filter": "If {statement.filter.exp} {statement.filter.type}",
"literal.block.select": "For each {statement.select.type?element} {statement.select.exp}",
"literal.statement.filter.exp": "{0}",
"literal.statement.filter.type": "it is a {0}",
"literal.statement.select.exp": "that {0}",
"literal.statement.select.type": "{0}",
"statement.comp": "with a {0}",
"statement.define": "Define {0} = {1}",
"statement.filter": "{0} {1}",
"statement.filter.exp": "it matches the expression {0}",
"statement.filter.type": "it is a {0}",
"statement.obj": "Create a container {0}",
"statement.prop": "Set its {0} to {1}",
"statement.select": "{0} {1}",
"statement.select.exp": "it matches the expression {0}",
"statement.select.type": "{0}",
"tool.debug": "Debug",
"tool.hideadd": "Hide Add",
"tool.hidedelete": "Hide Delete",
"tool.sort": "Sort",
};
"input.comp.anim": "animation",
"input.comp.default": "component",
"input.comp.image": "image sprite",
"input.comp.polysec": "polygon sectional mesh",
"input.comp.rect": "colored rectangle sprite",
"input.comp.scale3": "scale3 image sprite",
"input.comp.text": "text sprite",
"input.ident.default": "variable",
"input.identanchor.default": "anchor",
"input.number.default": "123",
"input.prop.anim.delay": "animation: start delay",
"input.prop.anim.direction": "animation: playback direction",
"input.prop.anim.duration": "animation: duration",
"input.prop.anim.name": "animation: name",
"input.prop.anim.iteration": "animation: iteration count",
"input.prop.default": "property",
"input.prop.image.fit": "image sprite: scale mode",
"input.prop.image.frame": "image sprite: frame name",
"input.prop.image.frames": "image sprite: list of frame names",
"input.prop.image.index": "image sprite: frame index",
"input.prop.image.shader": "image sprite: shader",
"input.prop.mesh.color": "mesh: color",
"input.prop.mesh.opacity": "mesh: opacity",
"input.prop.mesh.zindex": "mesh: layer order",
"input.prop.polysec.body": "polygon sectional mesh: body frame name",
"input.prop.polysec.head": "polygon sectional mesh: head frame name",
"input.prop.polysec.shape": "polygon sectional mesh: section shape",
"input.prop.polysec.tail": "polygon sectional mesh: tail frame name",
"input.prop.pos": "position",
"input.prop.rot": "rotation",
"input.prop.scale": "scale",
"input.prop.scale3.border": "scale3 image sprite: unstretched area ratios",
"input.prop.sec.part": "sectional mesh: current part",
"input.prop.sec.partial": "sectional mesh: partial mode",
"input.prop.sprite.bound": "sprite: secondary anchor position",
"input.prop.sprite.pivot": "sprite: anchor",
"input.prop.sprite.scale": "sprite: scale",
"input.prop.sprite.ui": "sprite: ui mode",
"input.prop.text.frames": "text sprite: frame mapping",
"input.prop.text.size": "text sprite: font size",
"input.prop.text.spacing": "text sprite: character spacing",
"input.prop.text.value": "text sprite: content",
"input.string.default": "string",
"input.type.chart": "chart",
"input.type.default": "element",
"input.type.group": "track group",
"input.type.note": "note",
"input.type.track": "track",
"list.category.exp.any": "Any",
"list.category.exp.array": "Array",
"list.category.exp.const": "Constants",
"list.category.exp.func": "Functions",
"list.category.exp.func.anim": "Animation Functions",
"list.category.exp.func.ctx": "Contextual Functions",
"list.category.exp.func.judge": "Judge Functions",
"list.category.exp.identifier": "Identifier",
"list.category.exp.number": "Number",
"list.category.exp.op": "Operators",
"list.category.exp.string": "String",
"list.category.exp.vector": "Vector",
"list.statement.comp": "Attach component",
"list.statement.define": "Define static variable",
"list.statement.exp.cast.vector2number": "From vector",
"list.statement.exp.const.false": "False",
"list.statement.exp.const.h": "Screen height",
"list.statement.exp.const.inf": "Infinity",
"list.statement.exp.const.null": "Null",
"list.statement.exp.const.true": "True",
"list.statement.exp.const.w": "Screen width",
"list.statement.exp.func.abs": "Absolute value",
"list.statement.exp.func.anim": "Animate value",
"list.statement.exp.func.attack_timing": "Attack in timing",
"list.statement.exp.func.clamp": "Clamp",
"list.statement.exp.func.contact_timing": "Contact timing",
"list.statement.exp.func.cubic_bezier": "Cubic Bézier curve",
"list.statement.exp.func.ease": "Ease",
"list.statement.exp.func.ease_in": "Ease in",
"list.statement.exp.func.ease_in_out": "Ease in out",
"list.statement.exp.func.ease_out": "Ease out",
"list.statement.exp.func.enter_timing": "Enter timing",
"list.statement.exp.func.frame_seq": "Frame sequence",
"list.statement.exp.func.int": "Round down",
"list.statement.exp.func.interval": "Interval",
"list.statement.exp.func.is": "Is equivalent",
"list.statement.exp.func.leave_timing": "Leave timing",
"list.statement.exp.func.max": "Maximum",
"list.statement.exp.func.min": "Minimum",
"list.statement.exp.func.release_timing": "Release in timing",
"list.statement.exp.func.screen_edge": "Screen edge",
"list.statement.exp.literal.ident": "Variable",
"list.statement.exp.literal.identforced": "Variable (forced)",
"list.statement.exp.literal.number": "Number",
"list.statement.exp.literal.string": "String",
"list.statement.exp.number": "Add element",
"list.statement.exp.string": "Add element",
"list.statement.exp.op.add": "a + b",
"list.statement.exp.op.add1": "+n",
"list.statement.exp.op.and": "p and q",
"list.statement.exp.op.at": "n-th element",
"list.statement.exp.op.div": "a ÷ b",
"list.statement.exp.op.eq": "a = b",
"list.statement.exp.op.gt": "a > b",
"list.statement.exp.op.lt": "a < b",
"list.statement.exp.op.mod": "a % b",
"list.statement.exp.op.mul": "a × b",
"list.statement.exp.op.not": "Not",
"list.statement.exp.op.or": "p or q",
"list.statement.exp.op.sep.arr": "Array",
"list.statement.exp.op.sep.vec": "Vector",
"list.statement.exp.op.sub": "a - b",
"list.statement.exp.op.sub1": "-n",
"list.statement.obj": "Create container",
"list.statement.prop": "Set property",
"list.statement.select": "Select elements",
"list.statement.select.anchor": "Select anchor",
"list.statement.select.atanchor": "Select at anchor",
"list.statement.select.exp": "Filter expression",
"list.statement.select.type": "Filter element type",
"statement.comp": "with a {0}",
"statement.define": "Define static {0} = {1}",
"statement.exp.cast.vector2number": "vector {0}",
"statement.exp.const.false": "false",
"statement.exp.const.h": "screen height",
"statement.exp.const.inf": "infinity",
"statement.exp.const.null": "null",
"statement.exp.const.true": "true",
"statement.exp.const.w": "screen width",
"statement.exp.func.abs": "absolute value of {0}",
"statement.exp.func.anim": "animate value from {0} to {1} with {2}",
"statement.exp.func.attack_timing": "attack in timing ({0}, {1})",
"statement.exp.func.clamp": "clamp {1} between {0} and {2}",
"statement.exp.func.contact_timing": "contact timing ({0}, {1})",
"statement.exp.func.cubic_bezier": "cubic Bézier curve defined by the control points ({0}, {1}) and ({2}, {3}) with {4}",
"statement.exp.func.ease": "ease with {0}",
"statement.exp.func.ease_in": "ease in with {0}",
"statement.exp.func.ease_in_out": "ease in out with {0}",
"statement.exp.func.ease_out": "ease out with {0}",
"statement.exp.func.enter_timing": "enter timing ({0}, +∞)",
"statement.exp.func.frame_seq": "frame sequence with prefix {0} from {1} to {2}",
"statement.exp.func.int": "round down {0}",
"statement.exp.func.interval": "interval between {0} and {1}",
"statement.exp.func.is": "{0} is equivalent to {1}",
"statement.exp.func.leave_timing": "leave timing (-∞, {0})",
"statement.exp.func.max": "maximum of {0} and {1}",
"statement.exp.func.min": "minimum of {0} and {1}",
"statement.exp.func.release_timing": "release in timing ({0}, {1})",
"statement.exp.func.screen_edge": "the screen edge #{0}",
"statement.exp.literal.ident": "{0}",
"statement.exp.literal.identforced": "{0} (forced)",
"statement.exp.literal.number": "{0}",
"statement.exp.literal.string": "{0}",
"statement.exp.number": "{0}",
"statement.exp.number_or_vector": "{0}",
"statement.exp.string": "{0}",
"statement.exp.op.add": "{0} + {1}",
"statement.exp.op.add1": "+{0}",
"statement.exp.op.and": "{0} and {1}",
"statement.exp.op.at": "the {1}th item of {0}",
"statement.exp.op.div": "{0} ÷ {1}",
"statement.exp.op.eq": "{0} = {1}",
"statement.exp.op.gt": "{0} > {1}",
"statement.exp.op.lt": "{0} < {1}",
"statement.exp.op.mod": "{0} % {1}",
"statement.exp.op.mul": "{0} × {1}",
"statement.exp.op.not": "not {0}",
"statement.exp.op.or": "{0} or {1}",
"statement.exp.op.sep.arr": "Array {0}",
"statement.exp.op.sep.vec": "Vector {0}",
"statement.exp.op.sub": "{0} - {1}",
"statement.exp.op.sub1": "-{0}",
"statement.obj": "Create a container {0}",
"statement.prop": "Set its {0} to {1}",
"statement.select": "Select {0} {1}",
"statement.select.anchor": "Select its anchor {0}",
"statement.select.atanchor": "Select at its anchor {0}",
"statement.select.exp": "If it matches the expression {0}",
"statement.select.type": "If it is a {0}",
"tool.debug": "Debug",
"tool.hideadd": "Hide Add",
"tool.hidedelete": "Hide Delete",
"tool.sort": "Sort",
};

View File

@@ -1,71 +1,183 @@
messages["zh_CN"] = {
"block.filter": "如果 {}",
"block.select": "选择 {}",
"input.comp.anim": "动画",
"input.comp.default": "组件",
"input.comp.image": "图片",
"input.comp.image": "图片图形",
"input.comp.polysec": "多边形截面网格",
"input.comp.rect": "纯色矩形",
"input.comp.scale3": "三段拉伸图片",
"input.comp.text": "文字",
"input.comp.rect": "纯色矩形图形",
"input.comp.scale3": "三段拉伸图片图形",
"input.comp.text": "文字图形",
"input.ident.default": "变量",
"input.identanchor.default": "锚点",
"input.number.default": "123",
"input.prop.anim.delay": "动画:起始延迟",
"input.prop.anim.direction": "动画:播放方向",
"input.prop.anim.duration": "动画:时长",
"input.prop.anim.name": "动画:名称",
"input.prop.anim.iteration": "动画:重复次数",
"input.prop.default": "属性",
"input.prop.image.fit": "图片:缩放模式",
"input.prop.image.frame": "图片:图片名",
"input.prop.image.opacity": "图片:不透明度",
"input.prop.image.fit": "图片图形:缩放模式",
"input.prop.image.frame": "图片图形:帧名称",
"input.prop.image.frames": "图片图形:帧名称列表",
"input.prop.image.index": "图片图形:帧索引",
"input.prop.image.shader": "图片图形:着色器",
"input.prop.mesh.color": "网格:颜色",
"input.prop.mesh.opacity": "网格:不透明度",
"input.prop.mesh.zindex": "网格:叠加次序",
"input.prop.polysec.body": "多边形截面网格:中部图片名",
"input.prop.polysec.head": "多边形截面网格:头部图片名",
"input.prop.polysec.shape": "多边形截面网格:截面形状",
"input.prop.polysec.tail": "多边形截面网格:尾部图片名",
"input.prop.polysec.transparent": "多边形截面网格:透明模式",
"input.prop.pos": "位置",
"input.prop.rect.color": "纯色矩形:颜色",
"input.prop.rot": "旋转",
"input.prop.scale": "缩放",
"input.prop.scale3.border": "三段拉伸图片:非拉伸区域占比",
"input.prop.sprite.bound": "图像:副锚点位置",
"input.prop.sprite.pivot": "图像:锚点",
"input.prop.sprite.scale": "图像:缩放",
"input.prop.sprite.transparent": "图像:透明模式",
"input.prop.sprite.ui": "图像:界面模式",
"input.prop.sprite.zindex": "图像:叠加次序",
"input.prop.text.frames": "文字:图片映射",
"input.prop.text.opacity": "文字:不透明度",
"input.prop.text.size": "文字:字体大小",
"input.prop.text.spacing": "文字:字符间距",
"input.prop.text.value": "文字:内容",
"input.prop.scale3.border": "三段拉伸图片图形:非拉伸区域占比",
"input.prop.sec.part": "截面网格:当前分段",
"input.prop.sec.partial": "截面网格:分段模式",
"input.prop.sprite.bound": "图形:副锚点位置",
"input.prop.sprite.pivot": "图形:锚点",
"input.prop.sprite.scale": "图形:缩放",
"input.prop.sprite.ui": "图形:界面模式",
"input.prop.text.frames": "文字图形:图片映射",
"input.prop.text.size": "文字图形:字体大小",
"input.prop.text.spacing": "文字图形:字符间距",
"input.prop.text.value": "文字图形:内容",
"input.string.default": "字符串",
"input.type.chart": "谱面",
"input.type.default": "元素",
"input.type.group": "轨道组",
"input.type.note": "按键",
"input.type.track": "轨道",
"list.category.exp.any": "任意",
"list.category.exp.array": "数组",
"list.category.exp.const": "常量",
"list.category.exp.func": "函数",
"list.category.exp.func.anim": "动画函数",
"list.category.exp.func.ctx": "环境函数",
"list.category.exp.func.judge": "判定函数",
"list.category.exp.identifier": "变量",
"list.category.exp.number": "数字",
"list.category.exp.op": "运算符",
"list.category.exp.string": "字符串",
"list.category.exp.vector": "向量",
"list.statement.comp": "附加组件",
"list.statement.define": "定义变量",
"list.statement.filter": "条件分歧",
"list.statement.filter.exp": "判断表达式",
"list.statement.filter.type": "判断元素类型",
"list.statement.define": "定义静态变量",
"list.statement.exp.cast.vector2number": "从向量",
"list.statement.exp.const.false": "",
"list.statement.exp.const.h": "屏幕高度",
"list.statement.exp.const.inf": "无穷大",
"list.statement.exp.const.null": "空变量",
"list.statement.exp.const.true": "真",
"list.statement.exp.const.w": "屏幕宽度",
"list.statement.exp.func.abs": "绝对值",
"list.statement.exp.func.anim": "动画值",
"list.statement.exp.func.attack_timing": "在时间区间中按下",
"list.statement.exp.func.clamp": "限制值",
"list.statement.exp.func.contact_timing": "接触时间区间",
"list.statement.exp.func.cubic_bezier": "三次贝塞尔曲线",
"list.statement.exp.func.ease": "缓动",
"list.statement.exp.func.ease_in": "缓入",
"list.statement.exp.func.ease_in_out": "缓入缓出",
"list.statement.exp.func.ease_out": "缓出",
"list.statement.exp.func.enter_timing": "进入时间区间",
"list.statement.exp.func.frame_seq": "帧序列",
"list.statement.exp.func.int": "向下取整",
"list.statement.exp.func.interval": "区间",
"list.statement.exp.func.is": "等价",
"list.statement.exp.func.leave_timing": "离开时间区间",
"list.statement.exp.func.max": "最大值",
"list.statement.exp.func.min": "最小值",
"list.statement.exp.func.release_timing": "在时间区间中松开",
"list.statement.exp.func.screen_edge": "屏幕边缘",
"list.statement.exp.literal.ident": "变量",
"list.statement.exp.literal.identforced": "变量(强制)",
"list.statement.exp.literal.number": "数字",
"list.statement.exp.literal.string": "字符串",
"list.statement.exp.number": "添加元素",
"list.statement.exp.string": "添加元素",
"list.statement.exp.op.add": "a + b",
"list.statement.exp.op.add1": "+n",
"list.statement.exp.op.and": "p 且 q",
"list.statement.exp.op.at": "索引元素",
"list.statement.exp.op.div": "a ÷ b",
"list.statement.exp.op.eq": "a = b",
"list.statement.exp.op.gt": "a > b",
"list.statement.exp.op.lt": "a < b",
"list.statement.exp.op.mod": "a % b",
"list.statement.exp.op.mul": "a × b",
"list.statement.exp.op.not": "非",
"list.statement.exp.op.or": "p 或 q",
"list.statement.exp.op.sep.arr": "数组",
"list.statement.exp.op.sep.vec": "向量",
"list.statement.exp.op.sub": "a - b",
"list.statement.exp.op.sub1": "-n",
"list.statement.obj": "创建容器",
"list.statement.prop": "设置属性",
"list.statement.select": "选择元素",
"list.statement.select.anchor": "选择锚点",
"list.statement.select.atanchor": "选择位于锚点",
"list.statement.select.exp": "筛选表达式",
"list.statement.select.type": "筛选元素类型",
"literal.block.filter": "如果 {statement.filter.exp} {statement.filter.type}",
"literal.block.select": "对于每个 {statement.select.exp} {statement.select.type?元素}",
"literal.statement.filter.exp": "{0}",
"literal.statement.filter.type": "元素的类型为 {0}",
"literal.statement.select.exp": "{0} 的",
"literal.statement.select.type": "{0}",
"statement.comp": "创建一个 {0} 组件",
"statement.define": "定义变量 {0} = {1}",
"statement.filter": "{0} {1}",
"statement.filter.exp": "元素符合表达式 {0}",
"statement.filter.type": "元素的类型为 {0}",
"statement.define": "静态定义 {0} = {1}",
"statement.exp.cast.vector2number": "向量 {0}",
"statement.exp.const.false": "假",
"statement.exp.const.h": "屏幕高度",
"statement.exp.const.inf": "无穷大",
"statement.exp.const.null": "空变量",
"statement.exp.const.true": "真",
"statement.exp.const.w": "屏幕宽度",
"statement.exp.func.abs": "{0} 的绝对值",
"statement.exp.func.anim": "动画值从 {0} 到 {1},使用函数 {2}",
"statement.exp.func.attack_timing": "在时间区间 ({0}, {1}) 中按下",
"statement.exp.func.clamp": "限制 {1} 在 {0} 和 {2} 之间",
"statement.exp.func.contact_timing": "接触时间区间 ({0}, {1})",
"statement.exp.func.cubic_bezier": "由控制点 ({0}, {1}) 和 ({2}, {3}) 定义的三次贝塞尔曲线,复合 {4}",
"statement.exp.func.ease": "缓动,复合 {0}",
"statement.exp.func.ease_in": "缓入,复合 {0}",
"statement.exp.func.ease_in_out": "缓入缓出,复合 {0}",
"statement.exp.func.ease_out": "缓出,复合 {0}",
"statement.exp.func.enter_timing": "进入时间区间 ({0}, +∞)",
"statement.exp.func.frame_seq": "前缀为 {0} 从 {1} 的 {2} 帧序列",
"statement.exp.func.int": "向下取整 {0}",
"statement.exp.func.interval": "{0} 和 {1} 之间的区间",
"statement.exp.func.is": "{0} 等价于 {1}",
"statement.exp.func.leave_timing": "离开时间区间 (-∞, {0})",
"statement.exp.func.max": "{0} 和 {1} 的最大值",
"statement.exp.func.min": "{0} 和 {1} 的最小值",
"statement.exp.func.release_timing": "在时间区间 ({0}, {1}) 中松开",
"statement.exp.func.screen_edge": "屏幕边缘 #{0}",
"statement.exp.literal.ident": "{0}",
"statement.exp.literal.identforced": "{0}(强制)",
"statement.exp.literal.number": "{0}",
"statement.exp.literal.string": "{0}",
"statement.exp.number": "{0}",
"statement.exp.number_or_vector": "{0}",
"statement.exp.string": "{0}",
"statement.exp.op.add": "{0} + {1}",
"statement.exp.op.add1": "+{0}",
"statement.exp.op.and": "{0} 且 {1}",
"statement.exp.op.at": "{0} 的第 {1} 个元素",
"statement.exp.op.div": "{0} ÷ {1}",
"statement.exp.op.eq": "{0} = {1}",
"statement.exp.op.gt": "{0} > {1}",
"statement.exp.op.lt": "{0} < {1}",
"statement.exp.op.mod": "{0} % {1}",
"statement.exp.op.mul": "{0} × {1}",
"statement.exp.op.not": "非 {0}",
"statement.exp.op.or": "{0} 或 {1}",
"statement.exp.op.sep.arr": "数组 {0}",
"statement.exp.op.sep.vec": "向量 {0}",
"statement.exp.op.sub": "{0} - {1}",
"statement.exp.op.sub1": "-{0}",
"statement.obj": "创建一个容器 {0}",
"statement.prop": "设置属性 {0} 为 {1}",
"statement.select": "{0} {1}",
"statement.select.exp": "元素符合表达式 {0}",
"statement.select.type": "元素的类型为 {0}",
"statement.select": "选择 {0} {1}",
"statement.select.anchor": "选择其 {0} 锚点",
"statement.select.atanchor": "选择位于其 {0} 锚点",
"statement.select.exp": "如果元素符合表达式 {0}",
"statement.select.type": "如果元素的类型为 {0}",
"tool.debug": "调试",
"tool.hideadd": "隐藏添加按钮",
"tool.hidedelete": "隐藏删除按钮",
"tool.sort": "排序",
};
};