85 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
76 changed files with 1848 additions and 571 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) {

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

@@ -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,
@@ -255,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));
}
@@ -284,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);

View File

@@ -4,7 +4,7 @@ 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;

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

@@ -24,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;
@@ -175,16 +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;
if (frames.ContainsKey(name)) {
Logger.Log("main", 3, "Load/Prehandle", "Duplicated texture name: {0}", name);
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 {
frames.Add(name, new SpriteFrame(tex));
Logger.Log("main", 4, "Load/Prehandle", "Unable to load texture: {0}", name);
}
texs.Add(name, tex);
texLoader.Dispose();
texHandler.Dispose();
texLoader = null;
@@ -468,6 +473,8 @@ 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) {
@@ -478,7 +485,6 @@ namespace Cryville.Crtr {
}
Game.AudioSequencer.Playing = true;
atime0 = Game.AudioClient.BufferPosition;
Thread.Sleep((int)((atime0 - Game.AudioClient.Position) * 1000));
inputProxy.SyncTime(cbus.Time);
started = true;
}

View File

@@ -2,8 +2,15 @@
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));
}
@@ -28,12 +35,32 @@ namespace Cryville.Crtr.Components {
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() {
if (materials != null)
foreach (var mat in materials) {
Material.Destroy(mat);
}
DestroyMaterials();
mesh.Destroy();
}
protected void DestroyMaterials() {
if (materials == null) return;
foreach (var mat in materials) {
Material.Destroy(mat);
}
}
}
}

View File

