160 Commits

Author SHA1 Message Date
d510fec57b Update version. 2023-03-23 19:11:24 +08:00
c5214dd477 Update gitignore. 2023-03-17 18:08:11 +08:00
a2391aeb22 Cleanup. (Skin editor) 2023-03-15 15:44:32 +08:00
2207c80951 Fix incorrect style for single-statement blocks in expression. 2023-03-15 15:43:30 +08:00
bf578d7cb9 Make statements in expression not sortable. 2023-03-15 15:41:02 +08:00
0bc57c368f Improve scaling logic of popup list in skin editor.. 2023-03-15 15:39:31 +08:00
b64f85aaa2 Add category for expression list in skin editor. 2023-03-15 15:36:45 +08:00
93fa2f2d7e Sync some constants, operators, and functions for skin editor. (3) 2023-03-15 15:34:33 +08:00
d72216de8b Sync some constants, operators, and functions for skin editor. (2) 2023-03-15 10:02:09 +08:00
df5133a91a Sync some constants, operators, and functions for skin editor. 2023-03-15 00:46:19 +08:00
88b959a118 Modify border color of expression statement. 2023-03-15 00:44:44 +08:00
310bf91fbd Always collapses delete button in skin editor. 2023-03-15 00:43:49 +08:00
699f47f98d Fix the height of popup list in skin editor. 2023-03-15 00:43:07 +08:00
24e881b138 Sync component and property list for skin editor. 2023-03-14 23:32:35 +08:00
2eef1b5c4e Update translations for skin editor. 2023-03-14 17:27:05 +08:00
c18ceb50d4 Update skin structure in editor. 2023-03-14 17:24:32 +08:00
27ca1a7292 Implement expression in skin editor. 2023-03-14 17:22:48 +08:00
dc59176eac Fix encoding for skin editor. 2023-03-14 16:59:37 +08:00
aec7470ff8 Optimize css for skin editor. 2023-03-14 16:58:03 +08:00
983cba6843 Detects user chart path for Malody chart finder. 2023-03-11 21:41:54 +08:00
871782e73f Remove potentially buggy syncing logic. 2023-03-11 21:41:22 +08:00
9aaa96fe10 Optimize GC for input proxy. 2023-03-11 21:40:34 +08:00
22190a29c1 Fix incorrect array length for vector operator. 2023-03-11 21:39:26 +08:00
613ca467d0 Fix offset error on function anim. 2023-03-09 22:02:34 +08:00
536a3066b2 Fix array operator creating array of type error. 2023-03-09 16:27:16 +08:00
43488cd002 Add "emit effect on self" annotation. 2023-03-09 16:26:43 +08:00
a11ccbd39c Cleanup variable name. 2023-03-09 11:41:25 +08:00
76df4929a7 Implement set variable annotation. 2023-03-09 11:38:49 +08:00
505b826627 Move up non-generic collection types and add debug view. 2023-03-09 11:37:23 +08:00
26a8675922 Make animation time of subspan relative. 2023-03-09 10:07:24 +08:00
b89e1f983e Code cleanup. 2023-03-08 20:36:18 +08:00
717e77b47e Fix inaccurate beat snapping for Quaver charts. 2023-03-06 08:16:42 +08:00
2f10c79dee Adjust offset for osu chart converter. 2023-03-05 23:06:18 +08:00
55f7790f89 Fix potential error on vector property source. 2023-03-05 23:05:48 +08:00
ae5f4a8c16 (Amend to 1851bd3c) 2023-03-05 21:53:30 +08:00
1851bd3c54 Fix inaccurate beat snapping for osu charts. Fix osu charts with too low BPM not able to be imported. 2023-03-05 20:40:02 +08:00
6d74685cb7 Add anim.iteration, anim.direction, and anim.delay properties. 2023-03-03 15:10:52 +08:00
03fd7f6d01 Add inf constant. 2023-03-03 15:09:08 +08:00
28c878f3e5 Code cleanup. 2023-03-03 13:34:12 +08:00
7736eba14d Supplement generic PairCollection. 2023-03-03 13:26:11 +08:00
2e54b38d2b Supplement Insert methods for pair list. 2023-03-03 11:49:32 +08:00
da60dc0903 Fix potential order inconsistency of element and property lists. 2023-03-03 11:45:16 +08:00
215f72b3b5 Add cubic bezier functions. 2023-03-02 10:40:18 +08:00
a93c081dd8 Add easing function parameter to anim function. 2023-03-02 10:39:39 +08:00
456782930a Fix incorrect zero format specifier range. 2023-03-01 17:55:09 +08:00
ba3cbbd64c Add state-based effect. 2023-03-01 00:37:22 +08:00
dfc3e9ca06 Refactor OpenedAnchorName in ISkinnableGroup. (Amend) 2023-03-01 00:36:09 +08:00
f567a2b78e Fix error on setting anim.name to null. 2023-03-01 00:35:19 +08:00
c7e7bd8a77 Add Identifier.Empty. 2023-03-01 00:33:28 +08:00
67720fd0e1 Refactor OpenedAnchorName in ISkinnableGroup. 2023-03-01 00:33:01 +08:00
1a30149942 Prevents infinite propagation on input proxy and judge. 2023-02-28 13:47:38 +08:00
a755cc13bd Implement animation. 2023-02-27 00:17:14 +08:00
9a51cf1b56 Add rewind and tick mechanism for skin component. 2023-02-27 00:16:44 +08:00
256c656e9c Fix once annotation not working on certain properties. 2023-02-27 00:13:38 +08:00
2ac7f05316 Add contextual function anim. 2023-02-27 00:11:37 +08:00
28d46dbabe Disallows multiple meshes in one object. 2023-02-26 16:24:58 +08:00
18b3e0bc84 Code cleanup. 2023-02-26 16:24:28 +08:00
23f2e7c1f2 Fix multiple flags ignored in enum property operator. 2023-02-26 16:23:17 +08:00
998713b41f Pull some init logic in enum property operator to static constructor. 2023-02-26 16:22:37 +08:00
3561354231 Implement execute once annotation on properties. 2023-02-26 16:21:33 +08:00
0cccb170c1 Support extra annotations on skin property key. Code cleanup. 2023-02-26 16:20:25 +08:00
d2480b8a6f Update global suppressions. 2023-02-26 16:16:46 +08:00
6837d3f7ee Make the group in skin container readonly. 2023-02-24 15:25:04 +08:00
3ecf3b4bfc Code cleanup. 2023-02-21 22:47:42 +08:00
1da8647ff1 Re-add start offset stub. 2023-02-21 22:47:24 +08:00
2f19e8daad Add limit for render distance settings. 2023-02-21 22:45:51 +08:00
07f62c7aeb Reduce font size for extra tag in input config. 2023-02-21 22:43:38 +08:00
39db8dfa45 Code cleanup. 2023-02-21 18:43:21 +08:00
f04cd370f1 Allow vector as number in contextual operators. 2023-02-21 18:42:58 +08:00
5c4acd54ce Add ticking stub for effect. 2023-02-21 18:42:03 +08:00
82dbc5c479 Add event property for event. 2023-02-21 18:41:32 +08:00
1f1663d714 Rename index to effect_index. 2023-02-21 18:29:25 +08:00
a3c5392caa Optimize GC for vector property source. 2023-02-21 18:27:29 +08:00
6c983cc2cb Add backward compatibility for opacity property. 2023-02-19 22:44:12 +08:00
3bf3fdac3d Code cleanup. 2023-02-19 22:15:46 +08:00
f2f3dba098 Fix effect queue with multiple items of the same instance. 2023-02-19 22:15:25 +08:00
3728360dd2 Fix index invalidation for effects. 2023-02-19 22:13:57 +08:00
887837bb3d Fix main thread stuck on texture missing. 2023-02-19 22:13:18 +08:00
99b4c2dfc1 Fix error on text frame update if texture not found. 2023-02-19 22:11:59 +08:00
e59769158a Change materials to shared mode in components. 2023-02-19 22:08:09 +08:00
ba3238614b Pull up mesh.color. Remove *.opacity properties. 2023-02-19 22:06:20 +08:00
a115999aab Add additive shader. 2023-02-19 21:57:06 +08:00
393947db9f Add image.shader property. 2023-02-19 21:56:30 +08:00
e9b2a7f894 Fix error on dynamic expressions in static context. 2023-02-19 21:55:01 +08:00
9c73455761 Fix error on appending arg set when current length equals to capacity in string formatter. 2023-02-19 11:07:50 +08:00
59c2210359 Prevents dimension-unapplicable inputs from being assigned. 2023-02-18 15:51:21 +08:00
4fab20953a Improve text hints in input config. 2023-02-18 15:49:45 +08:00
ee7b0f5081 Make pause input optional. 2023-02-18 15:48:02 +08:00
33ee7a9a87 Code cleanup. 2023-02-18 15:46:32 +08:00
900bd7b77a Implement effect. 2023-02-18 14:51:28 +08:00
6bd32c9aef Add context cascade blocking. 2023-02-18 14:48:43 +08:00
13893b2853 Add execute once annotation. 2023-02-18 14:48:09 +08:00
23789c15eb Pull up material disposal to MeshBase. (Amend) 2023-02-18 14:46:38 +08:00
a1f7418d32 Code cleanup. 2023-02-18 14:46:08 +08:00
274a823d02 Fix log not cleared on log toggle. 2023-02-18 14:44:05 +08:00
ba6239068a Optimize GC for sprite update. 2023-02-18 14:42:42 +08:00
ff8c925f32 Optimize GC for setting image.frame. 2023-02-18 14:40:56 +08:00
2a6a33e60c Pull up material disposal to MeshBase. 2023-02-18 14:39:45 +08:00
8910b1f4a0 Allow dynamic anchor reset. 2023-02-17 23:14:51 +08:00
36dddea4d9 Code cleanup. 2023-02-17 21:13:19 +08:00
6a648c2dcd Fix error on image.frame(s) not set. 2023-02-17 21:12:41 +08:00
2d4087dc89 Fix behaviour on parameter overflow. 2023-02-17 21:11:38 +08:00
f91aacd78e Code cleanup. 2023-02-17 18:11:04 +08:00
9c08cbf0d2 Remove some dedicated properties on ISkinnableGroup. 2023-02-17 18:10:46 +08:00
88d35e4eaf Add backward compatibility for skin. (Amend) 2023-02-17 16:27:49 +08:00
675ce68073 Add backward compatibility for skin. 2023-02-17 16:24:24 +08:00
db0165d145 Pull up ISkinnableGroup. 2023-02-17 15:19:18 +08:00
7015426300 Add error handling for setting text.frames. 2023-02-17 14:41:12 +08:00
0d4cc5e208 Add skin property image.frames and image.index. 2023-02-17 14:40:34 +08:00
e7ce0985fb Add effect emitting stub. 2023-02-15 18:13:04 +08:00
eb6dafbd60 Add animation stub and effect stub for skin. 2023-02-15 18:12:41 +08:00
b6e238780e Change fixed skin root to configurable root element in skin container. 2023-02-15 18:09:21 +08:00
c7ea6f1d4b Cleanup logic of PDT interpreter. 2023-02-15 18:07:36 +08:00
4a5b2a6889 Add effect definition. 2023-02-15 15:35:09 +08:00
b84d645aee Pull up PdtBinder. 2023-02-15 15:34:27 +08:00
67b44db1ae Code cleanup. 2023-02-13 16:09:19 +08:00
ee4399109a Optimize GC for log in gameplay scene. 2023-02-12 21:50:57 +08:00
87ef534f59 Fix resize logic in StringBuffer. 2023-02-12 21:48:39 +08:00
87362b47c5 Cleanup CategorizedPool. 2023-02-12 17:27:54 +08:00
f60ba1088d Fix input conflict in input config. 2023-02-12 17:27:15 +08:00
abb7ad6f24 Adjust offset for osu chart converter. 2023-02-11 23:13:30 +08:00
880b475c07 Update project version. 2023-02-11 23:12:01 +08:00
4707c40e6a Add object pool related debug status info. 2023-02-11 23:11:45 +08:00
7f87c23da2 Fix contextual state variables available in static context. 2023-02-11 23:11:15 +08:00
6df10837fe Eliminate Array.Copy GC in SquareMatrix. 2023-02-11 23:09:46 +08:00
42cb54de1d Add RentedCount for ObjectPool. 2023-02-11 23:09:05 +08:00
9fd685b8b3 Pull up CategorizedPool. Add Reset method for ObjectPool. 2023-02-11 23:08:43 +08:00
b364005741 Update UnsafeIL. 2023-02-10 17:52:45 +08:00
7d938de409 Code cleanup. 2023-02-10 17:36:36 +08:00
bb4ecfcd8c Add graphical offset global settings. 2023-02-10 17:36:19 +08:00
ff410529b0 Add invisible_bounds contextual variable. 2023-02-10 17:35:36 +08:00
fdc55a8e3b Pull current_time to container handler. 2023-02-10 17:34:40 +08:00
fc8512ff63 Combine score and score string property sources. 2023-02-10 17:32:59 +08:00
1b1ed42a1b Code cleanup. 2023-02-10 15:50:49 +08:00
b437925f92 Replace TrustedAsOfLength with safe As and Set. 2023-02-10 15:47:20 +08:00
c04e50e959 Modify priority logic for normal/temporary events. 2023-02-09 18:22:39 +08:00
314cdb9935 Implement transform update for static judge anchor. 2023-02-09 18:21:17 +08:00
77c91d015a Add standalone event property. 2023-02-09 18:20:36 +08:00
291a018c13 Activates anchors only on set. 2023-02-09 18:19:46 +08:00
18ff4b8e16 Code cleanup. 2023-02-09 18:18:34 +08:00
7714c277fd Modify text in status debug info. 2023-02-09 18:14:07 +08:00
d6c2ac6be6 Fix TypedChildren shared across ContainerState. 2023-02-09 18:12:33 +08:00
682fe38d40 Fix priority for manually set special anchors. 2023-02-09 18:11:32 +08:00
3e525842cb Modify texts in input config panel. 2023-02-09 18:09:40 +08:00
3dd25b51a8 Fix wrong context access in component creation. 2023-02-09 18:08:12 +08:00
041c1e374e Optimize GC for frame calculation. 2023-02-09 18:07:06 +08:00
16b1d323dc Add exception handling for invalid key interpretation in PDT. 2023-02-09 12:21:41 +08:00
c4d5e5f480 Matches member name first then generic list in PDT. 2023-02-09 12:15:07 +08:00
187f07d2c9 Optimize GC for motions. 2023-02-07 23:15:52 +08:00
4e9d7e5b87 Optimize GC for SectionalGameObject. 2023-02-07 23:15:11 +08:00
7df5b15e2e Animation cleanup. 2023-02-07 16:36:17 +08:00
4863aa0ae7 Add persist in judge definition. 2023-02-07 16:24:27 +08:00
eb53c3465b Implement pausing. 2023-02-07 16:23:16 +08:00
f683d61298 Reorganize resources. 2023-02-07 14:20:47 +08:00
fbd03c8037 Add sound offset for ruleset config. 2023-02-06 22:55:43 +08:00
da68c8b877 Move ruleset config to main scene. Add title for UI. 2023-02-06 22:55:14 +08:00
c0744a3464 Add interval function. 2023-02-06 15:16:35 +08:00
3ca3746cec Fix judge passing for inputs without any events. 2023-02-06 15:16:02 +08:00
5e76ddf2cd Fix use of discarded digits in rounded numbers in string formatter. 2023-02-06 15:14:54 +08:00
dca1ba304e Code cleanup. 2023-02-05 23:01:46 +08:00
140 changed files with 3343 additions and 1206 deletions

1
.gitignore vendored
View File

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

Binary file not shown.

Binary file not shown.

View File

@@ -1,8 +1,8 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 66a6563760d5cfa47ac1057052043fa7 guid: 2e0c61e29fd90f04b9e41265d93e2029
timeCreated: 1610937108
licenseType: Free
NativeFormatImporter: NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 7400000
userData: userData:
assetBundleName: assetBundleName:
assetBundleVariant: assetBundleVariant:

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d815e4d844e6a1c4d849e96e199f8881
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 7400000
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 82867c59112ff5a419fbea2ebff2d3b9
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 7400000
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,90 @@
using System.Collections.Generic;
namespace Cryville.Common.Buffers {
/// <summary>
/// A set of resource pools categorized by a category type.
/// </summary>
/// <typeparam name="TCategory">The category type.</typeparam>
/// <typeparam name="TObject">The type of the objects in the pool.</typeparam>
public abstract class CategorizedPool<TCategory, TObject> where TObject : class {
/// <summary>
/// The set of underlying pools.
/// </summary>
/// <remarks>
/// <para>The <see cref="Rent(TCategory)" /> and <see cref="Return(TCategory, TObject)" /> method select an underlying pool directly from this set with the category as the key. When overridden, this set must be available since construction.</para>
/// </remarks>
protected abstract IReadOnlyDictionary<TCategory, ObjectPool<TObject>> Buckets { get; }
/// <summary>
/// The count of objects rented from the set of pools.
/// </summary>
public int RentedCount { get; private set; }
/// <summary>
/// Rents an object from the pool.
/// </summary>
/// <param name="category">The category.</param>
/// <returns>The rented object.</returns>
public TObject Rent(TCategory category) {
var obj = Buckets[category].Rent();
RentedCount++;
return obj;
}
/// <summary>
/// Returns a rented object to the pool.
/// </summary>
/// <param name="category">The category.</param>
/// <param name="obj">The object to return.</param>
public void Return(TCategory category, TObject obj) {
Buckets[category].Return(obj);
--RentedCount;
}
}
/// <summary>
/// A utility to access a categorized pool, representing a single unit that uses a shared categorized pool.
/// </summary>
/// <typeparam name="TCategory">The category type.</typeparam>
/// <typeparam name="TObject">The type of the objects in the pool.</typeparam>
public class CategorizedPoolAccessor<TCategory, TObject> where TObject : class {
readonly CategorizedPool<TCategory, TObject> _pool;
static readonly SimpleObjectPool<Dictionary<TObject, TCategory>> _dictPool
= new SimpleObjectPool<Dictionary<TObject, TCategory>>(1024);
Dictionary<TObject, TCategory> _rented;
/// <summary>
/// Creates an instance of the <see cref="CategorizedPoolAccessor{TCategory, TObject}" /> class.
/// </summary>
/// <param name="pool">The categorized pool.</param>
public CategorizedPoolAccessor(CategorizedPool<TCategory, TObject> pool) {
_pool = pool;
}
/// <summary>
/// Rents an object from the pool.
/// </summary>
/// <param name="category">The category.</param>
/// <returns>The rented object.</returns>
public TObject Rent(TCategory category) {
var obj = _pool.Rent(category);
if (_rented == null) _rented = _dictPool.Rent();
_rented.Add(obj, category);
return obj;
}
/// <summary>
/// Returns a rented object to the pool.
/// </summary>
/// <param name="obj">The object to return.</param>
public void Return(TObject obj) {
_pool.Return(_rented[obj], obj);
_rented.Remove(obj);
}
/// <summary>
/// Returns all objects rented by this accessor to the pool.
/// </summary>
public void ReturnAll() {
if (_rented == null) return;
foreach (var obj in _rented) {
_pool.Return(obj.Value, obj.Key);
}
_rented.Clear();
_dictPool.Return(_rented);
_rented = null;
}
}
}

View File

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

View File

@@ -14,6 +14,10 @@
_objs = new T[capacity]; _objs = new T[capacity];
} }
/// <summary> /// <summary>
/// The count of objects rented from the pool.
/// </summary>
public int RentedCount { get { return _index; } }
/// <summary>
/// Rents a object from the pool. /// Rents a object from the pool.
/// </summary> /// </summary>
/// <returns>The rented object.</returns> /// <returns>The rented object.</returns>
@@ -24,6 +28,7 @@
_objs[_index++] = null; _objs[_index++] = null;
} }
if (obj == null) obj = Construct(); if (obj == null) obj = Construct();
else Reset(obj);
return obj; return obj;
} }
/// <summary> /// <summary>
@@ -38,5 +43,10 @@
/// </summary> /// </summary>
/// <returns>The new instance.</returns> /// <returns>The new instance.</returns>
protected abstract T Construct(); protected abstract T Construct();
/// <summary>
/// Resets an object.
/// </summary>
/// <param name="obj">The object.</param>
protected virtual void Reset(T obj) { }
} }
} }

View File

@@ -1,5 +1,6 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 215ebdd4cb9187741a2e24f5e7d8511d guid: c4ef48e4a4983de4e9c31483df2a918e
folderAsset: yes
DefaultImporter: DefaultImporter:
externalObjects: {} externalObjects: {}
userData: userData:

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