@@ -72,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);
@@ -107,7 +107,7 @@ namespace Cryville.Crtr.Components {
base.Init();
mesh.Init(transform);
mesh.Renderer.materials = materials = new Material[] {
mesh.Renderer.sharedMaterials = materials = new Material[] {
MeshWrapper.NewMaterial(),
MeshWrapper.NewMaterial(),
MeshWrapper.NewMaterial(),

View File

@@ -1,5 +1,89 @@
namespace Cryville.Crtr.Components {
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

@@ -26,6 +26,8 @@ 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 {

View File

@@ -88,8 +88,9 @@ namespace Cryville.Crtr.Components {
protected void InternalInit(string meshName = "quad") {
mesh.Init(transform);
mesh.Renderer.materials = materials = new Material[] { MeshWrapper.NewMaterial() };
mesh.Renderer.sharedMaterials = materials = new Material[] { MeshWrapper.NewMaterial() };
mesh.Mesh = GenericResources.Meshes[meshName];
UpdateColor();
UpdateScale();
UpdateZIndex();
}

View File

@@ -60,7 +60,7 @@ namespace Cryville.Crtr.Components {
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;
@@ -122,9 +122,21 @@ namespace Cryville.Crtr.Components {
return;
}
mesh.Renderer.enabled = true;
mesh.Renderer.material.mainTexture = frame.Frame.Texture;
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];
@@ -138,21 +150,6 @@ namespace Cryville.Crtr.Components {
mesh.Mesh.uv = _uvs;
}
float _opacity = 1;
public float Opacity {
get { return _opacity; }
set {
_opacity = value;
UpdateOpacity();
}
}
protected void UpdateOpacity() {
if (!mesh.Initialized) return;
var c = mesh.Renderer.material.color;
c.a = _opacity;
mesh.Renderer.material.color = c;
}
private FitMode m_fit = FitMode.height;
public FitMode Fit {
get { return m_fit; }
@@ -185,7 +182,7 @@ namespace Cryville.Crtr.Components {
public override void Init() {
InternalInit();
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"];
@@ -84,7 +84,6 @@ namespace Cryville.Crtr.Components {
public override void Init() {
InternalInit("quad_scale3h");
OnFrameUpdate();
UpdateOpacity();
}
}
}

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,7 +19,7 @@ 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;
@@ -47,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();
@@ -78,7 +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) {
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;
@@ -86,14 +89,17 @@ namespace Cryville.Crtr.Components {
var m = new MeshWrapper();
m.Init(mesh.MeshTransform);
m.Mesh = new Mesh();
m.Renderer.material = MeshWrapper.NewMaterial(); // TODO Destroy or add to `materials`
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;
@@ -158,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) {
var c = m.Value.Renderer.material.color;
c.a = _opacity;
m.Value.Renderer.material.color = c;
}
}
public override void Init() {
InternalInit();
UpdateFrames();

View File

@@ -93,10 +93,10 @@ namespace Cryville.Crtr.Config {
var tsrc = src.Value;
bool flag = false;
if (proxy.IsUsed(tsrc)) {
text.text += " (Used)";
text.text += " <size=9>(Used)</size>";
}
else if (tsrc.Handler.GetDimension(src.Value.Type) < m_configScene.ruleset.Root.inputs[_sel].dim) {
text.text += " (Not Applicable)";
text.text += " <size=9>(Not Applicable)</size>";
}
else flag = true;
btn.interactable = flag;

View File

@@ -1,5 +1,6 @@
using Cryville.Common.Buffers;
using System.Collections.Generic;
using UnityEngine;
namespace Cryville.Crtr {
public class EffectGroup {
@@ -35,22 +36,37 @@ namespace Cryville.Crtr {
while (_endQueue.Count > 0) {
var item = _endQueue[0];
if (item.EndTime > _time) break;
item.OnDone();
_instances.Remove(item.Index);
_pool.Return(item);
_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) {
public void Emit(float index, Transform target = null) {
EffectInstance instance;
if (!_instances.TryGetValue(index, out instance)) {
_instances.Add(index, instance = _pool.Rent());
}
bool flag = _instances.TryGetValue(index, out instance);
if (!flag) _instances.Add(index, instance = _pool.Rent());
instance.Index = index;
instance.OnEmit(_time);
var i = _endQueue.BinarySearch(instance);
if (i < 0) i = ~i;
_endQueue.Insert(i, instance);
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

@@ -1,5 +1,6 @@
using Cryville.Common;
using Cryville.Crtr.Components;
using Cryville.Crtr.Event;
using System;
using System.Collections.Generic;
using System.Globalization;
@@ -10,37 +11,89 @@ namespace Cryville.Crtr {
readonly EffectDefinition _def;
readonly SkinContainer _skinContainer;
public Transform RootTransform { get; private set; }
readonly SkinComponent[] _comps;
public EffectInstance(EffectDefinition def) {
_def = def;
_skinContainer = new SkinContainer(_def.elements);
_skinContainer = new SkinContainer(this, _def.elements);
RootTransform = new GameObject("effect:" + GetHashCode().ToString(CultureInfo.InvariantCulture)).transform;
SkinContext = new SkinContext(RootTransform);
ChartPlayer.etor.ContextCascadeInsertBlock();
_skinContainer.MatchStatic(this);
_skinContainer.MatchStatic();
ChartPlayer.etor.ContextCascadeDiscardBlock();
foreach (var i in RootTransform.GetComponentsInChildren<SkinComponent>())
i.Init();
_comps = RootTransform.GetComponentsInChildren<SkinComponent>();
foreach (var i in _comps) i.Init();
_indexSrc = new PropSrc.Float(() => Index);
_durationOp = new PropOp.Float(v => _duration = v);
}
public float Index { get; set; }
static readonly int _var_index = IdentifierManager.SharedInstance.Request("index");
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 OnEmit(double time) {
_startTime = time;
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_index, _indexSrc);
ChartPlayer.etor.Evaluate(_durationOp, _def.duration);
_skinContainer.MatchDynamic(this, 0);
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 void OnDone() {
RootTransform.gameObject.SetActive(false);
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);
@@ -48,7 +101,7 @@ namespace Cryville.Crtr {
public string TypeName { get { throw new InvalidOperationException("Type name undefined"); } }
public SkinContext SkinContext { get; private set; }
public Anchor OpenedAnchor { get { throw new InvalidOperationException("Anchor not supported"); } }
public int OpenedAnchorName { get { return _currentStateName.Key; } }
public void PushAnchorEvent(double time, int name) {
throw new InvalidOperationException("Anchor not supported");
}
@@ -60,7 +113,9 @@ namespace Cryville.Crtr {
}
public int CompareTo(EffectInstance other) {
return EndTime.CompareTo(other.EndTime);
int r = EndTime.CompareTo(other.EndTime);
if (r != 0) return r;
return GetHashCode().CompareTo(other.GetHashCode());
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using UnityEngine;
namespace Cryville.Crtr {
public class EffectManager {
@@ -15,6 +16,9 @@ namespace Cryville.Crtr {
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

@@ -37,10 +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;
protected Transform RootTransform;
SkinComponent[] _comps;
public Vector3 Position { get; protected set; }
public Quaternion Rotation { get; protected set; }
@@ -70,7 +69,7 @@ namespace Cryville.Crtr.Event {
SkinContainer skinContainer;
protected Judge judge;
public void AttachSystems(PdtSkin skin, Judge judge) {
skinContainer = new SkinContainer(skin.elements);
skinContainer = new SkinContainer(this, skin.elements);
this.judge = judge;
}
@@ -80,15 +79,15 @@ namespace Cryville.Crtr.Event {
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))
@@ -103,22 +102,22 @@ 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);
@@ -126,16 +125,16 @@ namespace Cryville.Crtr.Event {
public virtual void Init() {
ChartPlayer.etor.ContextState = ps;
ChartPlayer.etor.ContextEvent = Container;
skinContainer.MatchStatic(this);
skinContainer.MatchStatic();
ChartPlayer.etor.ContextEvent = null;
ChartPlayer.etor.ContextState = null;
foreach (var i in gogroup.GetComponentsInChildren<SkinComponent>())
i.Init();
_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
@@ -146,14 +145,14 @@ namespace Cryville.Crtr.Event {
public virtual void StartLogicalUpdate(ContainerState s) { }
protected virtual void StartPreGraphicalUpdate(ContainerState s) { }
protected virtual void StartGraphicalUpdate(ContainerState s) {
if (gogroup) gogroup.gameObject.SetActive(true);
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);
@@ -172,7 +171,7 @@ namespace Cryville.Crtr.Event {
}
anchorEvPool.Return(tev);
}
else if (gogroup && s.CloneType == 2) MatchDynamic(s, 1);
else if (RootTransform && s.CloneType == 2) MatchDynamic(s, 1);
}
#region End methods
protected virtual void EndGraphicalUpdate(ContainerState s) { }
@@ -180,8 +179,8 @@ namespace Cryville.Crtr.Event {
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() { }
@@ -193,7 +192,7 @@ namespace Cryville.Crtr.Event {
void MatchDynamic(ContainerState s, int dl) {
ChartPlayer.etor.ContextState = s;
ChartPlayer.etor.ContextEvent = Container;
skinContainer.MatchDynamic(this, dl);
skinContainer.MatchDynamic(dl);
ChartPlayer.etor.ContextEvent = null;
ChartPlayer.etor.ContextState = null;
}
@@ -205,6 +204,7 @@ namespace Cryville.Crtr.Event {
atime_head = cs.StampedContainer.Time;
atime_tail = atime_head + cs.StampedContainer.Duration;
MatchDynamic(cs, 0);
foreach (var i in _comps) i.Tick(skinContainer, cs.Time);
if (cs.Active) PushAnchorEvent(cs.Time, a_cur);
if (double.IsNaN(DynamicAnchorSetTime[_a_head])) DynamicAnchorSetTime[_a_head] = atime_head;
if (double.IsNaN(DynamicAnchorSetTime[_a_tail])) DynamicAnchorSetTime[_a_tail] = atime_tail;
@@ -241,7 +241,8 @@ namespace Cryville.Crtr.Event {
#region ISkinnableGroup
public abstract string TypeName { get; }
public SkinContext SkinContext { get; private set; }
public Anchor OpenedAnchor { 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);

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,
};

View File

@@ -24,6 +24,7 @@ namespace Cryville.Crtr {
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));
@@ -32,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,12 +13,11 @@ 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;
@@ -174,14 +174,58 @@ namespace Cryville.Crtr {
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) {
@@ -191,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;
@@ -209,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();
@@ -306,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 {
@@ -134,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);
@@ -154,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;
}
@@ -323,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

@@ -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,7 +57,7 @@ namespace Cryville.Crtr {
}
public override void Init() {
base.Init();
sgos = gogroup.GetComponentsInChildren<SectionalGameObject>();
sgos = RootTransform.GetComponentsInChildren<SectionalGameObject>();
foreach (var judge in judges) judge.Value.InitPropSrcs();
}
@@ -70,7 +70,7 @@ namespace Cryville.Crtr {
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);
}
@@ -128,7 +128,7 @@ namespace Cryville.Crtr {
}
protected override void EndGraphicalUpdate(ContainerState s) {
if (gogroup) {
if (RootTransform) {
foreach (var i in sgos) i.Seal();
}
base.EndGraphicalUpdate(s);

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,11 +107,12 @@ 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() {
@@ -140,6 +150,7 @@ 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));
@@ -147,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));
@@ -263,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++) {
@@ -486,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");
@@ -554,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

@@ -63,7 +63,7 @@ namespace Cryville.Crtr {
public class StringArray : PropOp {
readonly Action<string[]> _cb;
public StringArray(Action<string[]> cb) { _cb = cb; }
protected unsafe override void Execute() {
protected override unsafe void Execute() {
var op = GetOperand(0);
int arrtype; int len;
op.GetArraySuffix(out arrtype, out len);
@@ -100,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

@@ -54,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,4 +1,5 @@
using Cryville.Common;
using Cryville.Common.Collections.Generic;
using Cryville.Common.Pdt;
using Cryville.Crtr.Browsing;
using Newtonsoft.Json;
@@ -64,9 +65,9 @@ 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) {
etor.Optimize(e.Value);

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,4 +1,5 @@
using Cryville.Common;
using Cryville.Common.Collections.Generic;
using Cryville.Common.Pdt;
using Cryville.Crtr.Browsing;
using Newtonsoft.Json;
@@ -59,7 +60,10 @@ namespace Cryville.Crtr {
foreach (var e in effects) {
var effect = e.Value;
etor.ContextCascadeInsert();
etor.Optimize(effect.duration);
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();
}
@@ -69,12 +73,12 @@ namespace Cryville.Crtr {
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;
@@ -98,18 +102,38 @@ namespace Cryville.Crtr {
}
public class EffectDefinition {
public PdtExpression duration;
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 Dictionary<Clip, AnimationSpan> spans
= new Dictionary<Clip, AnimationSpan>();
public PairList<Clip, AnimationSpan> spans
= new PairList<Clip, AnimationSpan>();
[PropertyList]
public Dictionary<SkinPropertyKey, PdtExpression> properties
= new Dictionary<SkinPropertyKey, PdtExpression>();
public PairList<SkinPropertyKey, PdtExpression> properties
= new PairList<SkinPropertyKey, PdtExpression>();
public void Optimize(PdtEvaluator etor) {
foreach (var p in properties) {

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 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,21 +29,26 @@ namespace Cryville.Crtr {
public SkinSelectors Selectors { get; set; }
public SkinElement Element { get; set; }
}
public SkinContainer(SkinElement rootElement) {
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(ISkinnableGroup group) {
public void MatchStatic() {
var stack = _stacks[0];
stack.Clear();
MatchStatic(_rootElement, group, stack, new RuntimeSkinContext(group.SkinContext));
MatchStatic(_rootElement, stack, new RuntimeSkinContext(_group.SkinContext));
}
void MatchStatic(SkinElement rel, ISkinnableGroup group, 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(group, 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 }
);
@@ -48,13 +56,13 @@ namespace Cryville.Crtr {
ChartPlayer.etor.ContextTransform = null;
foreach (var e in rel.elements) {
try {
var nctxs = e.Key.MatchStatic(group, 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, group, stack, nrctx);
MatchStatic(e.Value, stack, nrctx);
}
}
}
@@ -66,15 +74,19 @@ namespace Cryville.Crtr {
}
if (rc.PropSrcs != null) ChartPlayer.etor.ContextCascadeDiscard();
}
public void MatchDynamic(ISkinnableGroup group, int dl) {
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");
if (!recursive) ChartPlayer.etor.ContextSkinContainer = this;
for (int i = 0; i < stack.Properties.Count; i++) {
DynamicProperty p = stack.Properties[i];
p.Key.ExecuteDynamic(group, p.Context, p.Value, dl);
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];
@@ -82,14 +94,14 @@ namespace Cryville.Crtr {
if (psrcs != null) ChartPlayer.etor.ContextCascadeInsert(psrcs);
SkinContext nctx = null;
try {
nctx = e.Selectors.MatchDynamic(group, 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, group, dl, nstack, new RuntimeSkinContext(
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")) {
@@ -98,20 +110,28 @@ namespace Cryville.Crtr {
}
if (psrcs != null) ChartPlayer.etor.ContextCascadeDiscard();
}
if (!recursive) ChartPlayer.etor.ContextSkinContainer = null;
Profiler.EndSample();
}
void MatchDynamic(SkinElement rel, ISkinnableGroup group, int dl, 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(group, ctx, p.Value, dl);
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(group, dl)) {
SkinContext nctx = e.Key.MatchDynamic(group, rc);
if (nctx != null) MatchDynamic(e.Value, group, dl, 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")
));
}
@@ -124,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,9 +202,22 @@ namespace Cryville.Crtr {
public interface ISkinnableGroup {
string TypeName { get; }
SkinContext SkinContext { get; }
Anchor OpenedAnchor { 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,6 +1,4 @@
using Cryville.Common;
using Cryville.Common.Pdt;
using Cryville.Crtr.Components;
using Cryville.Common.Pdt;
using System;
using System.Collections.Generic;
using System.Reflection;
@@ -58,41 +56,7 @@ 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])
};
}
else if (a.Contains("emit")) {
if (k.Count != 1) throw new FormatException("Invalid effect name");
return new SkinPropertyKey.EmitEffect {
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 '}':
@@ -127,7 +91,7 @@ namespace Cryville.Crtr {
if (cc != '{') throw new FormatException("Invalid span format");
return new Clip(start, end);
}
k.Clear();
a.Clear(); k.Clear();
while (true) {
int pp = Position;
switch (cc) {
@@ -139,20 +103,7 @@ namespace Cryville.Crtr {
break;
case ';':
case ':':
switch (k.Count) {
case 1:
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, false);
case '{':
throw new FormatException("Invalid token");
case '}':
@@ -167,10 +118,5 @@ 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));
}
}
}

View File

@@ -2,38 +2,87 @@
using Cryville.Common.Pdt;
using Cryville.Crtr.Components;
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(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp);
public abstract void ExecuteDynamic(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, int dl);
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(ISkinnableGroup group, 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(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, int dl) {
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(ISkinnableGroup group, 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(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, int dl) {
public override void ExecuteDynamic(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, Dictionary<int, SkinVariable> vars, int dl) {
var prop = GetPropOp(ctx.WriteTransform);
if (dl > prop.UpdateDynamicLevel) return;
Execute(ctx, prop.Operator, exp);
@@ -61,33 +110,37 @@ 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(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp) {
public override void ExecuteStatic(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, Dictionary<int, SkinVariable> vars) {
group.RegisterAnchor(Name);
}
public override void ExecuteDynamic(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, int dl) {
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(ISkinnableGroup group, 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(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, int dl) {
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);
@@ -97,22 +150,48 @@ namespace Cryville.Crtr {
}
}
public class EmitEffect : SkinPropertyKey {
public int Name { get; set; }
public EmitEffect() {
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("@emit {0}", IdentifierManager.SharedInstance.Retrieve(Name));
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) {
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, int dl) {
public override void ExecuteDynamic(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, Dictionary<int, SkinVariable> vars, int dl) {
ChartPlayer.etor.Evaluate(_op, exp);
ChartPlayer.effectManager.Emit(Name, _index);
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

@@ -101,7 +101,7 @@ namespace Cryville.Crtr {
public override string ToString() { return string.Format("..{0}", IdentifierManager.SharedInstance.Retrieve(Name)); }
public override SkinContext MatchDynamic(ISkinnableGroup g, SkinContext c) {
return g.OpenedAnchor != null && g.OpenedAnchor.Name == Name ? c : null;
return g.OpenedAnchorName == Name ? c : null;
}
public override bool IsUpdatable(ISkinnableGroup g, int dl) {
return dl >= 1;

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;
@@ -33,7 +33,7 @@ namespace Cryville.Crtr {
}
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);

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

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);
}

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": "排序",
};
};