@@ -3,7 +3,6 @@ using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text;
namespace Cryville.Common.Font { namespace Cryville.Common.Font {
public abstract class FontFile : IEnumerable<Typeface> { public abstract class FontFile : IEnumerable<Typeface> {

View File

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

View File

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

View File

@@ -54,16 +54,13 @@ namespace Cryville.Common.Math {
return res; return res;
} }
/// <summary> /// <summary>
/// Creates a <see cref="System.Single" /> column vector and fills it with polynomial coefficients. /// Fills a <see cref="System.Single" /> column vector with polynomial coefficients.
/// </summary> /// </summary>
/// <param name="size">The size of the column vector.</param> /// <param name="vec">The column vector.</param>
/// <param name="num">The base number.</param> /// <param name="num">The base number.</param>
/// <returns>A <see cref="System.Single" /> column vector filled with polynomial coefficients.</returns> public static void FillWithPolynomialCoefficients(ColumnVector<float> vec, float num) {
public static ColumnVector<float> WithPolynomialCoefficients(int size, float num) { for (var i = 0; i < vec.Size; i++)
var m = new ColumnVector<float>(size); vec[i] = (float)System.Math.Pow(num, i);
for (var i = 0; i < size; i++)
m[i] = (float)System.Math.Pow(num, i);
return m;
} }
} }
} }

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,4 @@
using System; using UnsafeIL;
namespace Cryville.Common.Math { namespace Cryville.Common.Math {
/// <summary> /// <summary>
@@ -40,11 +40,11 @@ namespace Cryville.Common.Math {
/// </summary> /// </summary>
/// <typeparam name="T">The vector type.</typeparam> /// <typeparam name="T">The vector type.</typeparam>
/// <param name="v">The column vector.</param> /// <param name="v">The column vector.</param>
/// <param name="result">The result column vector.</param>
/// <param name="o">The column operator.</param> /// <param name="o">The column operator.</param>
/// <returns>The column vector eliminated.</returns> public void Eliminate<T>(ColumnVector<T> v, ColumnVector<T> result, IVectorOperator<T> o) {
public ColumnVector<T> Eliminate<T>(ColumnVector<T> v, IVectorOperator<T> o) {
int s = Size; int s = Size;
Array.Copy(content, buffer, Size * Size); FillBuffer();
for (int i = 0; i < s; i++) refl[i] = i; for (int i = 0; i < s; i++) refl[i] = i;
for (int r = 0; r < s; r++) { for (int r = 0; r < s; r++) {
for (int r0 = r; r0 < s; r0++) for (int r0 = r; r0 < s; r0++)
@@ -66,14 +66,17 @@ namespace Cryville.Common.Math {
v[or1] = o.Add(v[or1], o.ScalarMultiply(-sf1, v[or])); v[or1] = o.Add(v[or1], o.ScalarMultiply(-sf1, v[or]));
} }
} }
ColumnVector<T> res = new ColumnVector<T>(s);
for (int r2 = s - 1; r2 >= 0; r2--) { for (int r2 = s - 1; r2 >= 0; r2--) {
var v2 = v[refl[r2]]; var v2 = v[refl[r2]];
for (int c2 = r2 + 1; c2 < s; c2++) for (int c2 = r2 + 1; c2 < s; c2++)
v2 = o.Add(v2, o.ScalarMultiply(-buffer[refl[r2], c2], res[refl[c2]])); v2 = o.Add(v2, o.ScalarMultiply(-buffer[refl[r2], c2], result[refl[c2]]));
res[refl[r2]] = v2; result[refl[r2]] = v2;
}
}
unsafe void FillBuffer() {
fixed (void* ptrc = content, ptrb = buffer) {
Unsafe.CopyBlock(ptrb, ptrc, (uint)(Size * Size * sizeof(float)));
} }
return res;
} }
/// <summary> /// <summary>
/// Creates a square matrix and fills it with polynomial coefficients. /// Creates a square matrix and fills it with polynomial coefficients.

View File

@@ -1,7 +1,21 @@
using System; using System;
namespace Cryville.Common.Pdt { namespace Cryville.Common.Pdt {
/// <summary>
/// Indicates that the attributed member is an element list.
/// </summary>
/// <remarks>
/// <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 { } public class ElementListAttribute : Attribute { }
public class ComponentListAttribute : Attribute { }
/// <summary>
/// Indicates that the attributed member is a property list.
/// </summary>
/// <remarks>
/// <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 { } public class PropertyListAttribute : Attribute { }
} }

View File

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

View File

@@ -11,7 +11,7 @@ namespace Cryville.Common.Pdt {
/// <summary> /// <summary>
/// Whether the value of this expression is constant. /// Whether the value of this expression is constant.
/// </summary> /// </summary>
/// <remarks>The value of this property is <c>false</c> until it is optimized.</remarks> /// <remarks>The value of this property is <see langword="false" /> until it is optimized.</remarks>
public bool IsConstant { get; internal set; } public bool IsConstant { get; internal set; }
internal bool IsPotentialConstant; internal bool IsPotentialConstant;
internal PdtExpression(LinkedList<PdtInstruction> ins) { internal PdtExpression(LinkedList<PdtInstruction> ins) {
@@ -92,7 +92,7 @@ namespace Cryville.Common.Pdt {
} }
} }
public partial class PdtInterpreter { public partial class PdtInterpreter {
readonly static Dictionary<char, int> OP_PRIORITY = new Dictionary<char, int> { static readonly Dictionary<char, int> OP_PRIORITY = new Dictionary<char, int> {
{ '@', 7 }, { '@', 7 },
{ '*', 6 }, { '/', 6 }, { '%', 6 }, { '*', 6 }, { '/', 6 }, { '%', 6 },
{ '+', 5 }, { '-', 5 }, { '+', 5 }, { '-', 5 },
@@ -103,7 +103,7 @@ namespace Cryville.Common.Pdt {
{ ',', 0 }, { ',', 0 },
{ '$', -1 }, { '$', -1 },
}; };
readonly static Dictionary<char, int> OP_TYPE = new Dictionary<char, int> { static readonly Dictionary<char, int> OP_TYPE = new Dictionary<char, int> {
{ '@', 0 }, { '@', 0 },
{ '*', 0 }, { '/', 0 }, { '%', 0 }, { '*', 0 }, { '/', 0 }, { '%', 0 },
{ '+', 0 }, { '-', 0 }, { '+', 0 }, { '-', 0 },
@@ -115,7 +115,7 @@ namespace Cryville.Common.Pdt {
{ '$', -1 }, { '$', -1 },
}; };
readonly static PdtExpression _emptyexp; static readonly PdtExpression _emptyexp;
static PdtInterpreter() { static PdtInterpreter() {
var ins = new LinkedList<PdtInstruction>(); var ins = new LinkedList<PdtInstruction>();
ins.AddLast(new PdtInstruction.PushConstant( ins.AddLast(new PdtInstruction.PushConstant(
@@ -143,7 +143,7 @@ namespace Cryville.Common.Pdt {
public override string ToString() { public override string ToString() {
return string.Format("0x{0:x4}: {1}", Type, Value); return string.Format("0x{0:x4}: {1}", Type, Value);
} }
public readonly static PdtExpToken EmptyOperator = new PdtExpToken { public static readonly PdtExpToken EmptyOperator = new PdtExpToken {
Type = 0x0080, Type = 0x0080,
Value = "$", Value = "$",
}; };

View File

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

View File

@@ -1,4 +1,5 @@
using System; using Cryville.Common.Collections;
using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@@ -27,16 +28,16 @@ namespace Cryville.Common.Pdt {
/// <item><term><c>0x1000</c></term><description>End of Key</description></item> /// <item><term><c>0x1000</c></term><description>End of Key</description></item>
/// </list> /// </list>
/// </remarks> /// </remarks>
readonly static int[] cm = new int[] { static readonly int[] cm = new int[] {
// 0 1 2 3 4 5 6 7 8 9 A B C D E F // 0 1 2 3 4 5 6 7 8 9 A B C D E F
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0001, 0x0000, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0001, 0x0000, 0x0000, 0x0001, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0001, 0x0080, 0x0100, 0x0000, 0x0030, 0x0080, 0x0080, 0x0000, 0x0200, 0x0400, 0x0080, 0x0080, 0x0080, 0x0080, 0x0040, 0x0080, 0x0001, 0x0080, 0x0100, 0x0000, 0x0030, 0x0080, 0x0080, 0x0000, 0x0200, 0x0400, 0x0080, 0x0080, 0x0080, 0x0080, 0x0040, 0x0080,
0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x1000, 0x1800, 0x0080, 0x0080, 0x0080, 0x0030, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x1000, 0x1800, 0x0080, 0x0080, 0x0080, 0x0030,
0x0080, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0080, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030,
0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0000, 0x0000, 0x0000, 0x0000, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0000, 0x0080, 0x0000, 0x0080, 0x0030,
0x0000, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0000, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030,
0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x1000, 0x0080, 0x1000, 0x0000, 0x0000, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x1000, 0x0080, 0x1000, 0x0080, 0x0000,
}; };
/// <summary> /// <summary>
@@ -54,43 +55,92 @@ namespace Cryville.Common.Pdt {
/// <param name="binder">The binder.</param> /// <param name="binder">The binder.</param>
/// <returns>The interpreted object.</returns> /// <returns>The interpreted object.</returns>
public static T Interpret<T>(string src, Binder binder) { public static T Interpret<T>(string src, Binder binder) {
return (T)new PdtInterpreter(src, typeof(T), binder).Interpret(); return (T)new PdtInterpreter(src, binder).Interpret(typeof(T));
} }
/// <summary>
/// The source string.
/// </summary>
public string Source { get; private set; } public string Source { get; private set; }
readonly Type _type; Binder _binder;
readonly Binder _binder; /// <summary>
/// The current position in the string being parsed by the interpreter.
/// </summary>
public int Position { get; private set; } public int Position { get; private set; }
#pragma warning disable IDE1006 #pragma warning disable IDE1006
/// <summary>
/// The character at the current position.
/// </summary>
/// <exception cref="IndexOutOfRangeException">The end of the source string is reached.</exception>
protected char cc { get { return Source[Position]; } } protected char cc { get { return Source[Position]; } }
/// <summary>
/// The category of the character.
/// </summary>
/// <exception cref="IndexOutOfRangeException">The end of the source string is reached.</exception>
protected int ct { get { return cm[cc]; } } protected int ct { get { return cm[cc]; } }
protected string tokenb(int flag) { // Token Whitelist /// <summary>
/// Reads a token until a character of type <paramref name="flag" /> is met.
/// </summary>
/// <param name="flag">The type filter.</param>
/// <returns>A token from the current position (inclusive) to the next character of type <paramref name="flag" /> (exclusive).</returns>
/// <exception cref="IndexOutOfRangeException">No character of type <paramref name="flag" /> is met.</exception>
protected string tokenb(int flag) {
int sp = Position; int sp = Position;
while ((ct & flag) == 0) Position++; while ((ct & flag) == 0) Position++;
return Source.Substring(sp, Position - sp); return Source.Substring(sp, Position - sp);
} }
protected string tokenw(int flag) { // Token Whitelist /// <summary>
/// Reads a token until a character that is not of type <paramref name="flag" /> is met.
/// </summary>
/// <param name="flag">The type filter.</param>
/// <returns>A token from the current position (inclusive) to the next character that is not of type <paramref name="flag" /> (exclusive).</returns>
/// <exception cref="IndexOutOfRangeException">No character that is not of type <paramref name="flag" /> is met.</exception>
protected string tokenw(int flag) {
int sp = Position; int sp = Position;
while ((ct & flag) != 0) Position++; while ((ct & flag) != 0) Position++;
return Source.Substring(sp, Position - sp); return Source.Substring(sp, Position - sp);
} }
/// <summary>
/// Skips over whitespaces.
/// </summary>
/// <exception cref="IndexOutOfRangeException">The end of the source string is reached.</exception>
protected void ws() { protected void ws() {
while ((ct & 0x0001) != 0) Position++; while ((ct & 0x0001) != 0) Position++;
} }
#pragma warning restore IDE1006 #pragma warning restore IDE1006
/// <summary>
/// Reads the current character and increments the position.
/// </summary>
/// <returns>The current character.</returns>
/// <exception cref="IndexOutOfRangeException">The end of the source string is reached.</exception>
protected char GetChar() { protected char GetChar() {
char r = cc; char r = cc;
Position++; Position++;
return r; return r;
} }
/// <summary>
/// Reads an identifier.
/// </summary>
/// <returns>An identifier.</returns>
/// <exception cref="IndexOutOfRangeException">The end of the source string is reached.</exception>
protected string GetIdentifier() { protected string GetIdentifier() {
if ((ct & 0x0020) == 0) return ""; if ((ct & 0x0020) == 0) return "";
return tokenw(0x0010); return tokenw(0x0010);
} }
/// <summary>
/// Reads a number.
/// </summary>
/// <returns>A number.</returns>
/// <exception cref="IndexOutOfRangeException">The end of the source string is reached.</exception>
protected string GetNumber() { protected string GetNumber() {
return tokenw(0x0040); return tokenw(0x0040);
} }
/// <summary>
/// Reads a string.
/// </summary>
/// <returns>A string.</returns>
/// <exception cref="IndexOutOfRangeException">The end of the source string is reached.</exception>
protected string GetString() { protected string GetString() {
int sp = Position; int sp = Position;
do { do {
@@ -100,6 +150,11 @@ namespace Cryville.Common.Pdt {
Position++; Position++;
return Regex.Replace(Source.Substring(sp + 1, Position - sp - 2), @"\\(.)", "$1"); return Regex.Replace(Source.Substring(sp + 1, Position - sp - 2), @"\\(.)", "$1");
} }
/// <summary>
/// Reads an expression.
/// </summary>
/// <returns>An expression.</returns>
/// <exception cref="IndexOutOfRangeException">The end of the source string is reached.</exception>
protected PdtExpression GetExp() { protected PdtExpression GetExp() {
var ins = new LinkedList<PdtInstruction>(); var ins = new LinkedList<PdtInstruction>();
int _; int _;
@@ -112,23 +167,27 @@ namespace Cryville.Common.Pdt {
/// Creates an instance of the <see cref="PdtInterpreter" /> class. /// Creates an instance of the <see cref="PdtInterpreter" /> class.
/// </summary> /// </summary>
/// <param name="src">The source string.</param> /// <param name="src">The source string.</param>
/// <param name="type">The destination type.</param>
/// <param name="binder">The binder. May be <c>null</c>.</param> /// <param name="binder">The binder. May be <c>null</c>.</param>
public PdtInterpreter(string src, Type type, Binder binder) { public PdtInterpreter(string src, Binder binder) {
Source = src; Source = src;
_type = type;
_binder = binder; _binder = binder;
if (_binder == null) }
_binder = BinderAttribute.CreateBinderOfType(_type); int[] m_formatVersion;
public int[] GetFormatVersion() {
if (m_formatVersion == null) InterpretDirectives();
return m_formatVersion;
} }
/// <summary> /// <summary>
/// Interprets the source to an object. /// Interprets the source to an object.
/// </summary> /// </summary>
/// <param name="type">The output type.</param>
/// <returns>The interpreted object.</returns> /// <returns>The interpreted object.</returns>
public object Interpret() { public object Interpret(Type type) {
try { try {
InterpretDirectives(); if (m_formatVersion == null) InterpretDirectives();
return InterpretObject(_type); if (_binder == null)
_binder = BinderAttribute.CreateBinderOfType(type);
return InterpretObject(type);
} }
catch (Exception ex) { catch (Exception ex) {
throw new PdtParsingException(this, ex); throw new PdtParsingException(this, ex);
@@ -146,7 +205,10 @@ namespace Cryville.Common.Pdt {
break; break;
case "format": case "format":
ws(); ws();
if (GetNumber() != "1") m_formatVersion = (from i in GetNumber().Split('.') select int.Parse(i)).ToArray();
if (m_formatVersion.Length == 0)
throw new FormatException("Invalid format version");
if (m_formatVersion[0] != 1)
throw new NotSupportedException("Format not supported"); throw new NotSupportedException("Format not supported");
flag = true; flag = true;
break; break;
@@ -167,10 +229,14 @@ namespace Cryville.Common.Pdt {
} }
object InterpretObject(Type type) { object InterpretObject(Type type) {
var result = ReflectionHelper.InvokeEmptyConstructor(type); var result = ReflectionHelper.InvokeEmptyConstructor(type);
bool dictflag = ReflectionHelper.IsGenericDictionary(type); bool dictflag = typeof(IDictionary).IsAssignableFrom(type);
while (true) { while (true) {
try { ws(); } try { ws(); }
catch (IndexOutOfRangeException) { return result; } catch (IndexOutOfRangeException) { return result; }
if (cc == '}') {
GetChar();
return result;
}
object pkey = InterpretKey(type); object pkey = InterpretKey(type);
char c = GetChar(); char c = GetChar();
switch (c) { switch (c) {
@@ -183,19 +249,20 @@ namespace Cryville.Common.Pdt {
((IDictionary)result).Add(key, value); ((IDictionary)result).Add(key, value);
} }
else { else {
MemberInfo prop; MemberInfo prop = null;
bool flag = ReflectionHelper.TryFindMemberWithAttribute<ElementListAttribute>(type, out prop); bool flag = false;
if (!flag && pkey is string) prop = ReflectionHelper.GetMember(type, (string)pkey); if (pkey is string) prop = ReflectionHelper.GetMember(type, (string)pkey);
if (prop == null) flag = ReflectionHelper.TryFindMemberWithAttribute<ElementListAttribute>(type, out prop);
if (prop == null) throw new MissingMemberException(string.Format("The property \"{0}\" is not found", pkey));
Type ptype = ReflectionHelper.GetMemberType(prop); Type ptype = ReflectionHelper.GetMemberType(prop);
if (ReflectionHelper.IsGenericDictionary(ptype)) { if (flag) {
using (var collection = new PairCollection(ReflectionHelper.GetValue(prop, result))) {
var ktype = ptype.GetGenericArguments()[0]; var ktype = ptype.GetGenericArguments()[0];
var vtype = ptype.GetGenericArguments()[1]; var vtype = ptype.GetGenericArguments()[1];
if (flag) {
object key = _binder.ChangeType(pkey, ktype, null); object key = _binder.ChangeType(pkey, ktype, null);
object value = InterpretObject(vtype); object value = InterpretObject(vtype);
((IDictionary)ReflectionHelper.GetValue(prop, result)).Add(key, value); collection.Add(key, value);
} }
else ReflectionHelper.SetValue(prop, result, InterpretObject(ptype));
} }
else ReflectionHelper.SetValue(prop, result, InterpretObject(ptype)); else ReflectionHelper.SetValue(prop, result, InterpretObject(ptype));
} }
@@ -211,28 +278,36 @@ namespace Cryville.Common.Pdt {
((IDictionary)result).Add(key, value); ((IDictionary)result).Add(key, value);
} }
else { else {
MemberInfo prop; MemberInfo prop = null;
bool flag = ReflectionHelper.TryFindMemberWithAttribute<PropertyListAttribute>(type, out prop); bool flag = false;
if (!flag && pkey is string) prop = ReflectionHelper.GetMember(type, (string)pkey); if (pkey is string) prop = ReflectionHelper.GetMember(type, (string)pkey);
if (prop == null) flag = ReflectionHelper.TryFindMemberWithAttribute<PropertyListAttribute>(type, out prop);
if (prop == null) throw new MissingMemberException(string.Format("The property \"{0}\" is not found", pkey));
var ptype = ReflectionHelper.GetMemberType(prop); var ptype = ReflectionHelper.GetMemberType(prop);
if (!typeof(IDictionary).IsAssignableFrom(ptype)) { if (flag) {
object value = _binder.ChangeType(exp, ptype, null); using (var collection = new PairCollection(ReflectionHelper.GetValue(prop, result))) {
ReflectionHelper.SetValue(prop, result, value, _binder);
}
else {
var ktype = ptype.GetGenericArguments()[0]; var ktype = ptype.GetGenericArguments()[0];
var vtype = ptype.GetGenericArguments()[1]; var vtype = ptype.GetGenericArguments()[1];
object key = _binder.ChangeType(pkey, ktype, null); object key = _binder.ChangeType(pkey, ktype, null);
object value = _binder.ChangeType(exp, vtype, null); object value = _binder.ChangeType(exp, vtype, null);
((IDictionary)ReflectionHelper.GetValue(prop, result)).Add(key, value); collection.Add(key, value);
}
}
else {
object value = _binder.ChangeType(exp, ptype, null);
ReflectionHelper.SetValue(prop, result, value, _binder);
} }
} }
break; break;
case '}': default:
return result; throw new InvalidOperationException("Internal error: Invalid key interpretation");
} }
} }
} }
/// <summary>
/// Interprets a key from the current position.
/// </summary>
/// <returns>The interpreted key.</returns>
protected virtual object InterpretKey(Type type) { protected virtual object InterpretKey(Type type) {
return tokenb(0x1000).Trim(); return tokenb(0x1000).Trim();
} }

View File

@@ -4,14 +4,14 @@ namespace Cryville.Common.Pdt {
/// <summary> /// <summary>
/// PDT operator. /// PDT operator.
/// </summary> /// </summary>
public unsafe abstract class PdtOperator { public abstract unsafe class PdtOperator {
byte* _prmem; byte* _prmem;
int _loadindex; int _loadindex;
readonly PdtVariableMemory[] _operands; readonly PdtVariableMemory[] _operands;
/// <summary> /// <summary>
/// The count of the operands loaded. /// The count of the operands loaded.
/// </summary> /// </summary>
protected int LoadedOperandCount { get { return ParamCount - _loadindex; } } protected int LoadedOperandCount { get; private set; }
/// <summary> /// <summary>
/// Gets the operand at the specified index. /// Gets the operand at the specified index.
/// </summary> /// </summary>
@@ -24,24 +24,24 @@ namespace Cryville.Common.Pdt {
int i = index + _loadindex; int i = index + _loadindex;
return _operands[i]; return _operands[i];
} }
internal int ParamCount { get; private set; } readonly int _pc;
/// <summary> /// <summary>
/// Creates an instance of the <see cref="PdtOperator" /> class. /// Creates an instance of the <see cref="PdtOperator" /> class.
/// </summary> /// </summary>
/// <param name="pc">The suggested parameter count.</param> /// <param name="pc">The suggested parameter count.</param>
protected PdtOperator(int pc) { protected PdtOperator(int pc) {
ParamCount = pc; _pc = pc;
_operands = new PdtVariableMemory[pc]; _operands = new PdtVariableMemory[pc];
} }
PdtEvaluatorBase _etor; PdtEvaluatorBase _etor;
bool _rfreq = true; bool _rfreq = true;
internal void Begin(PdtEvaluatorBase etor) { internal void Begin(PdtEvaluatorBase etor, int pc) {
_etor = etor; _etor = etor;
_loadindex = ParamCount; _loadindex = LoadedOperandCount = pc;
} }
internal void LoadOperand(PdtVariableMemory mem) { internal void LoadOperand(PdtVariableMemory mem) {
if (_loadindex == 0) return; if (--_loadindex >= _pc) return;
_operands[--_loadindex] = mem; _operands[_loadindex] = mem;
} }
internal void Call(byte* prmem, bool noset) { internal void Call(byte* prmem, bool noset) {
_prmem = prmem; _prmem = prmem;
@@ -55,6 +55,9 @@ namespace Cryville.Common.Pdt {
/// <summary> /// <summary>
/// Executes the operator. /// Executes the operator.
/// </summary> /// </summary>
/// <remarks>
/// <para>When overridden, this method reads operands by calling <see cref="GetOperand(int)" />, and writes the result to the frame obtained by calling <see cref="GetReturnFrame(int, int)" />.</para>
/// </remarks>
protected abstract void Execute(); protected abstract void Execute();
/// <summary> /// <summary>
/// Gets a return frame. /// Gets a return frame.

View File

@@ -1,4 +1,5 @@
using System; using System;
using UnsafeIL;
namespace Cryville.Common.Pdt { namespace Cryville.Common.Pdt {
/// <summary> /// <summary>
@@ -42,7 +43,9 @@ namespace Cryville.Common.Pdt {
/// <param name="dest">The destination buffer.</param> /// <param name="dest">The destination buffer.</param>
/// <param name="destOffset">The offset on the destination buffer to start copying to.</param> /// <param name="destOffset">The offset on the destination buffer to start copying to.</param>
/// <param name="length">The length to copy.</param> /// <param name="length">The length to copy.</param>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="length" /> is greater than the length of the span.</exception>
public void CopyTo(byte* dest, int destOffset, int length) { public void CopyTo(byte* dest, int destOffset, int length) {
if (length > Length) throw new ArgumentOutOfRangeException("length");
for (int i = 0; i < length; i++) for (int i = 0; i < length; i++)
dest[destOffset + i] = _ptr[i]; dest[destOffset + i] = _ptr[i];
} }
@@ -126,10 +129,43 @@ namespace Cryville.Common.Pdt {
throw new InvalidCastException("Not an identifier"); throw new InvalidCastException("Not an identifier");
return *(int*)(_ptr + offset); return *(int*)(_ptr + offset);
} }
internal void* TrustedAsOfLength(int len) { /// <summary>
if (Length < len) /// Gets the memory of the span as an instance of the specified type.
throw new InvalidCastException("Type not matched"); /// </summary>
return _ptr; /// <typeparam name="T">The specified type.</typeparam>
/// <param name="offset">The offset on the span to start reading from.</param>
/// <returns>An instance of the specified type.</returns>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="offset" /> is not less than the length of the span.</exception>
/// <exception cref="InvalidCastException">The length of the span is not sufficient.</exception>
/// <remarks>
/// <para>Use <see cref="AsNumber(int)" /> instead while reading an unaligned number.</para>
/// </remarks>
public T As<T>(int offset = 0) {
var len = Unsafe.SizeOf<T>();
if (offset >= Length)
throw new ArgumentOutOfRangeException("offset");
if (offset + len > Length)
throw new InvalidCastException("Frame length not sufficient");
return Unsafe.Read<T>(_ptr + offset);
}
/// <summary>
/// Sets the memory of the span to an instance of the specified type.
/// </summary>
/// <typeparam name="T">The specified type.</typeparam>
/// <param name="value">The value.</param>
/// <param name="offset">The offset from the start of the span.</param>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="offset" /> is not less than the length of the span.</exception>
/// <exception cref="InvalidCastException">The length of the span is not sufficient.</exception>
/// <remarks>
/// <para>Use <see cref="SetNumber(float, int)" /> instead while writing an unaligned number.</para>
/// </remarks>
public void Set<T>(T value, int offset = 0) {
var len = Unsafe.SizeOf<T>();
if (offset >= Length)
throw new ArgumentOutOfRangeException("offset");
if (offset + len > Length)
throw new InvalidCastException("Frame length not sufficient");
Unsafe.Write(_ptr + offset, value);
} }
/// <summary> /// <summary>
/// Gets the array suffix. /// Gets the array suffix.

View File

@@ -0,0 +1,10 @@
using UnityEngine;
namespace Cryville.Common.Unity.UI {
public class SetIntegerParameterBehaviour : SetParameterBehaviour {
[SerializeField] int m_value;
public override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) {
animator.SetInteger(m_name, m_value);
}
}
}

View File

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

View File

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

View File

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

View File

@@ -45,7 +45,7 @@ namespace Cryville.Common.Unity.UI {
} }
static MethodInfo _methodCreateFontAsset; static MethodInfo _methodCreateFontAsset;
static object[] _paramsCreateFontAsset = new object[] { null, null, 90, 9, GlyphRenderMode.SDFAA, 1024, 1024, Type.Missing, Type.Missing }; static readonly object[] _paramsCreateFontAsset = new object[] { null, null, 90, 9, GlyphRenderMode.SDFAA, 1024, 1024, Type.Missing, Type.Missing };
static FontAsset CreateFontAsset(string path, int index) { static FontAsset CreateFontAsset(string path, int index) {
if (_methodCreateFontAsset == null) { if (_methodCreateFontAsset == null) {
_methodCreateFontAsset = typeof(FontAsset).GetMethod( _methodCreateFontAsset = typeof(FontAsset).GetMethod(

View File

@@ -1,5 +1,4 @@
using System; using System.Collections.Generic;
using System.Collections.Generic;
namespace Cryville.Crtr.Browsing { namespace Cryville.Crtr.Browsing {
public abstract class ExtensionInterface { public abstract class ExtensionInterface {

View File

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

View File

@@ -1,5 +1,6 @@
using Cryville.Common; using Cryville.Common;
using Cryville.Common.Unity.UI; using Cryville.Common.Unity.UI;
using Cryville.Crtr.Config;
using Newtonsoft.Json; using Newtonsoft.Json;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
@@ -12,11 +13,12 @@ namespace Cryville.Crtr.Browsing {
private Button m_playButton; private Button m_playButton;
[SerializeField] [SerializeField]
private Button m_configButton; private Button m_configButton;
[SerializeField]
private ConfigPanelMaster m_configPanel;
private DockLayoutGroup _group; private DockLayoutGroup _group;
public ResourceBrowser MainBrowser { get; private set; } public ResourceBrowser MainBrowser { get; private set; }
private DetailPanel _detailPanel; private DetailPanel _detailPanel;
private SettingsPanel _settingsPanel;
readonly List<ResourceBrowserUnit> _units = new List<ResourceBrowserUnit>(); readonly List<ResourceBrowserUnit> _units = new List<ResourceBrowserUnit>();
#pragma warning disable IDE0051 #pragma warning disable IDE0051
@@ -25,7 +27,6 @@ namespace Cryville.Crtr.Browsing {
MainBrowser = transform.GetChild(0).GetComponent<ResourceBrowser>(); MainBrowser = transform.GetChild(0).GetComponent<ResourceBrowser>();
MainBrowser.ResourceManager = new LegacyResourceManager(Settings.Default.GameDataPath); MainBrowser.ResourceManager = new LegacyResourceManager(Settings.Default.GameDataPath);
_detailPanel = transform.GetChild(1).GetComponent<DetailPanel>(); _detailPanel = transform.GetChild(1).GetComponent<DetailPanel>();
_settingsPanel = transform.GetChild(2).GetComponent<SettingsPanel>();
_units.Add(MainBrowser); _units.Add(MainBrowser);
_units.Add(_detailPanel); _units.Add(_detailPanel);
} }
@@ -80,12 +81,6 @@ namespace Cryville.Crtr.Browsing {
public void OpenConfig(int id, ChartDetail detail) { public void OpenConfig(int id, ChartDetail detail) {
SetDataSettings(id, detail); SetDataSettings(id, detail);
#if UNITY_5_3_OR_NEWER
SceneManager.LoadScene("Config", LoadSceneMode.Additive);
#else
Application.LoadLevelAdditive("Config");
#endif
GameObject.Find("/Master").GetComponent<Master>().HideMenu();
} }
void SetDataSettings(int id, ChartDetail detail) { void SetDataSettings(int id, ChartDetail detail) {

View File

@@ -6,6 +6,7 @@ using System.ComponentModel;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using UnsafeIL;
namespace Cryville.Crtr { namespace Cryville.Crtr {
[JsonConverter(typeof(BeatTimeConverter))] [JsonConverter(typeof(BeatTimeConverter))]
@@ -109,9 +110,10 @@ namespace Cryville.Crtr {
public float BeatOffset; public float BeatOffset;
[JsonIgnore] [JsonIgnore]
public abstract int Priority { public abstract int Priority { get; }
get;
} [JsonIgnore]
public virtual bool Standalone { get { return false; } }
public ChartEvent Clone() { public ChartEvent Clone() {
return (ChartEvent)MemberwiseClone(); return (ChartEvent)MemberwiseClone();
@@ -153,6 +155,10 @@ namespace Cryville.Crtr {
protected ChartEvent() { protected ChartEvent() {
PropSrcs = new Dictionary<int, PropSrc>(); PropSrcs = new Dictionary<int, PropSrc>();
PropOps = new Dictionary<int, PropOp>(); PropOps = new Dictionary<int, PropOp>();
SubmitPropSrc("event", new PropSrc.Float(() => {
int hash = GetHashCode();
return Unsafe.As<int, float>(ref hash);
}));
SubmitPropSrc("long", new PropSrc.Boolean(() => IsLong)); SubmitPropSrc("long", new PropSrc.Boolean(() => IsLong));
SubmitPropSrc("time", new PropSrc.BeatTime(() => time.Value)); SubmitPropSrc("time", new PropSrc.BeatTime(() => time.Value));
SubmitPropSrc("endtime", new PropSrc.BeatTime(() => endtime.Value)); SubmitPropSrc("endtime", new PropSrc.BeatTime(() => endtime.Value));
@@ -259,9 +265,7 @@ namespace Cryville.Crtr {
} }
} }
public override int Priority { public override int Priority { get { return 10; } }
get { return 10; }
}
public class Group : EventContainer { public class Group : EventContainer {
public List<Track> tracks = new List<Track>(); public List<Track> tracks = new List<Track>();
@@ -281,15 +285,11 @@ namespace Cryville.Crtr {
default: return base.GetEventsOfType(type); default: return base.GetEventsOfType(type);
} }
} }
public override int Priority { public override int Priority { get { return 10; } }
get { return 10; }
}
} }
public class Track : EventContainer { public class Track : EventContainer {
public override int Priority { public override int Priority { get { return 10; } }
get { return 10; }
}
} }
public class Motion : ChartEvent { public class Motion : ChartEvent {
@@ -325,7 +325,7 @@ namespace Cryville.Crtr {
else { else {
AbsoluteValue = Vector.Construct(registry.Type, m.Groups[11].Value); AbsoluteValue = Vector.Construct(registry.Type, m.Groups[11].Value);
} }
SubmitPropSrc("value", VectorSrc.Construct(() => { SubmitPropSrc("value", new VectorSrc(() => {
if (RelativeNode != null) return RelativeNode.Value; if (RelativeNode != null) return RelativeNode.Value;
else return AbsoluteValue; else return AbsoluteValue;
})); }));
@@ -375,9 +375,7 @@ namespace Cryville.Crtr {
[DefaultValue(0.0f)] [DefaultValue(0.0f)]
public float sumfix = 0.0f; public float sumfix = 0.0f;
public override int Priority { public override int Priority { get { return -2; } }
get { return -2; }
}
public Motion() { public Motion() {
SubmitPropOp("motion", new PropOp.String(v => motion = v)); SubmitPropOp("motion", new PropOp.String(v => motion = v));
@@ -413,9 +411,7 @@ namespace Cryville.Crtr {
default: return base.GetEventsOfType(type); default: return base.GetEventsOfType(type);
} }
} }
public override int Priority { public override int Priority { get { return 12; } }
get { return 12; }
}
} }
public class Judge : ChartEvent { public class Judge : ChartEvent {
@@ -428,9 +424,8 @@ namespace Cryville.Crtr {
} }
#pragma warning restore IDE1006 #pragma warning restore IDE1006
public override int Priority { public override int Priority { get { return 0; } }
get { return 0; } public override bool Standalone { get { return true; } }
}
public Judge() { public Judge() {
SubmitPropSrc("name", new PropSrc.Identifier(() => Id.Key)); SubmitPropSrc("name", new PropSrc.Identifier(() => Id.Key));
@@ -444,9 +439,7 @@ namespace Cryville.Crtr {
public class Signature : ChartEvent { public class Signature : ChartEvent {
public float? tempo; public float? tempo;
public override int Priority { public override int Priority { get { return -4; } }
get { return -4; }
}
} }
public List<Sound> sounds; public List<Sound> sounds;
@@ -457,9 +450,7 @@ namespace Cryville.Crtr {
// TODO [Obsolete] // TODO [Obsolete]
public float offset; public float offset;
public override int Priority { public override int Priority { get { return 0; } }
get { return 0; }
}
} }
} }
} }

View File

@@ -16,7 +16,6 @@ using UnityEngine;
using UnityEngine.Networking; using UnityEngine.Networking;
using UnityEngine.SceneManagement; using UnityEngine.SceneManagement;
using UnityEngine.Scripting; using UnityEngine.Scripting;
using UnityEngine.UI;
using diag = System.Diagnostics; using diag = System.Diagnostics;
using Logger = Cryville.Common.Logger; using Logger = Cryville.Common.Logger;
@@ -25,7 +24,7 @@ namespace Cryville.Crtr {
#region Fields #region Fields
Chart chart; Chart chart;
Skin skin; Skin skin;
PdtSkin pskin; public static PdtSkin pskin;
Ruleset ruleset; Ruleset ruleset;
PdtRuleset pruleset; PdtRuleset pruleset;
Dictionary<string, Texture2D> texs; Dictionary<string, Texture2D> texs;
@@ -43,14 +42,14 @@ namespace Cryville.Crtr {
EventBus bbus; EventBus bbus;
EventBus tbus; EventBus tbus;
EventBus nbus; EventBus nbus;
InputProxy inputProxy;
Judge judge; Judge judge;
public static EffectManager effectManager;
bool started = false; bool started = false;
static bool initialized; static bool initialized;
static Text logs; TextMeshProUGUI logs;
TextMeshProUGUI status; TextMeshProUGUI status;
readonly TargetString statusstr = new TargetString();
readonly StringBuffer statusbuf = new StringBuffer();
static Vector2 screenSize; static Vector2 screenSize;
public static Rect hitRect; public static Rect hitRect;
@@ -63,6 +62,7 @@ namespace Cryville.Crtr {
static double renderStep = 0.05; static double renderStep = 0.05;
public static double actualRenderStep = 0; public static double actualRenderStep = 0;
static bool autoRenderStep = false; static bool autoRenderStep = false;
public static float graphicalOffset = 0;
public static float soundOffset = 0; public static float soundOffset = 0;
static float startOffset = 0; static float startOffset = 0;
public static float sv = 16f; public static float sv = 16f;
@@ -70,15 +70,15 @@ namespace Cryville.Crtr {
public static Dictionary<Identifier, MotionRegistry> motionRegistry = new Dictionary<Identifier, MotionRegistry>(); public static Dictionary<Identifier, MotionRegistry> motionRegistry = new Dictionary<Identifier, MotionRegistry>();
public static PdtEvaluator etor; public static PdtEvaluator etor;
InputProxy inputProxy;
#endregion #endregion
#region MonoBehaviour #region MonoBehaviour
void Start() { void Start() {
d_addLogEntry = new Action<int, string, string>(AddLogEntry);
var logobj = GameObject.Find("Logs"); var logobj = GameObject.Find("Logs");
if (logobj != null) if (logobj != null)
logs = logobj.GetComponent<Text>(); logs = logobj.GetComponent<TextMeshProUGUI>();
if (!initialized) { if (!initialized) {
Game.Init(); Game.Init();
GenericResources.LoadDefault(); GenericResources.LoadDefault();
@@ -133,7 +133,7 @@ namespace Cryville.Crtr {
if (forceSyncFrames != 0) { if (forceSyncFrames != 0) {
forceSyncFrames--; forceSyncFrames--;
double target = Game.AudioClient.Position - atime0; double target = Game.AudioClient.Position - atime0;
dt = target - cbus.Time; dt = target - cbus.Time - graphicalOffset;
step = autoRenderStep ? 1f / Application.targetFrameRate : renderStep; step = autoRenderStep ? 1f / Application.targetFrameRate : renderStep;
inputProxy.SyncTime(target); inputProxy.SyncTime(target);
} }
@@ -142,6 +142,7 @@ namespace Cryville.Crtr {
step = autoRenderStep ? Time.smoothDeltaTime : renderStep; step = autoRenderStep ? Time.smoothDeltaTime : renderStep;
} }
inputProxy.ForceTick(); inputProxy.ForceTick();
if (paused) return;
cbus.ForwardByTime(dt); cbus.ForwardByTime(dt);
bbus.ForwardByTime(dt); bbus.ForwardByTime(dt);
UnityEngine.Profiling.Profiler.BeginSample("ChartPlayer.Forward"); UnityEngine.Profiling.Profiler.BeginSample("ChartPlayer.Forward");
@@ -160,6 +161,8 @@ namespace Cryville.Crtr {
tbus.ForwardStepByTime(renderDist, step); tbus.ForwardStepByTime(renderDist, step);
tbus.EndGraphicalUpdate(); tbus.EndGraphicalUpdate();
UnityEngine.Profiling.Profiler.EndSample(); UnityEngine.Profiling.Profiler.EndSample();
effectManager.Tick(cbus.Time);
} }
catch (Exception ex) { catch (Exception ex) {
Game.LogException("Game", "An error occured while playing", ex); Game.LogException("Game", "An error occured while playing", ex);
@@ -172,10 +175,21 @@ namespace Cryville.Crtr {
string url = texLoader.url; string url = texLoader.url;
string name = StringUtils.TrimExt(url.Substring(url.LastIndexOfAny(new char[] {'/', '\\'}) + 1)); string name = StringUtils.TrimExt(url.Substring(url.LastIndexOfAny(new char[] {'/', '\\'}) + 1));
#if UNITY_5_4_OR_NEWER #if UNITY_5_4_OR_NEWER
if (texLoader.isDone) {
if (texHandler.isDone) { if (texHandler.isDone) {
var tex = texHandler.texture; var tex = texHandler.texture;
tex.wrapMode = TextureWrapMode.Clamp; 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); texs.Add(name, tex);
}
else {
Logger.Log("main", 4, "Load/Prehandle", "Unable to load texture: {0}", name);
}
texLoader.Dispose(); texLoader.Dispose();
texHandler.Dispose(); texHandler.Dispose();
texLoader = null; texLoader = null;
@@ -190,7 +204,7 @@ namespace Cryville.Crtr {
} }
#endif #endif
} }
if (texLoader == null) if (texLoader == null) {
if (texLoadQueue.Count > 0) { if (texLoadQueue.Count > 0) {
#if UNITY_5_4_OR_NEWER #if UNITY_5_4_OR_NEWER
texHandler = new DownloadHandlerTexture(); texHandler = new DownloadHandlerTexture();
@@ -205,6 +219,7 @@ namespace Cryville.Crtr {
texloadtimer.Stop(); texloadtimer.Stop();
Logger.Log("main", 1, "Load/MainThread", "Main thread done ({0}ms)", texloadtimer.Elapsed.TotalMilliseconds); Logger.Log("main", 1, "Load/MainThread", "Main thread done ({0}ms)", texloadtimer.Elapsed.TotalMilliseconds);
} }
}
if (!loadThread.IsAlive) { if (!loadThread.IsAlive) {
if (threadException != null) { if (threadException != null) {
Logger.Log("main", 4, "Load/MainThread", "Load failed"); Logger.Log("main", 4, "Load/MainThread", "Load failed");
@@ -220,9 +235,14 @@ namespace Cryville.Crtr {
} }
} }
} }
void LogUpdate() { readonly TargetString statusstr = new TargetString();
string _logs = logs.text; readonly StringBuffer statusbuf = new StringBuffer();
Game.MainLogger.Enumerate((level, module, msg) => { readonly TargetString logsstr = new TargetString();
readonly StringBuffer logsbuf = new StringBuffer();
readonly List<string> logEntries = new List<string>();
int logsLength = 0;
Action<int, string, string> d_addLogEntry;
void AddLogEntry(int level, string module, string msg) {
string color; string color;
switch (level) { switch (level) {
case 0: color = "#888888"; break; case 0: color = "#888888"; break;
@@ -233,12 +253,28 @@ namespace Cryville.Crtr {
case 5: color = "#bb0000"; break; case 5: color = "#bb0000"; break;
default: color = "#ff00ff"; break; default: color = "#ff00ff"; break;
} }
_logs += string.Format( var l = string.Format(
"\r\n<color={1}bb><{2}> {3}</color>", "\n<color={1}bb><{2}> {3}</color>",
DateTime.UtcNow.ToString("s"), color, module, msg DateTime.UtcNow.ToString("s"), color, module, msg
); );
}); logEntries.Add(l);
logs.text = _logs.Substring(Mathf.Max(0, _logs.IndexOf('\n', Mathf.Max(0, _logs.Length - 4096)))); logsLength += l.Length;
}
void LogUpdate() {
logsbuf.Clear();
Game.MainLogger.Enumerate(d_addLogEntry);
while (logsLength >= 4096) {
logsLength -= logEntries[0].Length;
logEntries.RemoveAt(0);
}
foreach (var l in logEntries) {
logsbuf.Append(l);
}
logsstr.Length = logsbuf.Count;
var larr = logsstr.TrustedAsArray();
logsbuf.CopyTo(0, larr, 0, logsbuf.Count);
logs.SetText(larr, 0, logsbuf.Count);
statusbuf.Clear(); statusbuf.Clear();
statusbuf.AppendFormat( statusbuf.AppendFormat(
"FPS: i{0:0} / s{1:0}\nSMem: {2:N0} / {3:N0}\nIMem: {4:N0} / {5:N0}", "FPS: i{0:0} / s{1:0}\nSMem: {2:N0} / {3:N0}\nIMem: {4:N0} / {5:N0}",
@@ -258,15 +294,19 @@ namespace Cryville.Crtr {
); );
if (started) { if (started) {
statusbuf.AppendFormat( statusbuf.AppendFormat(
"\nStates: c{0} / b{1}", "\nStates: c{0} / b{1}\nPools: RMV {2}, MC {3}",
cbus.ActiveStateCount, bbus.ActiveStateCount cbus.ActiveStateCount, bbus.ActiveStateCount,
ContainerState.RMVPool.RentedCount,
ContainerState.MCPool.RentedCount
); );
statusbuf.AppendFormat( statusbuf.AppendFormat(
"\nSTime: {0:G17}s {3}\ndATime: {1:+0.0ms;-0.0ms;0} {3}\ndITime: {2:+0.0ms;-0.0ms;0} {3}", "\nSTime: {0:G17}s {3} {4}\ndATime: {1:+0.0ms;-0.0ms;0} {3} {4}\ndITime: {2:+0.0ms;-0.0ms;0} {3} {5}",
cbus.Time, cbus.Time,
(Game.AudioClient.Position - atime0 - cbus.Time) * 1e3, (Game.AudioClient.Position - atime0 - cbus.Time) * 1e3,
(inputProxy.GetTimestampAverage() - cbus.Time) * 1e3, (inputProxy.GetTimestampAverage() - cbus.Time) * 1e3,
forceSyncFrames != 0 ? "(force sync)" : "" forceSyncFrames != 0 ? "(force sync)" : "",
paused ? "(paused)" : "",
paused ? "(semi-locked)" : ""
); );
if (judge != null) { if (judge != null) {
statusbuf.Append("\n== Scores ==\n"); statusbuf.Append("\n== Scores ==\n");
@@ -275,9 +315,9 @@ namespace Cryville.Crtr {
} }
} }
statusstr.Length = statusbuf.Count; statusstr.Length = statusbuf.Count;
var arr = statusstr.TrustedAsArray(); var sarr = statusstr.TrustedAsArray();
statusbuf.CopyTo(0, arr, 0, statusbuf.Count); statusbuf.CopyTo(0, sarr, 0, statusbuf.Count);
status.SetText(arr, 0, statusbuf.Count); status.SetText(sarr, 0, statusbuf.Count);
} }
#endregion #endregion
@@ -307,6 +347,8 @@ namespace Cryville.Crtr {
bool logEnabled = true; bool logEnabled = true;
public void ToggleLogs() { public void ToggleLogs() {
logEntries.Clear();
logsLength = 0;
logs.text = ""; logs.text = "";
status.SetText(""); status.SetText("");
logEnabled = !logEnabled; logEnabled = !logEnabled;
@@ -319,6 +361,20 @@ namespace Cryville.Crtr {
else Logger.Log("main", 2, "Load/MainThread", "The chart is currently loading"); else Logger.Log("main", 2, "Load/MainThread", "The chart is currently loading");
} }
} }
bool paused = false;
public void TogglePause() {
paused = !paused;
if (!paused) {
forceSyncFrames = Settings.Default.ForceSyncFrames;
Game.AudioClient.Start();
inputProxy.UnlockTime();
}
else {
Game.AudioClient.Pause();
inputProxy.LockTime();
}
}
#endregion #endregion
#region Load #region Load
@@ -329,6 +385,7 @@ namespace Cryville.Crtr {
renderStep = Settings.Default.RenderStep; renderStep = Settings.Default.RenderStep;
actualRenderStep = renderStep; actualRenderStep = renderStep;
autoRenderStep = renderStep == 0; autoRenderStep = renderStep == 0;
graphicalOffset = Settings.Default.GraphicalOffset;
soundOffset = Settings.Default.SoundOffset; soundOffset = Settings.Default.SoundOffset;
startOffset = Settings.Default.StartOffset; startOffset = Settings.Default.StartOffset;
forceSyncFrames = Settings.Default.ForceSyncFrames; forceSyncFrames = Settings.Default.ForceSyncFrames;
@@ -368,6 +425,7 @@ namespace Cryville.Crtr {
}); });
} }
sv = _rscfg.generic.ScrollVelocity; sv = _rscfg.generic.ScrollVelocity;
soundOffset += _rscfg.generic.SoundOffset;
FileInfo skinFile = new FileInfo( FileInfo skinFile = new FileInfo(
string.Format("{0}/skins/{1}/{2}/.umgs", Game.GameDataPath, rulesetFile.Directory.Name, _rscfg.generic.Skin) string.Format("{0}/skins/{1}/{2}/.umgs", Game.GameDataPath, rulesetFile.Directory.Name, _rscfg.generic.Skin)
@@ -402,16 +460,6 @@ namespace Cryville.Crtr {
try { try {
diag::Stopwatch timer = new diag::Stopwatch(); diag::Stopwatch timer = new diag::Stopwatch();
timer.Reset(); timer.Start(); timer.Reset(); timer.Start();
Logger.Log("main", 0, "Load/Prehandle", "Initializing textures");
foreach (var t in texs) {
if (frames.ContainsKey(t.Key)) {
Logger.Log("main", 3, "Load/Prehandle", "Duplicated texture name: {0}", t.Key);
continue;
}
var f = new SpriteFrame(t.Value);
f.Init();
frames.Add(t.Key, f);
}
Logger.Log("main", 0, "Load/Prehandle", "Prehandling (iteration 2)"); Logger.Log("main", 0, "Load/Prehandle", "Prehandling (iteration 2)");
cbus.BroadcastPreInit(); cbus.BroadcastPreInit();
Logger.Log("main", 0, "Load/Prehandle", "Prehandling (iteration 3)"); Logger.Log("main", 0, "Load/Prehandle", "Prehandling (iteration 3)");
@@ -425,15 +473,18 @@ namespace Cryville.Crtr {
Logger.Log("main", 0, "Load/Prehandle", "Cleaning up"); Logger.Log("main", 0, "Load/Prehandle", "Cleaning up");
GC.Collect(); GC.Collect();
if (disableGC) GarbageCollector.GCMode = GarbageCollector.Mode.Disabled; if (disableGC) GarbageCollector.GCMode = GarbageCollector.Mode.Disabled;
cbus.ForwardByTime(startOffset);
bbus.ForwardByTime(startOffset);
timer.Stop(); timer.Stop();
Logger.Log("main", 1, "Load/Prehandle", "Prehandling done ({0}ms)", timer.Elapsed.TotalMilliseconds); Logger.Log("main", 1, "Load/Prehandle", "Prehandling done ({0}ms)", timer.Elapsed.TotalMilliseconds);
if (Settings.Default.ClearLogOnPlay) { if (Settings.Default.ClearLogOnPlay) {
logs.text = ""; logEntries.Clear();
logsLength = 0;
Game.MainLogger.Enumerate((level, module, msg) => { }); Game.MainLogger.Enumerate((level, module, msg) => { });
logs.text = "";
} }
Game.AudioSequencer.Playing = true; Game.AudioSequencer.Playing = true;
atime0 = Game.AudioClient.BufferPosition; atime0 = Game.AudioClient.BufferPosition;
Thread.Sleep((int)((atime0 - Game.AudioClient.Position) * 1000));
inputProxy.SyncTime(cbus.Time); inputProxy.SyncTime(cbus.Time);
started = true; started = true;
} }
@@ -447,12 +498,16 @@ namespace Cryville.Crtr {
public void Stop() { public void Stop() {
try { try {
Logger.Log("main", 1, "Game", "Stopping"); Logger.Log("main", 1, "Game", "Stopping");
Game.AudioClient.Start();
Game.AudioSession = Game.AudioSequencer.NewSession(); Game.AudioSession = Game.AudioSequencer.NewSession();
inputProxy.Deactivate(); inputProxy.Deactivate();
if (nbus != null) { nbus.Dispose(); nbus = null; } if (nbus != null) { nbus.Dispose(); nbus = null; }
if (tbus != null) { tbus.Dispose(); tbus = null; } if (tbus != null) { tbus.Dispose(); tbus = null; }
if (bbus != null) { bbus.Dispose(); bbus = null; } if (bbus != null) { bbus.Dispose(); bbus = null; }
if (cbus != null) { cbus.Dispose(); cbus.DisposeAll(); cbus = null; } if (cbus != null) { cbus.Dispose(); cbus.DisposeAll(); cbus = null; }
effectManager.Dispose();
effectManager = null;
etor = null;
Logger.Log("main", 1, "Game", "Stopped"); Logger.Log("main", 1, "Game", "Stopped");
} }
catch (Exception ex) { catch (Exception ex) {
@@ -496,8 +551,6 @@ namespace Cryville.Crtr {
try { try {
workerTimer = new diag::Stopwatch(); workerTimer = new diag::Stopwatch();
workerTimer.Start(); workerTimer.Start();
RMVPool.Prepare();
MotionCachePool.Prepare();
LoadChart(info); LoadChart(info);
workerTimer.Stop(); workerTimer.Stop();
Logger.Log("main", 1, "Load/WorkerThread", "Worker thread done ({0}ms)", workerTimer.Elapsed.TotalMilliseconds); Logger.Log("main", 1, "Load/WorkerThread", "Worker thread done ({0}ms)", workerTimer.Elapsed.TotalMilliseconds);
@@ -533,12 +586,12 @@ namespace Cryville.Crtr {
LoadSkin(info.skinFile); LoadSkin(info.skinFile);
Logger.Log("main", 0, "Load/WorkerThread", "Initializing judge and input"); Logger.Log("main", 0, "Load/WorkerThread", "Initializing judge and input");
judge = new Judge(pruleset); judge = new Judge(this, pruleset);
etor.ContextJudge = judge; etor.ContextJudge = judge;
inputProxy = new InputProxy(pruleset, judge); inputProxy = new InputProxy(pruleset, judge);
inputProxy.LoadFrom(_rscfg.inputs); inputProxy.LoadFrom(_rscfg.inputs);
if (!inputProxy.IsCompleted) { if (!inputProxy.IsCompleted()) {
throw new ArgumentException("Input config not completed\nPlease complete the input settings"); throw new ArgumentException("Input config not completed\nPlease complete the input settings");
} }
@@ -586,6 +639,8 @@ namespace Cryville.Crtr {
pruleset = ruleset.Root; pruleset = ruleset.Root;
pruleset.Optimize(etor); pruleset.Optimize(etor);
} }
ContainerState.RMVPool = new RMVPool();
ContainerState.MCPool = new MotionCachePool();
} }
void LoadSkin(FileInfo file) { void LoadSkin(FileInfo file) {
@@ -594,6 +649,7 @@ namespace Cryville.Crtr {
skin.LoadPdt(dir); skin.LoadPdt(dir);
pskin = skin.Root; pskin = skin.Root;
pskin.Optimize(etor); pskin.Optimize(etor);
effectManager = new EffectManager(pskin);
} }
#endregion #endregion
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -16,19 +16,15 @@ namespace Cryville.Crtr.Components {
public op_set_bound(SpriteBase self) : base(2) { public op_set_bound(SpriteBase self) : base(2) {
_self = self; _self = self;
} }
protected unsafe override void Execute() { protected override void Execute() {
_self.SetBound( _self.SetBound(
*(Vector2*)GetOperand(0).TrustedAsOfLength(sizeof(Vector2)), GetOperand(0).As<Vector2>(),
*(Vector3*)GetOperand(1).TrustedAsOfLength(sizeof(Vector3)) GetOperand(1).As<Vector3>()
); );
} }
} }
#pragma warning restore IDE1006 #pragma warning restore IDE1006
protected override void OnDestroy() {
mesh.Destroy();
}
Vector2 _scale = Vector2.one; Vector2 _scale = Vector2.one;
public Vector2 Scale { public Vector2 Scale {
get { return _scale; } get { return _scale; }
@@ -92,7 +88,9 @@ namespace Cryville.Crtr.Components {
protected void InternalInit(string meshName = "quad") { protected void InternalInit(string meshName = "quad") {
mesh.Init(transform); mesh.Init(transform);
mesh.Renderer.sharedMaterials = materials = new Material[] { MeshWrapper.NewMaterial() };
mesh.Mesh = GenericResources.Meshes[meshName]; mesh.Mesh = GenericResources.Meshes[meshName];
UpdateColor();
UpdateScale(); UpdateScale();
UpdateZIndex(); UpdateZIndex();
} }

View File

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

View File

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

View File

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

View File

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

View File

@@ -3,11 +3,13 @@ using System;
using System.IO; using System.IO;
using System.Text; using System.Text;
using UnityEngine; using UnityEngine;
using UnityEngine.SceneManagement;
using Logger = Cryville.Common.Logger; using Logger = Cryville.Common.Logger;
namespace Cryville.Crtr.Config { namespace Cryville.Crtr.Config {
public class ConfigScene : MonoBehaviour { public class ConfigPanelMaster : MonoBehaviour {
[SerializeField]
Menu m_menu;
[SerializeField] [SerializeField]
Transform m_content; Transform m_content;
@@ -20,7 +22,7 @@ namespace Cryville.Crtr.Config {
public Ruleset ruleset; public Ruleset ruleset;
RulesetConfig _rscfg; RulesetConfig _rscfg;
void Start() { void OnEnable() {
try { try {
ChartPlayer.etor = new PdtEvaluator(); ChartPlayer.etor = new PdtEvaluator();
FileInfo file = new FileInfo( FileInfo file = new FileInfo(
@@ -57,11 +59,13 @@ namespace Cryville.Crtr.Config {
var proxy = new InputProxy(ruleset.Root, null); var proxy = new InputProxy(ruleset.Root, null);
proxy.LoadFrom(_rscfg.inputs); proxy.LoadFrom(_rscfg.inputs);
m_inputConfigPanel.proxy = proxy; m_inputConfigPanel.proxy = proxy;
m_inputConfigPanel.OnConfigEnable();
} }
catch (Exception ex) { catch (Exception ex) {
Popup.CreateException(ex); Popup.CreateException(ex);
Logger.Log("main", 4, "Config", "An error occured while loading the config: {0}", ex); Logger.Log("main", 4, "Config", "An error occured while loading the config: {0}", ex);
ReturnToMenu(); m_menu.Back();
} }
} }
@@ -72,7 +76,7 @@ namespace Cryville.Crtr.Config {
cat.SetActive(true); cat.SetActive(true);
} }
public void SaveAndReturnToMenu() { void OnDisable() {
m_inputConfigPanel.proxy.SaveTo(_rscfg.inputs); m_inputConfigPanel.proxy.SaveTo(_rscfg.inputs);
m_inputConfigPanel.proxy.Dispose(); m_inputConfigPanel.proxy.Dispose();
FileInfo cfgfile = new FileInfo( FileInfo cfgfile = new FileInfo(
@@ -81,15 +85,7 @@ namespace Cryville.Crtr.Config {
using (StreamWriter cfgwriter = new StreamWriter(cfgfile.FullName, false, Encoding.UTF8)) { using (StreamWriter cfgwriter = new StreamWriter(cfgfile.FullName, false, Encoding.UTF8)) {
cfgwriter.Write(JsonConvert.SerializeObject(_rscfg, Game.GlobalJsonSerializerSettings)); cfgwriter.Write(JsonConvert.SerializeObject(_rscfg, Game.GlobalJsonSerializerSettings));
} }
ReturnToMenu(); m_inputConfigPanel.OnConfigDisable();
}
public void ReturnToMenu() {
GameObject.Find("Master").GetComponent<Master>().ShowMenu();
#if UNITY_5_5_OR_NEWER
SceneManager.UnloadSceneAsync("Config");
#elif UNITY_5_3_OR_NEWER
SceneManager.UnloadScene("Config");
#endif
} }
} }
} }

View File

@@ -1,4 +1,5 @@
using Cryville.Common.Unity; using Cryville.Common;
using Cryville.Common.Unity;
using Cryville.Common.Unity.Input; using Cryville.Common.Unity.Input;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
@@ -7,7 +8,7 @@ using UnityEngine.UI;
namespace Cryville.Crtr.Config { namespace Cryville.Crtr.Config {
public class InputConfigPanel : MonoBehaviour { public class InputConfigPanel : MonoBehaviour {
[SerializeField] [SerializeField]
ConfigScene m_configScene; ConfigPanelMaster m_configScene;
[SerializeField] [SerializeField]
GameObject m_inputDialog; GameObject m_inputDialog;
@@ -24,12 +25,12 @@ namespace Cryville.Crtr.Config {
[SerializeField] [SerializeField]
GameObject m_prefabInputConfigEntry; GameObject m_prefabInputConfigEntry;
readonly SimpleInputConsumer _consumer = new SimpleInputConsumer(Game.InputManager); SimpleInputConsumer _consumer;
public InputProxy proxy; public InputProxy proxy;
readonly Dictionary<string, InputConfigPanelEntry> _entries = new Dictionary<string, InputConfigPanelEntry>(); readonly Dictionary<Identifier, InputConfigPanelEntry> _entries = new Dictionary<Identifier, InputConfigPanelEntry>();
string _sel; Identifier _sel;
public void OpenDialog(string entry) { public void OpenDialog(Identifier entry) {
_sel = entry; _sel = entry;
m_inputDialog.SetActive(true); m_inputDialog.SetActive(true);
CallHelper.Purge(m_deviceList); CallHelper.Purge(m_deviceList);
@@ -50,7 +51,10 @@ namespace Cryville.Crtr.Config {
CloseDialog(); CloseDialog();
} }
void Start() { public void OnConfigEnable() {
CallHelper.Purge(m_entryList);
_entries.Clear();
_consumer = new SimpleInputConsumer(Game.InputManager);
_consumer.Activate(); _consumer.Activate();
foreach (var i in m_configScene.ruleset.Root.inputs) { foreach (var i in m_configScene.ruleset.Root.inputs) {
var e = GameObject.Instantiate(m_prefabInputConfigEntry, m_entryList.transform).GetComponent<InputConfigPanelEntry>(); var e = GameObject.Instantiate(m_prefabInputConfigEntry, m_entryList.transform).GetComponent<InputConfigPanelEntry>();
@@ -61,13 +65,12 @@ namespace Cryville.Crtr.Config {
proxy.ProxyChanged += OnProxyChanged; proxy.ProxyChanged += OnProxyChanged;
} }
void OnDestroy() { public void OnConfigDisable() {
_consumer.Deactivate(); _consumer.Deactivate();
} }
void OnProxyChanged(object sender, ProxyChangedEventArgs e) { void OnProxyChanged(object sender, ProxyChangedEventArgs e) {
_entries[e.Name].SetEnabled(!e.Used); _entries[e.Name].OnProxyChanged(e);
_entries[e.Name].SetValue(e.Proxy == null ? "None" : e.Proxy.Value.Handler.GetTypeName(e.Proxy.Value.Type));
} }
readonly List<InputSource?> _recvsrcs = new List<InputSource?>(); readonly List<InputSource?> _recvsrcs = new List<InputSource?>();
@@ -83,9 +86,21 @@ namespace Cryville.Crtr.Config {
if (_recvsrcs.Contains(src)) return; if (_recvsrcs.Contains(src)) return;
_recvsrcs.Add(src); _recvsrcs.Add(src);
var obj = Instantiate(m_prefabListItem, m_deviceList); var obj = Instantiate(m_prefabListItem, m_deviceList);
obj.transform.Find("Text").GetComponent<Text>().text = src == null ? "None" : src.Value.Handler.GetTypeName(src.Value.Type); var text = obj.transform.Find("Text").GetComponent<Text>();
text.text = src == null ? "(None)" : src.Value.Handler.GetTypeName(src.Value.Type);
var btn = obj.GetComponent<Button>(); var btn = obj.GetComponent<Button>();
if (src != null) btn.interactable = !proxy.IsUsed(src.Value); if (src != null) {
var tsrc = src.Value;
bool flag = false;
if (proxy.IsUsed(tsrc)) {
text.text += " <size=9>(Used)</size>";
}
else if (tsrc.Handler.GetDimension(src.Value.Type) < m_configScene.ruleset.Root.inputs[_sel].dim) {
text.text += " <size=9>(Not Applicable)</size>";
}
else flag = true;
btn.interactable = flag;
}
btn.onClick.AddListener(() => { btn.onClick.AddListener(() => {
CloseDialog(src); CloseDialog(src);
}); });

View File

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

View File

@@ -12,6 +12,12 @@ namespace Cryville.Crtr.Config {
[JsonProperty("skin")] [JsonProperty("skin")]
public string Skin { get; set; } public string Skin { get; set; }
[Category("gameplay")]
[JsonProperty("sound_offset")]
[Step(0.04f)]
[Precision(1e-3)]
public float SoundOffset { get; set; }
[Category("deprecated")][Obsolete] [Category("deprecated")][Obsolete]
[JsonProperty("scroll_velocity")][DefaultValue(1)] [JsonProperty("scroll_velocity")][DefaultValue(1)]
[LogarithmicScale][Step(0.5f)][Precision(1e-1)] [LogarithmicScale][Step(0.5f)][Precision(1e-1)]
@@ -19,6 +25,7 @@ namespace Cryville.Crtr.Config {
public Generic() { public Generic() {
Skin = ""; Skin = "";
SoundOffset = 0;
ScrollVelocity = 1; ScrollVelocity = 1;
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,6 +1,7 @@
//#define DISABLE_CACHE //#define DISABLE_CACHE
using Cryville.Common; using Cryville.Common;
using Cryville.Common.Buffers;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
@@ -70,7 +71,6 @@ namespace Cryville.Crtr.Event {
public byte CloneType; public byte CloneType;
public ContainerState rootPrototype = null; public ContainerState rootPrototype = null;
private ContainerState prototype = null;
public ContainerHandler Handler { public ContainerHandler Handler {
get; get;
@@ -87,10 +87,13 @@ namespace Cryville.Crtr.Event {
Container = _ev; Container = _ev;
if (parent != null) { if (parent != null) {
AddChild(_ev, this, parent); AddChild(_ev, parent);
Parent = parent; Parent = parent;
} }
_rmvpa = new CategorizedPoolAccessor<Identifier, RealtimeMotionValue>(RMVPool);
_mcpa = new CategorizedPoolAccessor<Identifier, MotionCache>(MCPool);
Values = new Dictionary<Identifier, RealtimeMotionValue>(ChartPlayer.motionRegistry.Count); Values = new Dictionary<Identifier, RealtimeMotionValue>(ChartPlayer.motionRegistry.Count);
CachedValues = new Dictionary<Identifier, MotionCache>(ChartPlayer.motionRegistry.Count); CachedValues = new Dictionary<Identifier, MotionCache>(ChartPlayer.motionRegistry.Count);
foreach (var m in ChartPlayer.motionRegistry) foreach (var m in ChartPlayer.motionRegistry)
@@ -99,11 +102,13 @@ namespace Cryville.Crtr.Event {
rootPrototype = this; rootPrototype = this;
} }
static void AddChild(EventContainer c, ContainerState s, ContainerState target) { void AddChild(EventContainer c, ContainerState parent) {
target.Children.Add(c, s); parent.Children.Add(c, this);
Type t = c.GetType(); Type t = c.GetType();
if (!target.TypedChildren.ContainsKey(t)) target.TypedChildren.Add(t, new List<ContainerState>()); List<ContainerState> tc;
target.TypedChildren[t].Add(s); if (!parent.TypedChildren.TryGetValue(t, out tc))
parent.TypedChildren.Add(t, tc = new List<ContainerState>());
tc.Add(this);
} }
public ContainerState Clone(byte ct) { public ContainerState Clone(byte ct) {
@@ -116,18 +121,14 @@ namespace Cryville.Crtr.Event {
r.Values = mvs; r.Values = mvs;
var cvs = new Dictionary<Identifier, MotionCache>(ChartPlayer.motionRegistry.Count); var cvs = new Dictionary<Identifier, MotionCache>(ChartPlayer.motionRegistry.Count);
foreach (var cv in CachedValues) {
var dv = r.MCPool.Rent(cv.Key);
cv.Value.CopyTo(dv);
cvs.Add(cv.Key, dv);
}
r.CachedValues = cvs; r.CachedValues = cvs;
r.Children = new Dictionary<EventContainer, ContainerState>(); r.Children = new Dictionary<EventContainer, ContainerState>();
r.TypedChildren = new Dictionary<Type, List<ContainerState>>();
foreach (var child in Children) { foreach (var child in Children) {
var cc = child.Value.Clone(ct); var cc = child.Value.Clone(ct);
cc.Parent = r; cc.Parent = r;
AddChild(child.Key, cc, r); cc.AddChild(child.Key, r);
} }
r.ActiveChildren = new HashSet<EventContainer>(); r.ActiveChildren = new HashSet<EventContainer>();
@@ -142,7 +143,6 @@ namespace Cryville.Crtr.Event {
else if (ct == 3) Handler.ns = r; else if (ct == 3) Handler.ns = r;
else if (ct >= 16) Handler.ps = r; else if (ct >= 16) Handler.ps = r;
else throw new InvalidOperationException("Invalid clone type"); else throw new InvalidOperationException("Invalid clone type");
r.prototype = this;
r.CloneType = ct; r.CloneType = ct;
return r; return r;
} }
@@ -163,7 +163,7 @@ namespace Cryville.Crtr.Event {
foreach (var cv in CachedValues) { foreach (var cv in CachedValues) {
MotionCache dv; MotionCache dv;
if (!dest.CachedValues.TryGetValue(cv.Key, out dv)) { if (!dest.CachedValues.TryGetValue(cv.Key, out dv)) {
dest.CachedValues.Add(cv.Key, dv = dest.MCPool.Rent(cv.Key)); dest.CachedValues.Add(cv.Key, dv = dest._mcpa.Rent(cv.Key));
} }
cv.Value.CopyTo(dv); cv.Value.CopyTo(dv);
} }
@@ -190,10 +190,12 @@ namespace Cryville.Crtr.Event {
if (Disposed) return; if (Disposed) return;
Disposed = true; Disposed = true;
if (CloneType == 1) Handler.Dispose(); if (CloneType == 1) Handler.Dispose();
if (CloneType == 1 || CloneType == 17) {
_rmvpa.ReturnAll();
_mcpa.ReturnAll();
}
foreach (var s in Children) foreach (var s in Children)
s.Value.Dispose(); s.Value.Dispose();
RMVPool.ReturnAll();
MCPool.ReturnAll();
} }
public void DisposeAll() { public void DisposeAll() {
foreach (var s in Children) foreach (var s in Children)
@@ -214,8 +216,10 @@ namespace Cryville.Crtr.Event {
#endregion #endregion
#region Motion #region Motion
readonly RMVPool RMVPool = new RMVPool(); internal static RMVPool RMVPool;
readonly MotionCachePool MCPool = new MotionCachePool(); internal static MotionCachePool MCPool;
readonly CategorizedPoolAccessor<Identifier, RealtimeMotionValue> _rmvpa;
readonly CategorizedPoolAccessor<Identifier, MotionCache> _mcpa;
Dictionary<StampedEvent, RealtimeMotionValue> PlayingMotions = new Dictionary<StampedEvent, RealtimeMotionValue>(4); Dictionary<StampedEvent, RealtimeMotionValue> PlayingMotions = new Dictionary<StampedEvent, RealtimeMotionValue>(4);
Dictionary<Identifier, RealtimeMotionValue> Values; Dictionary<Identifier, RealtimeMotionValue> Values;
Dictionary<Identifier, MotionCache> CachedValues; Dictionary<Identifier, MotionCache> CachedValues;
@@ -235,7 +239,7 @@ namespace Cryville.Crtr.Event {
void InvalidateMotion(Identifier name) { void InvalidateMotion(Identifier name) {
MotionCache cache; MotionCache cache;
if (!CachedValues.TryGetValue(name, out cache)) if (!CachedValues.TryGetValue(name, out cache))
CachedValues.Add(name, cache = MCPool.Rent(name)); CachedValues.Add(name, cache = _mcpa.Rent(name));
cache.Valid = false; cache.Valid = false;
foreach (var c in ActiveChildren) foreach (var c in ActiveChildren)
Children[c].InvalidateMotion(name); Children[c].InvalidateMotion(name);
@@ -244,7 +248,7 @@ namespace Cryville.Crtr.Event {
public Vector GetRawValue(Identifier key) { public Vector GetRawValue(Identifier key) {
MotionCache tr; MotionCache tr;
if (!CachedValues.TryGetValue(key, out tr)) if (!CachedValues.TryGetValue(key, out tr))
CachedValues.Add(key, tr = MCPool.Rent(key)); CachedValues.Add(key, tr = _mcpa.Rent(key));
Vector r = tr.Value; Vector r = tr.Value;
#if !DISABLE_CACHE #if !DISABLE_CACHE
if (tr.Valid) return r; if (tr.Valid) return r;
@@ -353,14 +357,14 @@ namespace Cryville.Crtr.Event {
if (ev != null) { if (ev != null) {
if (ev.Unstamped is Chart.Motion) { if (ev.Unstamped is Chart.Motion) {
var tev = (Chart.Motion)ev.Unstamped; var tev = (Chart.Motion)ev.Unstamped;
var mv = RMVPool.Rent(tev.Name); var mv = _rmvpa.Rent(tev.Name);
mv.CloneTypeFlag = CloneType; mv.CloneTypeFlag = CloneType;
GetMotionValue(tev.Name).CopyTo(mv); GetMotionValue(tev.Name).CopyTo(mv);
PlayingMotions.Add(ev, mv); PlayingMotions.Add(ev, mv);
Update(ev); Update(ev);
if (!ev.Unstamped.IsLong) { if (!ev.Unstamped.IsLong) {
PlayingMotions.Remove(ev); PlayingMotions.Remove(ev);
RMVPool.Return(mv); _rmvpa.Return(mv);
} }
} }
else if (ev.Unstamped is EventContainer) { else if (ev.Unstamped is EventContainer) {
@@ -378,7 +382,7 @@ namespace Cryville.Crtr.Event {
if (nev is Chart.Motion) { if (nev is Chart.Motion) {
Update(ev); Update(ev);
var mv = PlayingMotions[ev.Origin]; var mv = PlayingMotions[ev.Origin];
if (mv.CloneTypeFlag == CloneType) RMVPool.Return(mv); if (mv.CloneTypeFlag == CloneType) _rmvpa.Return(mv);
PlayingMotions.Remove(ev.Origin); PlayingMotions.Remove(ev.Origin);
} }
else if (nev is EventContainer) { else if (nev is EventContainer) {
@@ -430,14 +434,14 @@ namespace Cryville.Crtr.Event {
public void BroadcastPreInit() { public void BroadcastPreInit() {
Handler.PreInit(); Handler.PreInit();
foreach (var c in Children.Values) { foreach (var c in Children) {
c.BroadcastPreInit(); c.Value.BroadcastPreInit();
} }
} }
public void BroadcastPostInit() { public void BroadcastPostInit() {
Handler.PostInit(); Handler.PostInit();
foreach (var c in Children.Values) { foreach (var c in Children) {
c.BroadcastPostInit(); c.Value.BroadcastPostInit();
} }
} }
@@ -457,8 +461,8 @@ namespace Cryville.Crtr.Event {
public void Anchor() { public void Anchor() {
Handler.Anchor(); Handler.Anchor();
foreach (var ls in Children.Values) { foreach (var ls in Children) {
if (ls.Handler.Alive) ls.Anchor(); if (ls.Value.Handler.Alive) ls.Value.Anchor();
} }
} }
#endregion #endregion

View File

@@ -48,7 +48,7 @@ namespace Cryville.Crtr.Event {
} }
foreach (var ev in c.Events) { foreach (var ev in c.Events) {
if (ev.time == null) { if (ev.time == null) {
coevents.Add(ev); if (!ev.Standalone) coevents.Add(ev);
ev.time = c.time; ev.time = c.time;
if (ev is EventContainer) if (ev is EventContainer)
ev.endtime = c.endtime; ev.endtime = c.endtime;

View File

@@ -1,9 +1,9 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.CompilerServices;
namespace Cryville.Crtr.Event { namespace Cryville.Crtr.Event {
public class EventBus : StateBase<EventBatch>, IDisposable { public class EventBus : StateBase<EventBatch>, IDisposable {
EventBus prototype = null;
public ContainerState RootState { public ContainerState RootState {
get; get;
private set; private set;
@@ -25,7 +25,6 @@ namespace Cryville.Crtr.Event {
public EventBus Clone(byte ct, float offsetTime = 0) { public EventBus Clone(byte ct, float offsetTime = 0) {
var r = (EventBus)MemberwiseClone(); var r = (EventBus)MemberwiseClone();
r.prototype = this;
r.states = new Dictionary<EventContainer, ContainerState>(); r.states = new Dictionary<EventContainer, ContainerState>();
r.activeStates = new HashSet<ContainerState>(); r.activeStates = new HashSet<ContainerState>();
r.invalidatedStates = new HashSet<ContainerState>(); r.invalidatedStates = new HashSet<ContainerState>();
@@ -64,8 +63,8 @@ namespace Cryville.Crtr.Event {
s = RootState; s = RootState;
} }
AddState(s); AddState(s);
foreach (var c in s.Children.Values) foreach (var c in s.Children)
Expand(c); Expand(c.Value);
} }
public void AddState(ContainerState s) { public void AddState(ContainerState s) {
@@ -74,13 +73,13 @@ namespace Cryville.Crtr.Event {
} }
void AttachBus() { void AttachBus() {
foreach (var s in states.Values) foreach (var s in states)
s.Bus = this; s.Value.Bus = this;
} }
public void AttachSystems(PdtSkin skin, Judge judge) { public void AttachSystems(PdtSkin skin, Judge judge) {
foreach (var s in states.Values) foreach (var s in states)
s.AttachSystems(skin, judge); s.Value.AttachSystems(skin, judge);
} }
List<StampedEvent.Temporary> tempEvents = new List<StampedEvent.Temporary>(); List<StampedEvent.Temporary> tempEvents = new List<StampedEvent.Temporary>();
@@ -122,6 +121,7 @@ namespace Cryville.Crtr.Event {
var batch = Events[EventId]; var batch = Events[EventId];
for (var i = 0; i < batch.Count; i++) { for (var i = 0; i < batch.Count; i++) {
var ev = batch[i]; var ev = batch[i];
HandleTempEvents(time0, ev.Priority);
if (ev is StampedEvent.ClipBehind) { if (ev is StampedEvent.ClipBehind) {
var cevs = ev.Origin.Coevents; var cevs = ev.Origin.Coevents;
if (cevs != null) foreach (var cev in cevs) { if (cevs != null) foreach (var cev in cevs) {
@@ -139,16 +139,7 @@ namespace Cryville.Crtr.Event {
} }
EventId++; EventId++;
} }
if (time2 == time0) { HandleTempEvents(time0);
while (tempEvents.Count > 0) {
var ev = tempEvents[0];
if (ev.Time != time0) break;
if (ev.Container != null) {
states[ev.Container].Handle(ev);
}
tempEvents.RemoveAt(0);
}
}
} }
else { else {
Time = toTime; Time = toTime;
@@ -156,6 +147,17 @@ namespace Cryville.Crtr.Event {
} }
ValidateStates(); ValidateStates();
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
void HandleTempEvents(double time, int maxPriority = int.MaxValue) {
while (tempEvents.Count > 0) {
var ev2 = tempEvents[0];
if (ev2.Time != time || ev2.Priority >= maxPriority) break;
if (ev2.Container != null) {
states[ev2.Container].Handle(ev2);
}
tempEvents.RemoveAt(0);
}
}
private void ValidateStates() { private void ValidateStates() {
foreach (var s in invalidatedStates) foreach (var s in invalidatedStates)

View File

@@ -11,10 +11,10 @@ namespace Cryville.Crtr.Event {
Value.CopyTo(dest.Value); Value.CopyTo(dest.Value);
} }
} }
internal class MotionCachePool { internal class MotionCachePool : CategorizedPool<Identifier, MotionCache> {
private class Bucket : ObjectPool<MotionCache> { private class Bucket : ObjectPool<MotionCache> {
readonly MotionRegistry _reg; readonly MotionRegistry _reg;
public Bucket(string name, int capacity) : base(capacity) { public Bucket(Identifier name, int capacity) : base(capacity) {
_reg = ChartPlayer.motionRegistry[name]; _reg = ChartPlayer.motionRegistry[name];
} }
protected override MotionCache Construct() { protected override MotionCache Construct() {
@@ -22,34 +22,16 @@ namespace Cryville.Crtr.Event {
result.Value = (Vector)ReflectionHelper.InvokeEmptyConstructor(_reg.Type); result.Value = (Vector)ReflectionHelper.InvokeEmptyConstructor(_reg.Type);
return result; return result;
} }
} protected override void Reset(MotionCache obj) {
static Dictionary<Identifier, Bucket> _buckets;
public static void Prepare() {
_buckets = new Dictionary<Identifier, Bucket>(ChartPlayer.motionRegistry.Count);
foreach (var reg in ChartPlayer.motionRegistry)
_buckets.Add(reg.Key, new Bucket(reg.Key, 4096));
}
static readonly SimpleObjectPool<Dictionary<MotionCache, Identifier>> _dictPool
= new SimpleObjectPool<Dictionary<MotionCache, Identifier>>(1024);
Dictionary<MotionCache, Identifier> _rented;
public MotionCache Rent(Identifier name) {
var obj = _buckets[name].Rent();
obj.Valid = false; obj.Valid = false;
if (_rented == null) _rented = _dictPool.Rent();
_rented.Add(obj, name);
return obj;
} }
public void Return(MotionCache obj) {
_buckets[_rented[obj]].Return(obj);
_rented.Remove(obj);
} }
public void ReturnAll() { readonly Dictionary<Identifier, ObjectPool<MotionCache>> m_buckets;
if (_rented == null) return; protected override IReadOnlyDictionary<Identifier, ObjectPool<MotionCache>> Buckets { get { return m_buckets; } }
foreach (var obj in _rented) public MotionCachePool() {
_buckets[obj.Value].Return(obj.Key); m_buckets = new Dictionary<Identifier, ObjectPool<MotionCache>>(ChartPlayer.motionRegistry.Count);
_rented.Clear(); foreach (var reg in ChartPlayer.motionRegistry)
_dictPool.Return(_rented); m_buckets.Add(reg.Key, new Bucket(reg.Key, 4096));
} }
} }
} }

View File

@@ -3,42 +3,22 @@ using Cryville.Common.Buffers;
using System.Collections.Generic; using System.Collections.Generic;
namespace Cryville.Crtr.Event { namespace Cryville.Crtr.Event {
internal class RMVPool { internal class RMVPool : CategorizedPool<Identifier, RealtimeMotionValue> {
private class Bucket : ObjectPool<RealtimeMotionValue> { private class Bucket : ObjectPool<RealtimeMotionValue> {
readonly MotionRegistry _reg; readonly MotionRegistry _reg;
public Bucket(string name, int capacity) : base(capacity) { public Bucket(Identifier name, int capacity) : base(capacity) {
_reg = ChartPlayer.motionRegistry[name]; _reg = ChartPlayer.motionRegistry[name];
} }
protected override RealtimeMotionValue Construct() { protected override RealtimeMotionValue Construct() {
return new RealtimeMotionValue().Init(_reg.InitValue); return new RealtimeMotionValue().Init(_reg.InitValue);
} }
} }
static Dictionary<Identifier, Bucket> _buckets; readonly Dictionary<Identifier, ObjectPool<RealtimeMotionValue>> m_buckets;
public static void Prepare() { protected override IReadOnlyDictionary<Identifier, ObjectPool<RealtimeMotionValue>> Buckets { get { return m_buckets; } }
_buckets = new Dictionary<Identifier, Bucket>(ChartPlayer.motionRegistry.Count); public RMVPool() {
m_buckets = new Dictionary<Identifier, ObjectPool<RealtimeMotionValue>>(ChartPlayer.motionRegistry.Count);
foreach (var reg in ChartPlayer.motionRegistry) foreach (var reg in ChartPlayer.motionRegistry)
_buckets.Add(reg.Key, new Bucket(reg.Key, 4096)); m_buckets.Add(reg.Key, new Bucket(reg.Key, 4096));
}
static readonly SimpleObjectPool<Dictionary<RealtimeMotionValue, Identifier>> _dictPool
= new SimpleObjectPool<Dictionary<RealtimeMotionValue, Identifier>>(1024);
Dictionary<RealtimeMotionValue, Identifier> _rented;
public RealtimeMotionValue Rent(Identifier name) {
var obj = _buckets[name].Rent();
if (_rented == null) _rented = _dictPool.Rent();
_rented.Add(obj, name);
return obj;
}
public void Return(RealtimeMotionValue obj) {
_buckets[_rented[obj]].Return(obj);
_rented.Remove(obj);
}
public void ReturnAll() {
if (_rented == null) return;
foreach (var obj in _rented)
_buckets[obj.Value].Return(obj.Key);
_rented.Clear();
_dictPool.Return(_rented);
} }
} }
} }

View File

@@ -1,24 +1,45 @@
using Cryville.Common; using Cryville.Common;
using Cryville.Crtr.Browsing; using Cryville.Crtr.Browsing;
using Microsoft.Win32; using Microsoft.Win32;
using Newtonsoft.Json;
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text;
namespace Cryville.Crtr.Extensions.Malody { namespace Cryville.Crtr.Extensions.Malody {
public class MalodyChartFinder : LocalResourceFinder { public class MalodyChartFinder : LocalResourceFinder {
public override string Name { get { return "Malody beatmaps"; } } public override string Name { get { return "Malody beatmaps"; } }
public override string GetRootPath() { 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) { switch (Environment.OSVersion.Platform) {
case PlatformID.Unix: case PlatformID.Unix:
return "/storage/emulated/0/data/malody/beatmap"; return "/storage/emulated/0/data/malody";
case PlatformID.Win32NT: case PlatformID.Win32NT:
var reg = Registry.ClassesRoot.OpenSubKey(@"malody\Shell\Open\Command"); var reg = Registry.ClassesRoot.OpenSubKey(@"malody\Shell\Open\Command");
if (reg == null) return null; if (reg == null) return null;
var pathObj = reg.GetValue(null); var pathObj = reg.GetValue(null);
if (pathObj == null) return null; if (pathObj == null) return null;
var path = (string)pathObj; 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; default: return null;
} }
} }

View File

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

View File

@@ -42,15 +42,24 @@ namespace Cryville.Crtr.Extensions {
} }
} }
public class TimeTimingModel : TimingModel { 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) { public void ForwardTo(double t) {
if (t == Time) return; if (t == Time) return;
if (BPM == 0) throw new InvalidOperationException("BPM not determined"); if (BPM == 0) throw new InvalidOperationException("BPM not determined");
BeatTime += (t - Time) * BPM / 60; BeatTime += (t - Time) * BPM / 60;
int n, d; 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); FractionalBeatTime = new BeatTime(n, d);
Time = t; 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 { public class osuChartConverter : ResourceConverter {
#pragma warning restore IDE1006 #pragma warning restore IDE1006
static readonly string[] SUPPORTED_FORMATS = { ".osu" }; static readonly string[] SUPPORTED_FORMATS = { ".osu" };
const double OFFSET = 0.07; const double OFFSET = 0.011;
public override string[] GetSupportedFormats() { public override string[] GetSupportedFormats() {
return SUPPORTED_FORMATS; return SUPPORTED_FORMATS;
@@ -108,10 +108,11 @@ namespace Cryville.Crtr.Extensions.osu {
else if (ev is osuEvent.TimingChange) { else if (ev is osuEvent.TimingChange) {
var tev = (osuEvent.TimingChange)ev; var tev = (osuEvent.TimingChange)ev;
if (tm == null) { if (tm == null) {
tm = new TimeTimingModel(tev.StartTime / 1e3); tm = new TimeTimingModel(tev.StartTime / 1e3, 2e-3);
bgmEv.offset = (float)(tev.StartTime / 1e3 + OFFSET); bgmEv.offset = (float)(tev.StartTime / 1e3 + OFFSET);
} }
tm.BeatLength = tev.BeatLength / 1e3; tm.BeatLength = tev.BeatLength / 1e3;
tm.ForceSnap();
chart.sigs.Add(new Chart.Signature { chart.sigs.Add(new Chart.Signature {
time = tm.FractionalBeatTime, time = tm.FractionalBeatTime,
tempo = (float)tm.BPM, tempo = (float)tm.BPM,

View File

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

View File

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

View File

@@ -1,7 +1,6 @@
using Cryville.Common.Math; using Cryville.Common.Math;
using Cryville.Crtr.Event; using Cryville.Crtr.Event;
using System; using System;
using System.Linq;
using UnityEngine; using UnityEngine;
namespace Cryville.Crtr { namespace Cryville.Crtr {
@@ -10,6 +9,7 @@ namespace Cryville.Crtr {
SquareMatrix matFrame; SquareMatrix matFrame;
ContainerState[] tracks; ContainerState[] tracks;
public int TrackCount { get { return tracks.Length; } }
public GroupHandler(Chart.Group tg, ChartHandler ch) : base() { public GroupHandler(Chart.Group tg, ChartHandler ch) : base() {
this.ch = ch; this.ch = ch;
@@ -19,20 +19,19 @@ namespace Cryville.Crtr {
public override void PreInit() { public override void PreInit() {
base.PreInit(); base.PreInit();
tracks = ( tracks = cs.TypedChildren[typeof(Chart.Track)].ToArray();
from c in cs.Children
where c.Value.Container is Chart.Track
select c.Value
).ToArray();
matFrame = SquareMatrix.WithPolynomialCoefficients(tracks.Length); matFrame = SquareMatrix.WithPolynomialCoefficients(tracks.Length);
frame = new ColumnVector<Vector3>(tracks.Length); frame1 = new ColumnVector<Vector3>(tracks.Length);
frame2 = new ColumnVector<Vector3>(tracks.Length);
} }
ColumnVector<Vector3> frame; ColumnVector<Vector3> frame1;
ColumnVector<Vector3> frame2;
public ColumnVector<Vector3> GetCurrentFrame(Func<ContainerState, Vector3> func) { public ColumnVector<Vector3> GetCurrentFrame(Func<ContainerState, Vector3> func) {
for (int i = 0; i < tracks.Length; i++) for (int i = 0; i < tracks.Length; i++)
frame[i] = func(tracks[i]); frame1[i] = func(tracks[i]);
return matFrame.Eliminate(frame, Vector3Operator.Instance); matFrame.Eliminate(frame1, frame2, Vector3Operator.Instance);
return frame2;
} }
} }

View File

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

View File

@@ -4,19 +4,21 @@ using Cryville.Common.Pdt;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.Runtime.Serialization;
using System.Text.Formatting; using System.Text.Formatting;
namespace Cryville.Crtr { namespace Cryville.Crtr {
public class Judge { public class Judge {
#region Data #region Data
readonly ChartPlayer _sys;
readonly PdtEvaluator _etor; readonly PdtEvaluator _etor;
readonly PdtRuleset _rs; readonly PdtRuleset _rs;
readonly Dictionary<Identifier, float> ct
= new Dictionary<Identifier, float>();
readonly Dictionary<Identifier, List<JudgeEvent>> evs readonly Dictionary<Identifier, List<JudgeEvent>> evs
= new Dictionary<Identifier, List<JudgeEvent>>(); = new Dictionary<Identifier, List<JudgeEvent>>();
readonly Dictionary<Identifier, List<JudgeEvent>> activeEvs readonly Dictionary<Identifier, List<JudgeEvent>> activeEvs
= new Dictionary<Identifier, List<JudgeEvent>>(); = new Dictionary<Identifier, List<JudgeEvent>>();
static readonly int _var_pause = IdentifierManager.SharedInstance.Request("pause");
readonly JudgeDefinition _judgePause;
public struct JudgeEvent { public struct JudgeEvent {
public double StartTime { get; set; } public double StartTime { get; set; }
public double EndTime { get; set; } public double EndTime { get; set; }
@@ -32,27 +34,38 @@ namespace Cryville.Crtr {
return x.StartClip.CompareTo(y.StartClip); return x.StartClip.CompareTo(y.StartClip);
} }
} }
public Judge(PdtRuleset rs) { public Judge(ChartPlayer sys, PdtRuleset rs) {
_sys = sys;
_etor = ChartPlayer.etor; _etor = ChartPlayer.etor;
_rs = rs; _rs = rs;
_numsrc1 = new PropSrc.Float(() => _numbuf1); _numsrc1 = new PropSrc.Float(() => _numbuf1);
_numsrc2 = new PropSrc.Float(() => _numbuf2); _numsrc2 = new PropSrc.Float(() => _numbuf2);
_numsrc3 = new PropSrc.Float(() => _numbuf3); _numsrc3 = new PropSrc.Float(() => _numbuf3);
_numsrc4 = new PropSrc.Float(() => _numbuf4); _numsrc4 = new PropSrc.Float(() => _numbuf4);
_rs.judges.TryGetValue(new Identifier(_var_pause), out _judgePause);
foreach (var i in rs.inputs) {
var id = i.Key;
var l = new List<JudgeEvent>();
evs.Add(id, l);
activeEvs.Add(id, new List<JudgeEvent>());
if (_judgePause != null && id.Key == _var_pause) {
l.Add(new JudgeEvent {
StartTime = double.NegativeInfinity, EndTime = double.PositiveInfinity,
StartClip = double.NegativeInfinity, EndClip = double.PositiveInfinity,
Definition = _judgePause,
});
}
}
InitJudges(); InitJudges();
InitScores(); InitScores();
} }
public void Prepare(StampedEvent sev, NoteHandler handler) { public void Prepare(StampedEvent sev, NoteHandler handler) {
var tev = (Chart.Judge)sev.Unstamped; var tev = (Chart.Judge)sev.Unstamped;
if (tev.Id.Key == _var_pause) throw new InvalidOperationException("Cannot assign the special judge \"pause\" to notes");
Identifier input = default(Identifier); Identifier input = default(Identifier);
ChartPlayer.etor.Evaluate(new PropOp.Identifier(v => input = new Identifier(v)), _rs.judges[tev.Id].input); ChartPlayer.etor.Evaluate(new PropOp.Identifier(v => input = new Identifier(v)), _rs.judges[tev.Id].input);
double st = sev.Time, et = st + sev.Duration; double st = sev.Time, et = st + sev.Duration;
List<JudgeEvent> list; var list = evs[input];
if (!evs.TryGetValue(input, out list)) {
ct.Add(input, 0);
evs.Add(input, list = new List<JudgeEvent>());
activeEvs.Add(input, new List<JudgeEvent>());
}
var def = _rs.judges[tev.Id]; var def = _rs.judges[tev.Id];
var ev = new JudgeEvent { var ev = new JudgeEvent {
StartTime = st, StartTime = st,
@@ -71,8 +84,9 @@ namespace Cryville.Crtr {
#region Judge #region Judge
internal readonly Dictionary<int, int> judgeMap = new Dictionary<int, int>(); internal readonly Dictionary<int, int> judgeMap = new Dictionary<int, int>();
void InitJudges() { void InitJudges() {
foreach (var i in _rs.judges.Keys) { foreach (var i in _rs.judges) {
judgeMap.Add(i.Key, IdentifierManager.SharedInstance.Request("judge_" + i.Name)); var id = i.Key;
judgeMap.Add(id.Key, IdentifierManager.SharedInstance.Request("judge_" + id.Name));
} }
} }
static bool _flag; static bool _flag;
@@ -121,7 +135,7 @@ namespace Cryville.Crtr {
if (actlist.Count > 0) { if (actlist.Count > 0) {
_numbuf3 = ft; _numsrc3.Invalidate(); _etor.ContextCascadeUpdate(_var_ft, _numsrc3); _numbuf3 = ft; _numsrc3.Invalidate(); _etor.ContextCascadeUpdate(_var_ft, _numsrc3);
_numbuf4 = tt; _numsrc4.Invalidate(); _etor.ContextCascadeUpdate(_var_tt, _numsrc4); _numbuf4 = tt; _numsrc4.Invalidate(); _etor.ContextCascadeUpdate(_var_tt, _numsrc4);
var index = 0; int index = 0, iter = 0;
while (index >= 0 && index < actlist.Count) { while (index >= 0 && index < actlist.Count) {
var ev = actlist[index]; var ev = actlist[index];
_numbuf1 = (float)ev.StartTime; _numsrc1.Invalidate(); _etor.ContextCascadeUpdate(_var_fn, _numsrc1); _numbuf1 = (float)ev.StartTime; _numsrc1.Invalidate(); _etor.ContextCascadeUpdate(_var_fn, _numsrc1);
@@ -130,27 +144,32 @@ namespace Cryville.Crtr {
if (def.hit != null) _etor.Evaluate(_flagop, def.hit); if (def.hit != null) _etor.Evaluate(_flagop, def.hit);
else _flag = true; else _flag = true;
if (_flag) { if (_flag) {
if (ev.Definition == _judgePause) _sys.TogglePause();
if (def.scores != null) UpdateScore(def.scores); if (def.scores != null) UpdateScore(def.scores);
if (def.pass != null) Pass(ev, (ft + tt) / 2, def.pass); if (def.pass != null) Pass(ev, (ft + tt) / 2, def.pass);
actlist.RemoveAt(index); if (def.persist != null) _etor.Evaluate(_flagop, def.persist);
else _flag = false;
if (!_flag) actlist.RemoveAt(index);
if (def.prop != 0 && actlist.Count > 0) { if (def.prop != 0 && actlist.Count > 0) {
index = BinarySearchFirst(actlist, (float)ev.StartClip, def.stack - def.prop); index = BinarySearchFirst(actlist, (float)ev.StartClip, def.stack - def.prop);
if (index < 0) index = ~index; if (index < 0) index = ~index;
} }
else index++; else index++;
if (iter++ >= 16) throw new JudgePropagationException();
} }
else index++; else index++;
} }
} }
} }
bool Pass(JudgeEvent ev, float time, Identifier[] ids) { bool Pass(JudgeEvent ev, float time, Identifier[] ids, int depth = 0) {
if (depth >= 16) throw new JudgePropagationException();
foreach (var i in ids) { foreach (var i in ids) {
var def = _rs.judges[i]; var def = _rs.judges[i];
if (def.hit != null) _etor.Evaluate(_flagop, def.hit); if (def.hit != null) _etor.Evaluate(_flagop, def.hit);
else _flag = true; else _flag = true;
if (_flag) { if (_flag) {
if (def.scores != null) UpdateScore(def.scores); if (def.scores != null) UpdateScore(def.scores);
if (def.pass != null) Pass(ev, time, def.pass); if (def.pass != null) Pass(ev, time, def.pass, depth + 1);
ev.Handler.ReportJudge(ev, time, i); ev.Handler.ReportJudge(ev, time, i);
return true; return true;
} }
@@ -203,7 +222,6 @@ namespace Cryville.Crtr {
readonly Dictionary<int, ScoreDefinition> scoreDefs = new Dictionary<int, ScoreDefinition>(); readonly Dictionary<int, ScoreDefinition> scoreDefs = new Dictionary<int, ScoreDefinition>();
readonly Dictionary<int, float> scores = new Dictionary<int, float>(); readonly Dictionary<int, float> scores = new Dictionary<int, float>();
readonly Dictionary<int, string> scoreStringCache = new Dictionary<int, string>(); readonly Dictionary<int, string> scoreStringCache = new Dictionary<int, string>();
readonly Dictionary<int, PropSrc> scoreStringSrcs = new Dictionary<int, PropSrc>();
readonly ArrayPool<byte> scoreStringPool = new ArrayPool<byte>(); readonly ArrayPool<byte> scoreStringPool = new ArrayPool<byte>();
readonly Dictionary<int, string> scoreFormatCache = new Dictionary<int, string>(); readonly Dictionary<int, string> scoreFormatCache = new Dictionary<int, string>();
readonly TargetString scoreFullStr = new TargetString(); readonly TargetString scoreFullStr = new TargetString();
@@ -219,27 +237,25 @@ namespace Cryville.Crtr {
scoreDefs.Add(key, s.Value); scoreDefs.Add(key, s.Value);
scores.Add(key, s.Value.init); scores.Add(key, s.Value.init);
scoreStringCache.Add(scoreStringKeys[key], null); scoreStringCache.Add(scoreStringKeys[key], null);
scoreStringSrcs.Add(scoreStringKeys[key], new ScoreStringSrc(scoreStringPool, () => scores[key], scoreDefs[key].format)); scoreSrcs.Add(scoreStringKeys[key], new ScoreStringSrc(scoreStringPool, () => scores[key], scoreDefs[key].format));
scoreFormatCache[key] = string.Format("{{0:{0}}}", s.Value.format); scoreFormatCache[key] = string.Format("{{0:{0}}}", s.Value.format);
} }
} }
void InvalidateScore(int key) { void InvalidateScore(int key) {
scoreSrcs[key].Invalidate(); scoreSrcs[key].Invalidate();
scoreStringCache[scoreStringKeys[key]] = null; scoreStringCache[scoreStringKeys[key]] = null;
scoreStringSrcs[scoreStringKeys[key]].Invalidate(); scoreSrcs[scoreStringKeys[key]].Invalidate();
} }
public bool TryGetScoreSrc(int key, out PropSrc value) { public bool TryGetScoreSrc(int key, out PropSrc value) {
return scoreSrcs.TryGetValue(key, out value); return scoreSrcs.TryGetValue(key, out value);
} }
public bool TryGetScoreStringSrc(int key, out PropSrc value) {
return scoreStringSrcs.TryGetValue(key, out value);
}
public TargetString GetFullFormattedScoreString() { public TargetString GetFullFormattedScoreString() {
bool flag = false; bool flag = false;
scoreFullBuf.Clear(); scoreFullBuf.Clear();
foreach (var s in scores.Keys) { foreach (var s in scores) {
scoreFullBuf.AppendFormat(flag ? "\n{0}: " : "{0}: ", (string)IdentifierManager.SharedInstance.Retrieve(s)); var id = s.Key;
scoreFullBuf.AppendFormat(scoreFormatCache[s], scores[s]); scoreFullBuf.AppendFormat(flag ? "\n{0}: " : "{0}: ", (string)IdentifierManager.SharedInstance.Retrieve(id));
scoreFullBuf.AppendFormat(scoreFormatCache[id], scores[id]);
flag = true; flag = true;
} }
scoreFullStr.Length = scoreFullBuf.Count; scoreFullStr.Length = scoreFullBuf.Count;
@@ -289,6 +305,7 @@ namespace Cryville.Crtr {
public Clip clip; public Clip clip;
public PdtExpression input; public PdtExpression input;
public PdtExpression hit; public PdtExpression hit;
public PdtExpression persist;
public Identifier[] pass; public Identifier[] pass;
public Identifier[] miss; public Identifier[] miss;
public Dictionary<ScoreOperation, PdtExpression> scores; public Dictionary<ScoreOperation, PdtExpression> scores;
@@ -309,4 +326,12 @@ namespace Cryville.Crtr {
public string format = ""; public string format = "";
} }
#endregion #endregion
[Serializable]
public class JudgePropagationException : Exception {
public JudgePropagationException() : base("Judge propagation limit reached\nThe ruleset has invalid judge definitions") { }
public JudgePropagationException(string message) : base(message) { }
public JudgePropagationException(string message, Exception inner) : base(message, inner) { }
protected JudgePropagationException(SerializationInfo info, StreamingContext context) : base(info, context) { }
}
} }

View File

@@ -7,13 +7,8 @@ namespace Cryville.Crtr {
private GameObject m_menu; private GameObject m_menu;
#pragma warning restore IDE0044 #pragma warning restore IDE0044
internal void ShowMenu() { internal void ShowMenu() { m_menu.SetActive(true); }
m_menu.SetActive(true); internal void HideMenu() { m_menu.SetActive(false); }
}
internal void HideMenu() {
m_menu.SetActive(false);
}
void OnApplicationQuit() { void OnApplicationQuit() {
Game.Shutdown(); Game.Shutdown();

View File

@@ -1,5 +1,7 @@
using Cryville.Common.Unity.UI; using Cryville.Common.Unity.UI;
using Cryville.Crtr.Browsing; using Cryville.Crtr.Browsing;
using System.Collections.Generic;
using TMPro;
using UnityEngine; using UnityEngine;
namespace Cryville.Crtr { namespace Cryville.Crtr {
@@ -13,6 +15,10 @@ namespace Cryville.Crtr {
ProgressBar m_progressBar; ProgressBar m_progressBar;
[SerializeField] [SerializeField]
SettingsPanel m_settingsPanel; SettingsPanel m_settingsPanel;
[SerializeField]
TMP_Text m_title;
[SerializeField]
GameObject[] m_backBlockingObjects;
#pragma warning restore IDE0044 #pragma warning restore IDE0044
int frameIndex = 2; int frameIndex = 2;
@@ -23,6 +29,7 @@ namespace Cryville.Crtr {
Game.Init(); Game.Init();
transform.parent.Find("Canvas/Contents").gameObject.SetActive(true); transform.parent.Find("Canvas/Contents").gameObject.SetActive(true);
m_settingsPanel.Target = Settings.Default; m_settingsPanel.Target = Settings.Default;
PushTitle("Chart Browser");
} }
void Update() { void Update() {
if (!initialized) { if (!initialized) {
@@ -54,9 +61,20 @@ namespace Cryville.Crtr {
} }
#pragma warning restore IDE0051 #pragma warning restore IDE0051
readonly Stack<string> _uiStack = new Stack<string>();
public void PushTitle(string title) {
_uiStack.Push(title);
m_title.SetText(title);
}
public void Back() { public void Back() {
foreach (var obj in m_backBlockingObjects) {
if (obj.activeInHierarchy) return;
}
if (m_browserMaster.Back()) return; if (m_browserMaster.Back()) return;
m_targetAnimator.SetTrigger("G_Back"); m_targetAnimator.SetTrigger("G_Back");
if (_uiStack.Count <= 1) return;
_uiStack.Pop();
m_title.SetText(_uiStack.Peek());
} }
public void Quit() { public void Quit() {
Application.Quit(); Application.Quit();

View File

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

View File

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

View File

@@ -50,14 +50,15 @@ namespace Cryville.Crtr {
public override void PreInit() { public override void PreInit() {
base.PreInit(); base.PreInit();
coeffs = new ColumnVector<float>(gh.TrackCount);
foreach (var j in Event.judges) { foreach (var j in Event.judges) {
judges.Add(j, new JudgeState(this, j.Id.Key)); judges.Add(j, new JudgeState(this, j.Id.Key));
} }
} }
public override void Init() { public override void Init() {
base.Init(); base.Init();
sgos = gogroup.GetComponentsInChildren<SectionalGameObject>(); sgos = RootTransform.GetComponentsInChildren<SectionalGameObject>();
foreach (var judge in judges.Values) judge.InitPropSrcs(); foreach (var judge in judges) judge.Value.InitPropSrcs();
} }
public override void StartPhysicalUpdate(ContainerState s) { public override void StartPhysicalUpdate(ContainerState s) {
@@ -66,10 +67,10 @@ namespace Cryville.Crtr {
TransformAwake(s); TransformAwake(s);
} }
} }
public override void StartGraphicalUpdate(ContainerState s) { protected override void StartGraphicalUpdate(ContainerState s) {
base.StartGraphicalUpdate(s); base.StartGraphicalUpdate(s);
TransformAwake(s); TransformAwake(s);
if (gogroup) { if (RootTransform) {
if (Event.IsLong) { if (Event.IsLong) {
foreach (var i in sgos) { foreach (var i in sgos) {
i.Reset(); i.Reset();
@@ -78,10 +79,10 @@ namespace Cryville.Crtr {
} }
else { else {
#if UNITY_5_6_OR_NEWER #if UNITY_5_6_OR_NEWER
gogroup.SetPositionAndRotation(Position, Rotation); RootTransform.SetPositionAndRotation(Position, Rotation);
#else #else
gogroup.position = Position; RootTransform.position = Position;
gogroup.rotation = Rotation; RootTransform.rotation = Rotation;
#endif #endif
} }
} }
@@ -92,12 +93,10 @@ namespace Cryville.Crtr {
} }
public override void Update(ContainerState s, StampedEvent ev) { public override void Update(ContainerState s, StampedEvent ev) {
base.Update(s, ev);
if (s.CloneType <= 2) { if (s.CloneType <= 2) {
Position = GetFramePoint(s.Parent, s.Track); Position = GetFramePoint(s.Parent, s.Track);
Rotation = GetFrameRotation(s.Parent, s.Track); Rotation = GetFrameRotation(s.Parent, s.Track);
if (s.CloneType == 2) { if (s.CloneType == 2 && RootTransform && Event.IsLong) {
if (!gogroup || !Event.IsLong) return;
foreach (var i in sgos) foreach (var i in sgos)
i.AppendPoint(Position, Rotation); i.AppendPoint(Position, Rotation);
} }
@@ -113,10 +112,23 @@ namespace Cryville.Crtr {
ChartPlayer.etor.ContextEvent = null; ChartPlayer.etor.ContextEvent = null;
} }
} }
if (s.CloneType == 2 && ev != null && ev.Unstamped is Chart.Judge) {
var anchor = judges[(Chart.Judge)ev.Unstamped].StaticAnchor;
#if UNITY_5_6_OR_NEWER
anchor.Transform.SetPositionAndRotation(Position, Rotation);
#else
anchor.Transform.position = Position;
anchor.Transform.rotation = Rotation;
#endif
OpenAnchor(anchor);
base.Update(s, ev);
CloseAnchor();
}
else base.Update(s, ev);
} }
public override void EndGraphicalUpdate(ContainerState s) { protected override void EndGraphicalUpdate(ContainerState s) {
if (gogroup) { if (RootTransform) {
foreach (var i in sgos) i.Seal(); foreach (var i in sgos) i.Seal();
} }
base.EndGraphicalUpdate(s); base.EndGraphicalUpdate(s);
@@ -132,6 +144,7 @@ namespace Cryville.Crtr {
} }
readonly List<Vector3> ctrl = new List<Vector3>(2); readonly List<Vector3> ctrl = new List<Vector3>(2);
ColumnVector<float> coeffs;
Vector3 GetFrame(ContainerState state, float track, Func<ContainerState, Vector3> func) { Vector3 GetFrame(ContainerState state, float track, Func<ContainerState, Vector3> func) {
// TODO // TODO
int id = Mathf.FloorToInt(track); int id = Mathf.FloorToInt(track);
@@ -160,12 +173,8 @@ namespace Cryville.Crtr {
} }
if (ctrl.Count == 0) { if (ctrl.Count == 0) {
var frame = gh.GetCurrentFrame(func); var frame = gh.GetCurrentFrame(func);
return frame.Dot( ColumnVector<float>.FillWithPolynomialCoefficients(coeffs, track);
ColumnVector<float>.WithPolynomialCoefficients( return frame.Dot(coeffs, Vector3Operator.Instance);
frame.Size, track
),
Vector3Operator.Instance
);
} }
else if (ctrl.Count == 1) { else if (ctrl.Count == 1) {
return nt * (nt * p1 + t * (ctrl[0] + p1)) + t * t * p2; return nt * (nt * p1 + t * (ctrl[0] + p1)) + t * t * p2;

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