151 Commits

Author SHA1 Message Date
d9f6dd33d4 Optimize texture size. 2022-11-22 21:48:41 +08:00
e5d6e549bd Code cleanup. 2022-11-21 18:16:12 +08:00
145c0ce6c8 Optimize GC for value updating in text component. 2022-11-21 14:10:20 +08:00
a0174b94c6 Optimize GC for input proxy. 2022-11-21 14:09:44 +08:00
109b489104 Introduce TargetString to eliminate text GC. 2022-11-21 14:09:01 +08:00
784c3fc338 Disable GUI layout on Unity key receiver to avoid GC. 2022-11-21 14:06:57 +08:00
77d6ac2caf Cleanup unused functions. 2022-11-21 12:14:34 +08:00
321af22775 Code cleanup. 2022-11-20 23:17:08 +08:00
39ef9815e8 Fix verbose log about invalid resource. 2022-11-20 23:08:58 +08:00
bb3afba11f Fix import error on cover file missing. 2022-11-20 22:36:53 +08:00
e4fa160a90 Fix log typo. 2022-11-20 19:13:40 +08:00
34df9e2257 Optimize MatchDynamic performance. 2022-11-20 19:04:33 +08:00
cfdb5f021e Reconstruct skin container. Add update clone type limit to skin property. 2022-11-20 16:12:19 +08:00
d08eea5c1e Postpone skin static matching. 2022-11-20 16:09:34 +08:00
ce30b5427b Improve vector cache performance. 2022-11-20 16:02:39 +08:00
e38fed89e9 Update Cryville.Audio. 2022-11-20 13:29:29 +08:00
d4b12bf3f7 Add extra fallback logic for audio engine initialization. 2022-11-20 13:29:09 +08:00
40d75a91c6 Remove IL2CPP incompatibility workaround. 2022-11-20 09:34:37 +08:00
388a41cb55 Fix startup progress bar not working if first item has no cover. 2022-11-20 01:42:14 +08:00
3b23f78960 Update Unity to 2021.3.14. 2022-11-20 01:39:24 +08:00
4fce8369f0 Fix StartUpdate on root state not called. (Amend) 2022-11-19 22:32:36 +08:00
373554912a Pull skin container and judge attachment to handler. (Amend) 2022-11-19 22:13:17 +08:00
46039f6a12 Code cleanup. 2022-11-19 22:11:15 +08:00
9b872654d5 Disables time debug info generation when log disabled. 2022-11-19 22:10:24 +08:00
2c4ac3191c Optimize score variables. 2022-11-19 22:08:56 +08:00
20632d9b54 Fix performance optimization for RMVPool. 2022-11-19 22:05:51 +08:00
28cad97bbb Fix StartUpdate on root state not called. 2022-11-19 22:04:41 +08:00
75652ecff1 Pull skin container and judge attachment to handler. 2022-11-19 22:02:05 +08:00
1734cf9b72 Logic cleanup. 2022-11-19 10:49:52 +08:00
5eb9786a7c Prune code. (Amend) 2022-11-19 10:13:46 +08:00
16be67dc75 Prune code. 2022-11-19 10:13:06 +08:00
a7dfaa4558 Remove transparent property. (2) 2022-11-19 01:10:00 +08:00
3b65dbea5b Remove track property on note event. Attach contextual state on skin evaluation. 2022-11-19 01:04:15 +08:00
3ed7e566dd Fix time calculation in Malody chart converter. 2022-11-18 15:55:31 +08:00
f3549353f3 Add Bestdori chart converter. 2022-11-18 15:55:00 +08:00
78bb820f9e Fix skin resource import destination path. 2022-11-18 11:08:22 +08:00
b954dda676 Update materials. 2022-11-18 10:32:24 +08:00
1be5cc77ca Remove transparent property. 2022-11-18 10:23:51 +08:00
bf942cbe45 Fix z-index. Pull up z-index to MeshBase. 2022-11-18 09:58:01 +08:00
79bfd6764c Update ruleset and skin format number. (2) 2022-11-18 00:45:25 +08:00
dcc92bb024 Update ruleset and skin format number. 2022-11-18 00:20:29 +08:00
15e9217f93 Reconstruct resource structure. 2022-11-18 00:11:49 +08:00
79240fdfe8 Remove required attribute on base field of ruleset. 2022-11-18 00:07:53 +08:00
678e145271 Pull up data field in metadata. 2022-11-17 23:31:44 +08:00
5cdf10874e Add chart, ruleset, and skin file resource importer. 2022-11-17 17:22:27 +08:00
777b7d9c34 Code cleanup. 2022-11-17 17:21:59 +08:00
34b17f3111 Add chart file resource. 2022-11-17 17:21:09 +08:00
fd9e2ce409 Add frame list in skin data structure. Remove Cocos2d Plist support. 2022-11-17 17:19:31 +08:00
cd8aa0e65c Add ruleset and skin resource stub. 2022-11-17 12:05:57 +08:00
5240408f00 Add support for other media formats besides ogg. 2022-11-17 12:05:16 +08:00
a7e6522a57 Update meta info data structure. 2022-11-17 12:04:17 +08:00
d89e5a2e68 Trims trailing spaces and dots when escaping file name instead of replacing them. 2022-11-17 12:00:33 +08:00
05124ac406 Blocks ruleset config if ruleset not found. 2022-11-17 11:57:56 +08:00
a4fdb97424 Fix IL2CPP incompatibility. 2022-11-16 17:45:52 +08:00
735a85b914 Add error notice for mcz files. 2022-11-16 17:44:56 +08:00
be0c71702b Ignore Local directory. 2022-11-16 17:44:18 +08:00
535959a6ed Use symbolic link for default resources. 2022-11-16 17:43:19 +08:00
ae37b27dc0 Remove default resources temporarily. 2022-11-16 17:42:49 +08:00
80cc5fdbda Pull down scroll velocity option. Add property categories for ruleset config. 2022-11-16 17:30:33 +08:00
87e406e903 Cleanup. 2022-11-16 12:08:11 +08:00
f04d0ec299 Loads ruleset config before worker. Implement skin option of ruleset config. 2022-11-16 11:45:28 +08:00
a19057f869 Uses original cover file name on import. 2022-11-16 11:42:51 +08:00
d0d981b790 Add string property value panel. 2022-11-16 11:40:58 +08:00
c95ae92ba8 Fix input proxy not deactivated on stop. 2022-11-16 00:28:10 +08:00
31e9f1352b Redefine stack and propagation of judge. 2022-11-16 00:27:38 +08:00
9974b25377 Adjust config scene layout. 2022-11-16 00:25:25 +08:00
852c93c6d0 Add generic ruleset config. 2022-11-16 00:25:08 +08:00
15e66d29c4 Code cleanup. 2022-11-15 20:14:36 +08:00
3d5ea4f056 Fix null vector passing. 2022-11-15 20:14:27 +08:00
1772c90c2f Fix texture wrap mode. 2022-11-15 20:12:24 +08:00
53ada70dda Remove unexpected using. 2022-11-15 18:08:13 +08:00
a8ab73ac65 Fix chart player dispose. 2022-11-15 17:29:10 +08:00
35ac57bfba Code cleanup. 2022-11-15 17:28:42 +08:00
945f9ca7d1 Implement input config scene loading and saving. 2022-11-15 17:27:51 +08:00
d2b2834a60 Implement input config loading and saving. 2022-11-15 17:26:00 +08:00
f82e0ce9ef Add ruleset config. 2022-11-15 17:22:13 +08:00
5444ea7186 Add popup for exception on worker thread. 2022-11-15 17:20:00 +08:00
3a54d2023f Pull down popup from common. 2022-11-15 17:17:30 +08:00
cb3e3e5f28 Remove obsolete NO_THREAD symbol. 2022-11-15 15:25:53 +08:00
174f616e5c Add error notice popup for resource import. 2022-11-15 13:31:39 +08:00
0f8bb5f1f6 Fix and add popup. 2022-11-15 13:30:40 +08:00
2d35e3177b Update ruleset name for Malody extension. 2022-11-15 12:12:59 +08:00
7b1f639412 Code cleanup. 2022-11-15 12:12:29 +08:00
fcc9935325 Fix input config. 2022-11-15 12:10:54 +08:00
8b29cd2893 Generalize settings panel. 2022-11-15 12:10:34 +08:00
f44d9546e1 Implement config category switch. 2022-11-15 12:09:29 +08:00
1d1d2646c4 Passes chart detail on open and config. 2022-11-15 12:08:48 +08:00
6444de41a2 Fix property value panel layout update. 2022-11-15 12:06:00 +08:00
ea856f3339 Code cleanup. 2022-11-15 11:05:10 +08:00
74b1a5485b Fix resource import interrupted when item not valid. 2022-11-15 09:15:53 +08:00
975b48e61e Add leave_timing and contact_timing function. 2022-11-14 23:28:32 +08:00
9e0bf024d7 Fix judge propagation. 2022-11-14 23:28:14 +08:00
d2ff168e25 Add invalidation for property source. Fix cache lock for scores. 2022-11-14 16:38:15 +08:00
05664a2994 Code cleanup. 2022-11-14 16:05:44 +08:00
ba6166068b Implement score update. 2022-11-14 16:05:21 +08:00
d5d6465806 Implement compound operator patching. 2022-11-14 16:03:35 +08:00
1f57c299a2 Add some judge functions. Code cleanup. 2022-11-14 13:59:26 +08:00
49431e888c Implement judge feed, pass, cleanup, and miss. Add update score stub. 2022-11-14 13:57:02 +08:00
c31c16792c Add judge priority. 2022-11-14 13:55:10 +08:00
7ce73186ae Make Unity timestamps realtime critical. (2) 2022-11-14 13:49:29 +08:00
318a6705be Fix collapse operators and boolean property operator. 2022-11-14 11:28:10 +08:00
7fca09ff49 Code cleanup. 2022-11-13 13:42:08 +08:00
eff8dd2c35 Remove temporary debug logs. 2022-11-12 17:50:31 +08:00
252853f4d4 Add time debug info. Fix sleep duration for audio sync. 2022-11-12 17:02:21 +08:00
a47faf0049 Implement force tick and sync time for input proxy. 2022-11-12 17:01:10 +08:00
604398cae2 Add judge feed and cleanup stub. 2022-11-12 16:56:27 +08:00
457d491d89 Update internal judge event data structure. 2022-11-12 16:53:57 +08:00
0c8e24b079 Make Unity timestamps realtime critical. 2022-11-12 16:49:01 +08:00
fcc159ab6c Code cleanup. 2022-11-12 01:02:30 +08:00
f7454eb514 Add active counting for input sources for force tick. 2022-11-12 01:02:00 +08:00
35040e4ebd Update input feeding logic. 2022-11-12 01:00:31 +08:00
d10e6ea18b Implement judge event preparation. 2022-11-12 00:57:41 +08:00
8af09a7167 Prevents duplicated event hooks. 2022-11-12 00:52:44 +08:00
bca71982e5 Code cleanup. 2022-11-11 17:46:10 +08:00
0b17520bfd Modify logic for "not" operator. 2022-11-11 17:36:52 +08:00
990a42f71b Evaluates clipping of judge events on load. 2022-11-11 10:36:00 +08:00
383fca1a8e Modify logic for "at" operator. 2022-11-11 10:02:43 +08:00
cf00bd8db0 Implement input name evaluation. Implement context state. 2022-11-11 10:02:01 +08:00
84e4e3514d Reorganize event priority. 2022-11-11 09:57:08 +08:00
5ac0a558e0 Delay input name evaluation in judge definition. 2022-11-11 00:44:44 +08:00
20f4de3832 Implement int_map function. Remove "long operator" concept. 2022-11-11 00:36:16 +08:00
296d5bb615 Reads score operation as structure. 2022-11-11 00:34:30 +08:00
c33186086c Tokenize ruleset keys. Remove MotionName. 2022-11-09 14:01:27 +08:00
55efc7a428 Code cleanup. 2022-11-09 13:53:53 +08:00
1f621082c6 Fix item not reloaded on resource import. 2022-11-09 13:51:00 +08:00
f311eb5e8d Implement InputProxy. 2022-11-07 12:21:50 +08:00
0d7018c964 Fix import error due to invalid file name. (Amend) 2022-11-07 12:19:31 +08:00
a401585f07 Optimize context cascade in PDT evaluator. 2022-11-07 12:15:22 +08:00
7e025f9268 Fix import error due to invalid file name. 2022-11-07 12:13:07 +08:00
65d86ed72d Modify logic for "and" and "or" operator and in_area function. Add null marshaling for input proxy. 2022-11-06 14:52:05 +08:00
71a33c0b43 Code cleanup. 2022-11-06 14:25:02 +08:00
f33560daba Add in_area function. (Amend) 2022-11-06 14:20:28 +08:00
b4fa5849ae Add error type and null type. 2022-11-06 14:19:00 +08:00
cfcc371226 Add in_area function. 2022-11-06 13:48:23 +08:00
c635d89c6a Fix delegate invocation by input proxy. 2022-11-06 13:47:48 +08:00
fc04071b53 Fix number marshaling for PDT variable memory. 2022-11-06 13:46:23 +08:00
2c74296532 Add abs function. Fix "at" operator. 2022-11-06 13:21:15 +08:00
b92a21951d Transforms input from screen point to world point. 2022-11-06 13:20:26 +08:00
d58e255b3f Update operator exception handling. 2022-11-06 12:12:51 +08:00
01a4214265 Fix exception handling on failure to get operator. 2022-11-06 12:11:55 +08:00
15e8a2a2a8 Fix typo in PdtVariableMemory. 2022-11-06 12:10:32 +08:00
57fd2c0c0d Add lock for input proxy. 2022-11-06 00:55:56 +08:00
8f98cb63cb Implement input proxy. Change input callback delegate to event. Prevents repeated (de)activation. 2022-11-06 00:50:09 +08:00
7f02b75b29 Move arbitrary property operator to PropOp. 2022-11-06 00:30:36 +08:00
9d4f938675 Move InputEvent to InputManager.cs. 2022-11-06 00:20:01 +08:00
c3dc6b9a03 Modify PDT type identifiers to avoid hash collision. 2022-11-05 20:00:15 +08:00
a422f06221 Add "at" operator. 2022-11-05 17:41:54 +08:00
8e3bd87667 Reverse context cascade searching order. 2022-11-05 17:06:35 +08:00
324c887539 Retrieve identifier names for debugging. 2022-11-01 17:36:18 +08:00
2c9be2ef1e Introduce IdentifierManager to improve PDT evaluator performance. 2022-11-01 13:47:04 +08:00
3bfc7eb643 Logic cleanup. 2022-11-01 11:28:48 +08:00
204 changed files with 3720 additions and 2595 deletions

1
.gitignore vendored
View File

@@ -61,6 +61,7 @@ crashlytics-build.properties
# #
/Docs /Docs
/Issues /Issues
/Local
/Obsolete /Obsolete
/Snapshots /Snapshots
/UI /UI

Binary file not shown.

View File

@@ -0,0 +1,120 @@
using System;
using System.Collections;
using System.Collections.Generic;
namespace Cryville.Common.Buffers {
/// <summary>
/// An auto-resized <see cref="char" /> array as a variable-length string used as a target that is modified frequently.
/// </summary>
public class TargetString : IEnumerable<char> {
public event Action OnUpdate;
char[] _arr;
bool _invalidated;
/// <summary>
/// Creates an instance of the <see cref="TargetString" /> class with a capacity of 16.
/// </summary>
public TargetString() : this(16) { }
/// <summary>
/// Creates an instance of the <see cref="TargetString" /> class.
/// </summary>
/// <param name="capacity">The initial capacity of the string.</param>
public TargetString(int capacity) {
_arr = new char[capacity];
}
/// <summary>
/// Gets or sets one of the characters in the string.
/// </summary>
/// <param name="index">The zero-based index of the character.</param>
/// <returns>The character at the given index.</returns>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="index" /> is less than 0 or not less than <see cref="Length" />.</exception>
/// <remarks>
/// <para>Set <see cref="Length" /> to a desired value before updating the characters.</para>
/// <para>Call <see cref=" Validate" /> after all the characters are updated.</para>
/// </remarks>
public char this[int index] {
get {
if (index < 0 || index >= m_length)
throw new ArgumentOutOfRangeException("index");
return _arr[index];
}
set {
if (index < 0 || index >= m_length)
throw new ArgumentOutOfRangeException("index");
if (_arr[index] == value) return;
_arr[index] = value;
_invalidated = true;
}
}
int m_length;
/// <summary>
/// The length of the string.
/// </summary>
public int Length {
get {
return m_length;
}
set {
if (m_length == value) return;
if (_arr.Length < value) {
var len = m_length;
while (len < value) len *= 2;
var arr2 = new char[len];
Array.Copy(_arr, arr2, m_length);
_arr = arr2;
}
m_length = value;
_invalidated = true;
}
}
/// <summary>
/// Validates the string.
/// </summary>
public void Validate() {
if (!_invalidated) return;
_invalidated = false;
var ev = OnUpdate;
if (ev != null) OnUpdate.Invoke();
}
IEnumerator IEnumerable.GetEnumerator() {
return GetEnumerator();
}
public IEnumerator<char> GetEnumerator() {
return new Enumerator(this);
}
class Enumerator : IEnumerator<char> {
TargetString _self;
int _index = -1;
public Enumerator(TargetString self) { _self = self; }
public char Current {
get {
if (_index < 0)
throw new InvalidOperationException(_index == -1 ? "Enum not started" : "Enum ended");
return _self[_index];
}
}
object IEnumerator.Current { get { return Current; } }
public void Dispose() {
_index = -2;
}
public bool MoveNext() {
if (_index == -2) return false;
_index++;
if (_index >= _self.Length) {
_index = -2;
return false;
}
return true;
}
public void Reset() {
_index = -1;
}
}
}
}

View File

@@ -1,8 +1,7 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: da665e46f8c2b5b46ad8e3bf5cd34007 guid: f0fc34ac257793d4883a9cfcdb6941b9
timeCreated: 1605077404
licenseType: Free
MonoImporter: MonoImporter:
externalObjects: {}
serializedVersion: 2 serializedVersion: 2
defaultReferences: [] defaultReferences: []
executionOrder: 0 executionOrder: 0

View File

@@ -0,0 +1,34 @@
using System;
namespace Cryville.Common {
public struct Identifier : IEquatable<Identifier> {
public int Key { get; private set; }
public object Name { get { return IdentifierManager.SharedInstance.Retrieve(Key); } }
public Identifier(int key) {
Key = key;
}
public Identifier(object name) {
Key = IdentifierManager.SharedInstance.Request(name);
}
public override bool Equals(object obj) {
if (obj == null || !(obj is Identifier)) return false;
return Equals((Identifier)obj);
}
public bool Equals(Identifier other) {
return Key == other.Key;
}
public override int GetHashCode() {
return Key;
}
public override string ToString() {
if (Key == 0) return "";
return Name.ToString();
}
public static implicit operator Identifier(string identifier) {
return new Identifier(identifier);
}
public static implicit operator string(Identifier identifier) {
return identifier.ToString();
}
}
}

View File

@@ -1,8 +1,7 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 3bc71e8b62d4022409aa5518bbf3a7d8 guid: 5b0f66eb5ae446e44a34dc61dac132b6
timeCreated: 1608801352
licenseType: Free
MonoImporter: MonoImporter:
externalObjects: {}
serializedVersion: 2 serializedVersion: 2
defaultReferences: [] defaultReferences: []
executionOrder: 0 executionOrder: 0

View File

@@ -0,0 +1,52 @@
using System.Collections.Generic;
namespace Cryville.Common {
/// <summary>
/// A manager that assigns each given identifiers a unique integer ID.
/// </summary>
public class IdentifierManager {
/// <summary>
/// A shared instance of the <see cref="IdentifierManager" /> class.
/// </summary>
public static IdentifierManager SharedInstance = new IdentifierManager();
Dictionary<object, int> _idents = new Dictionary<object, int>();
List<object> _ids = new List<object>();
object _syncRoot = new object();
/// <summary>
/// Creates an instance of the <see cref="IdentifierManager" /> class.
/// </summary>
public IdentifierManager() {
Request(this);
}
/// <summary>
/// Requests an integer ID for an identifier.
/// </summary>
/// <param name="ident">The identifier.</param>
/// <returns>The integer ID.</returns>
public int Request(object ident) {
lock (_syncRoot) {
int id;
if (!_idents.TryGetValue(ident, out id)) {
_idents.Add(ident, id = _idents.Count);
_ids.Add(ident);
}
return id;
}
}
/// <summary>
/// Retrieves the identifier assigned with an integer ID.
/// </summary>
/// <param name="id">The integer ID.</param>
/// <returns>The identifier.</returns>
public object Retrieve(int id) {
lock (_syncRoot) {
return _ids[id];
}
}
}
}

View File

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

View File

@@ -17,7 +17,7 @@ namespace Cryville.Common {
public static void SetLogPath(string path) { public static void SetLogPath(string path) {
logPath = path; logPath = path;
var dir = new DirectoryInfo(path); var dir = new DirectoryInfo(path);
if (!dir.Exists) Directory.CreateDirectory(dir.FullName); if (!dir.Exists) dir.Create();
} }
/// <summary> /// <summary>
/// Logs to the specified logger. /// Logs to the specified logger.

View File

@@ -0,0 +1,52 @@
using System;
namespace Cryville.Common.Math {
/// <summary>
/// Provides a set of <see langword="static" /> methods related to fractions.
/// </summary>
public static class FractionUtils {
/// <summary>
/// Converts a <see cref="double" /> decimal to a fraction.
/// </summary>
/// <param name="value">The decimal.</param>
/// <param name="error">The error.</param>
/// <param name="n">The numerator.</param>
/// <param name="d">The denominator.</param>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="value" /> is less than 0 or <paramref name="error" /> is not greater than 0 or not less than 1.</exception>
public static void ToFraction(double value, double error, out int n, out int d) {
if (value < 0.0)
throw new ArgumentOutOfRangeException("value", "Must be >= 0.");
if (error <= 0.0 || error >= 1.0)
throw new ArgumentOutOfRangeException("accuracy", "Must be > 0 and < 1.");
int num = (int)System.Math.Floor(value);
value -= num;
if (value < error) { n = num; d = 1; return; }
if (1 - error < value) { n = num + 1; d = 1; return; }
int lower_n = 0;
int lower_d = 1;
int upper_n = 1;
int upper_d = 1;
while (true) {
int middle_n = lower_n + upper_n;
int middle_d = lower_d + upper_d;
if (middle_d * (value + error) < middle_n) {
upper_n = middle_n;
upper_d = middle_d;
}
else if (middle_n < (value - error) * middle_d) {
lower_n = middle_n;
lower_d = middle_d;
}
else {
n = num * middle_d + middle_n;
d = middle_d;
return;
}
}
}
}
}

View File

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

View File

@@ -19,9 +19,7 @@ namespace Cryville.Common.Network {
set { throw new NotSupportedException(); } set { throw new NotSupportedException(); }
} }
public override void Flush() { public override void Flush() { }
// Do nothing
}
public abstract byte[] ReadToEnd(); public abstract byte[] ReadToEnd();

View File

@@ -92,9 +92,7 @@ namespace Cryville.Common.Network {
return null; return null;
} }
public void NotifyServerCertificate(TlsServerCertificate serverCertificate) { public void NotifyServerCertificate(TlsServerCertificate serverCertificate) { }
// Do nothing
}
} }
} }
} }

View File

@@ -34,6 +34,16 @@ namespace Cryville.Common.Pdt {
} }
} }
/// <summary> /// <summary>
/// Patches an expression with a lefthand variable and a compound operator.
/// </summary>
/// <param name="target">The name of the lefthand variable.</param>
/// <param name="op">The name of the compound operator.</param>
/// <param name="exp">The expression.</param>
public void PatchCompound(int target, int op, PdtExpression exp) {
exp.Instructions.AddFirst(new PdtInstruction.PushVariable(target));
exp.Instructions.AddLast(new PdtInstruction.Operate(op, 2));
}
/// <summary>
/// Optimizes an expression by merging its instructions. /// Optimizes an expression by merging its instructions.
/// </summary> /// </summary>
/// <param name="exp">The expression to optimize.</param> /// <param name="exp">The expression to optimize.</param>
@@ -47,7 +57,7 @@ namespace Cryville.Common.Pdt {
var i = _rip.Value; var i = _rip.Value;
if (i is PdtInstruction.Operate) { if (i is PdtInstruction.Operate) {
int fc0 = _framecount; int fc0 = _framecount;
int fc1 = ((PdtInstruction.Operate)i).ParamCount; int fc1 = ((PdtInstruction.Operate)i).Signature.ParamCount;
try { i.Execute(this); } catch (Exception) { } try { i.Execute(this); } catch (Exception) { }
if (fc0 - _framecount == fc1) { if (fc0 - _framecount == fc1) {
unsafe { unsafe {
@@ -137,7 +147,7 @@ namespace Cryville.Common.Pdt {
_goffset += value.Length; _goffset += value.Length;
} }
} }
internal unsafe void PushVariable(ref string name) { internal unsafe void PushVariable(int name) {
fixed (StackFrame* frame = &_stack[_framecount++]) { fixed (StackFrame* frame = &_stack[_framecount++]) {
byte[] value; byte[] value;
GetVariable(name, out frame->Type, out value); GetVariable(name, out frame->Type, out value);
@@ -153,12 +163,16 @@ namespace Cryville.Common.Pdt {
/// <param name="name">The name of the variable.</param> /// <param name="name">The name of the variable.</param>
/// <param name="type">The type of the variable.</param> /// <param name="type">The type of the variable.</param>
/// <param name="value">The value of the variable.</param> /// <param name="value">The value of the variable.</param>
protected abstract void GetVariable(string name, out int type, out byte[] value); protected abstract void GetVariable(int name, out int type, out byte[] value);
internal void Operate(ref string name, int pc) { internal void Operate(PdtOperatorSignature sig) {
PdtOperator op; PdtOperator op;
try { op = GetOperator(name, pc); } try { op = GetOperator(sig); }
catch (Exception) { _framecount -= pc; return; } catch (Exception) {
Operate(op, pc); for (int i = 0; i < sig.ParamCount; i++)
DiscardStack();
throw;
}
Operate(op, sig.ParamCount);
} }
/// <summary> /// <summary>
/// Gets an operator of the specified name and the suggested parameter count. /// Gets an operator of the specified name and the suggested parameter count.
@@ -167,7 +181,7 @@ namespace Cryville.Common.Pdt {
/// <param name="pc">Suggested parameter count.</param> /// <param name="pc">Suggested parameter count.</param>
/// <returns>An operator of the specific name.</returns> /// <returns>An operator of the specific name.</returns>
/// <remarks>The parameter count of the returned operator does not necessarily equal to <paramref name="pc" />.</remarks> /// <remarks>The parameter count of the returned operator does not necessarily equal to <paramref name="pc" />.</remarks>
protected abstract PdtOperator GetOperator(string name, int pc); 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);
@@ -179,7 +193,7 @@ namespace Cryville.Common.Pdt {
op.Call(pmem + _goffset, noset); op.Call(pmem + _goffset, noset);
} }
} }
internal unsafe void Collapse(ref string name, LinkedListNode<PdtInstruction> target) { internal unsafe void Collapse(int name, LinkedListNode<PdtInstruction> target) {
fixed (byte* pmem = _mem) { fixed (byte* pmem = _mem) {
var frame = _stack[--_framecount]; var frame = _stack[--_framecount];
if (Collapse(name, new PdtVariableMemory(frame.Type, pmem + frame.Offset, frame.Length))) { if (Collapse(name, new PdtVariableMemory(frame.Type, pmem + frame.Offset, frame.Length))) {
@@ -194,7 +208,7 @@ namespace Cryville.Common.Pdt {
/// <param name="name">The name of the collapse operator.</param> /// <param name="name">The name of the collapse operator.</param>
/// <param name="param">The top frame in the stack as the parameter.</param> /// <param name="param">The top frame in the stack as the parameter.</param>
/// <returns>Whether to jump to the target of the collapse instruction.</returns> /// <returns>Whether to jump to the target of the collapse instruction.</returns>
protected abstract bool Collapse(string name, PdtVariableMemory param); protected abstract bool Collapse(int name, PdtVariableMemory param);
internal unsafe PdtVariableMemory StackAlloc(int type, byte* ptr, int len) { internal unsafe PdtVariableMemory StackAlloc(int type, byte* ptr, int len) {
fixed (StackFrame* frame = &_stack[_framecount++]) { fixed (StackFrame* frame = &_stack[_framecount++]) {
frame->Type = type; frame->Type = type;

View File

@@ -50,51 +50,49 @@ namespace Cryville.Common.Pdt {
} }
} }
public class PushVariable : PdtInstruction { public class PushVariable : PdtInstruction {
private string m_name; public int Name { get; private set; }
public string Name { get { return m_name; } } public PushVariable(int name) { Name = name; }
public PushVariable(string name) { public PushVariable(string name) : this(IdentifierManager.SharedInstance.Request(name)) { }
m_name = name;
}
internal override void Execute(PdtEvaluatorBase etor) { internal override void Execute(PdtEvaluatorBase etor) {
etor.PushVariable(ref m_name); etor.PushVariable(Name);
} }
public override string ToString() { public override string ToString() {
return string.Format("pushv {0}", Name); return string.Format("pushv {0}", IdentifierManager.SharedInstance.Retrieve(Name));
} }
} }
public class Operate : PdtInstruction { public class Operate : PdtInstruction {
private string m_name; public PdtOperatorSignature Signature { get; private set; }
public string Name { get { return m_name; } } public Operate(int name, int paramCount) {
public int ParamCount { get; private set; } Signature = new PdtOperatorSignature(name, paramCount);
}
public Operate(string name, int paramCount) { public Operate(string name, int paramCount) {
m_name = name; Signature = new PdtOperatorSignature(name, paramCount);
ParamCount = paramCount;
} }
internal override void Execute(PdtEvaluatorBase etor) { internal override void Execute(PdtEvaluatorBase etor) {
etor.Operate(ref m_name, ParamCount); etor.Operate(Signature);
} }
public override string ToString() { public override string ToString() {
return string.Format("op {0}({1})", Name, ParamCount); return string.Format("op {0}", Signature);
} }
} }
public class Collapse : PdtInstruction { public class Collapse : PdtInstruction {
private string m_name; public int Name { get; private set; }
public string Name { get { return m_name; } }
public LinkedListNode<PdtInstruction> Target { get; internal set; } public LinkedListNode<PdtInstruction> Target { get; internal set; }
public Collapse(string name, LinkedListNode<PdtInstruction> target) { public Collapse(string name, LinkedListNode<PdtInstruction> target) {
m_name = name; Name = IdentifierManager.SharedInstance.Request(name);
Target = target; Target = target;
} }
internal override void Execute(PdtEvaluatorBase etor) { internal override void Execute(PdtEvaluatorBase etor) {
etor.Collapse(ref m_name, Target); etor.Collapse(Name, Target);
} }
public override string ToString() { public override string ToString() {
return string.Format("col {0}{{{1}}}", Name, Target.Value); return string.Format("col {0}{{{1}}}", IdentifierManager.SharedInstance.Retrieve(Name), Target.Value);
} }
} }
} }
public partial class PdtInterpreter<T> { public partial class PdtInterpreter<T> {
readonly static Dictionary<char, int> OP_PRIORITY = new Dictionary<char, int> { readonly static Dictionary<char, int> OP_PRIORITY = new Dictionary<char, int> {
{ '@', 7 },
{ '*', 6 }, { '/', 6 }, { '%', 6 }, { '*', 6 }, { '/', 6 }, { '%', 6 },
{ '+', 5 }, { '-', 5 }, { '+', 5 }, { '-', 5 },
{ '=', 4 }, { '<', 4 }, { '>', 4 }, { '=', 4 }, { '<', 4 }, { '>', 4 },
@@ -105,6 +103,7 @@ namespace Cryville.Common.Pdt {
{ '$', -1 }, { '$', -1 },
}; };
readonly static Dictionary<char, int> OP_TYPE = new Dictionary<char, int> { readonly static Dictionary<char, int> OP_TYPE = new Dictionary<char, int> {
{ '@', 0 },
{ '*', 0 }, { '/', 0 }, { '%', 0 }, { '*', 0 }, { '/', 0 }, { '%', 0 },
{ '+', 0 }, { '-', 0 }, { '+', 0 }, { '-', 0 },
{ '=', 0 }, { '<', 0 }, { '>', 0 }, { '=', 0 }, { '<', 0 }, { '>', 0 },

View File

@@ -3,26 +3,33 @@
/// The identifiers of the internal types of PDT. /// The identifiers of the internal types of PDT.
/// </summary> /// </summary>
public static class PdtInternalType { public static class PdtInternalType {
internal readonly static int Error = "error".GetHashCode(); /// <summary>
/// Error type.
/// </summary>
public readonly static 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 = "array".GetHashCode(); public readonly static int Array = 0x00525241;
/// <summary>
/// Null type.
/// </summary>
public readonly static 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 = "number".GetHashCode(); public readonly static 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 = "string".GetHashCode(); public readonly static 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 = "undefined".GetHashCode(); public readonly static 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 = "vector".GetHashCode(); public readonly static int Vector = 0x00434556;
} }
} }

View File

@@ -47,7 +47,10 @@ namespace Cryville.Common.Pdt {
internal void Call(byte* prmem, bool noset) { internal void Call(byte* prmem, bool noset) {
_prmem = prmem; _prmem = prmem;
_rfreq = false; _rfreq = false;
try { Execute(); } catch (Exception) { _failure = true; } try { Execute(); } catch (Exception ex) {
if (_rfreq) _etor.DiscardStack();
throw new InvalidOperationException("Evaluation failed", ex);
}
if (_failure) { if (_failure) {
if (_rfreq) _etor.DiscardStack(); if (_rfreq) _etor.DiscardStack();
throw new InvalidOperationException("Evaluation failed"); throw new InvalidOperationException("Evaluation failed");
@@ -74,4 +77,48 @@ namespace Cryville.Common.Pdt {
return _etor.StackAlloc(type, _prmem, len); return _etor.StackAlloc(type, _prmem, len);
} }
} }
/// <summary>
/// The signature of a <see cref="PdtOperator" />.
/// </summary>
public struct PdtOperatorSignature : IEquatable<PdtOperatorSignature> {
/// <summary>
/// The name of the operator.
/// </summary>
public int Name { get; private set; }
/// <summary>
/// The parameter count.
/// </summary>
public int ParamCount { get; private set; }
readonly int _hash;
/// <summary>
/// Creates an operator signature.
/// </summary>
/// <param name="name">The name of the operator.</param>
/// <param name="paramCount">The parameter count.</param>
public PdtOperatorSignature(string name, int paramCount)
: this(IdentifierManager.SharedInstance.Request(name), paramCount) { }
/// <summary>
/// Creates an operator signature.
/// </summary>
/// <param name="name">The identifier of the operator.</param>
/// <param name="paramCount">The parameter count.</param>
public PdtOperatorSignature(int name, int paramCount) {
Name = name;
ParamCount = paramCount;
_hash = Name ^ ((ParamCount << 16) | (ParamCount >> 16));
}
public override bool Equals(object obj) {
if (!(obj is PdtOperatorSignature)) return false;
return Equals((PdtOperatorSignature)obj);
}
public bool Equals(PdtOperatorSignature other) {
return Name == other.Name && ParamCount == other.ParamCount;
}
public override int GetHashCode() {
return _hash;
}
public override string ToString() {
return string.Format("{0}({1})", IdentifierManager.SharedInstance.Retrieve(Name), ParamCount);
}
}
} }

View File

@@ -20,6 +20,13 @@ namespace Cryville.Common.Pdt {
Length = len; Length = len;
} }
/// <summary> /// <summary>
/// Copies the memory in the span to another span.
/// </summary>
/// <param name="dest">The destination span.</param>
public void CopyTo(PdtVariableMemory dest) {
CopyTo(dest._ptr, 0, Length);
}
/// <summary>
/// Copies the memory in the span to a buffer. /// Copies the memory in the span to a buffer.
/// </summary> /// </summary>
/// <param name="dest">The destination buffer.</param> /// <param name="dest">The destination buffer.</param>
@@ -42,28 +49,33 @@ namespace Cryville.Common.Pdt {
/// <summary> /// <summary>
/// Gets the memory of the span as a number. /// Gets the memory of the span as a number.
/// </summary> /// </summary>
/// <param name="offset">The offset on the span to start reading from.</param>
/// <returns>A number.</returns> /// <returns>A number.</returns>
/// <exception cref="InvalidCastException">The span does not represent a number.</exception> /// <exception cref="InvalidCastException">The span at the offset does not represent a number.</exception>
public float AsNumber() { public float AsNumber(int offset = 0) {
if (Type != PdtInternalType.Number) if (Type != PdtInternalType.Number && Type != PdtInternalType.Vector)
throw new InvalidCastException("Not a number"); throw new InvalidCastException("Not a number");
float value; float value;
byte* ptr = (byte*)&value; byte* ptr = (byte*)&value;
for (int i = 0; i < sizeof(float); i++) for (int i = 0; i < sizeof(float); i++)
ptr[i] = _ptr[i]; ptr[i] = _ptr[i + offset];
return value; return value;
} }
/// <summary> /// <summary>
/// Sets the memory of the span to a number. /// Sets the memory of the span to a number.
/// </summary> /// </summary>
/// <param name="value">The number.</param> /// <param name="value">The number.</param>
/// <exception cref="InvalidCastException">The span does not represent a number.</exception> /// <param name="offset">The offset from the start of the span.</param>
public void SetNumber(float value) { /// <exception cref="InvalidCastException">The span at the offset does not represent a number.</exception>
if (Type != PdtInternalType.Number) /// <exception cref="InvalidOperationException">The length of the span is not sufficient.</exception>
public void SetNumber(float value, int offset = 0) {
if (Type != PdtInternalType.Number && Type != PdtInternalType.Vector)
throw new InvalidCastException("Not a number"); throw new InvalidCastException("Not a number");
if (Length < sizeof(float) + offset)
throw new InvalidOperationException("Frame length not sufficient");
byte* ptr = (byte*)&value; byte* ptr = (byte*)&value;
for (int i = 0; i < sizeof(float); i++) for (int i = 0; i < sizeof(float); i++)
_ptr[i] = ptr[i]; _ptr[i + offset] = ptr[i];
} }
/// <summary> /// <summary>
/// Gets the memory of the span as a string. /// Gets the memory of the span as a string.
@@ -101,11 +113,10 @@ namespace Cryville.Common.Pdt {
/// <param name="offset">The offset on the span to start reading from.</param> /// <param name="offset">The offset on the span to start reading from.</param>
/// <returns>The name of an undefined identifier.</returns> /// <returns>The name of an undefined identifier.</returns>
/// <exception cref="InvalidCastException">The span does not represent an undefined identifier.</exception> /// <exception cref="InvalidCastException">The span does not represent an undefined identifier.</exception>
public string AsIdentifier(int offset = 0) { public int AsIdentifier(int offset = 0) {
if (Type != PdtInternalType.Undefined && Type != PdtInternalType.Array) if (Type != PdtInternalType.Undefined && Type != PdtInternalType.Array)
throw new InvalidCastException("Not an identifier"); throw new InvalidCastException("Not an identifier");
var len = *(int*)(_ptr + offset); return *(int*)(_ptr + offset);
return new string((char*)(_ptr + offset + sizeof(int)), 0, len);
} }
internal void* TrustedAsOfLength(int len) { internal void* TrustedAsOfLength(int len) {
if (Length < len) if (Length < len)
@@ -119,7 +130,7 @@ namespace Cryville.Common.Pdt {
/// <param name="pc">The item count of the array.</param> /// <param name="pc">The item count of the array.</param>
/// <exception cref="InvalidCastException">The span does not represent an array.</exception> /// <exception cref="InvalidCastException">The span does not represent an array.</exception>
public void GetArraySuffix(out int arrtype, out int pc) { public void GetArraySuffix(out int arrtype, out int pc) {
if (Type != PdtInternalType.Array && Type != PdtInternalType.Array) if (Type != PdtInternalType.Vector && Type != PdtInternalType.Array)
throw new InvalidCastException("Not an array or vector"); throw new InvalidCastException("Not an array or vector");
arrtype = *(int*)(_ptr + Length - sizeof(int)); arrtype = *(int*)(_ptr + Length - sizeof(int));
if (Type == PdtInternalType.Array) pc = *(int*)(_ptr + Length - 2 * sizeof(int)); if (Type == PdtInternalType.Array) pc = *(int*)(_ptr + Length - 2 * sizeof(int));

View File

@@ -1,49 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
namespace Cryville.Common.Plist {
public class PlistConvert {
public static T Deserialize<T>(string file) {
return (T)Deserialize(typeof(T), PlistCS.Plist.readPlist(file));
}
public static object Deserialize(Type type, object obj, Binder binder = null) {
if (binder == null)
binder = BinderAttribute.CreateBinderOfType(type);
if (obj is IList) {
var lobj = (List<object>)obj;
foreach (var i in lobj) {
throw new NotImplementedException(); // TODO
}
}
else if (obj is IDictionary) {
var dobj = (Dictionary<string, object>)obj;
if (typeof(IDictionary).IsAssignableFrom(type)) {
var result = (IDictionary)ReflectionHelper.InvokeEmptyConstructor(type);
var it = type.GetGenericArguments()[1];
foreach (var i in dobj) {
var value = Deserialize(it, i.Value, binder);
result.Add(i.Key, value);
}
return result;
}
else {
var result = ReflectionHelper.InvokeEmptyConstructor(type);
foreach (var i in dobj) {
var imis = type.GetMember(i.Key);
if (imis.Length == 0) continue;
var imi = imis[0];
var it = ReflectionHelper.GetMemberType(imi);
var value = Deserialize(it, i.Value, binder);
ReflectionHelper.SetValue(imi, result, value, binder);
}
return result;
}
}
else return obj;
throw new Exception(); // TODO
}
}
}

View File

@@ -168,5 +168,19 @@ namespace Cryville.Common {
} }
return result; return result;
} }
/// <summary>
/// Gets the namespace qualified name of a type.
/// </summary>
/// <param name="type">The type.</param>
/// <returns>The namespace qualified name of the class.</returns>
public static string GetNamespaceQualifiedName(Type type) {
string result = type.Namespace + "." + type.Name;
var typeargs = type.GetGenericArguments();
if (typeargs.Length > 0) {
result = string.Format("{0}[{1}]", result, string.Join(",", from a in typeargs select GetNamespaceQualifiedName(a)));
}
return result;
}
} }
} }

View File

@@ -1,5 +1,6 @@
using System; using System;
using System.Text; using System.Text;
using System.Text.RegularExpressions;
namespace Cryville.Common { namespace Cryville.Common {
/// <summary> /// <summary>
@@ -33,5 +34,15 @@ namespace Cryville.Common {
b.Append((timeSpan.TotalSeconds % 60).ToString("00." + new string('0', digits))); b.Append((timeSpan.TotalSeconds % 60).ToString("00." + new string('0', digits)));
return b.ToString(); return b.ToString();
} }
/// <summary>
/// Escapes special characters in a file name.
/// </summary>
/// <param name="name">The file name excluding the extension.</param>
/// <returns>The escaped file name.</returns>
public static string EscapeFileName(string name) {
var result = Regex.Replace(name, @"[\/\\\<\>\:\x22\|\?\*\p{Cc}]", "_").TrimEnd(' ', '.');
if (result.Length == 0) return "_";
return result;
}
} }
} }

View File

@@ -9,14 +9,6 @@ namespace Cryville.Common.Unity {
return (num2 & num) == num; return (num2 & num) == num;
} }
public static void ShowException(Exception ex) {
ShowMessageBox(ex.ToString());
}
public static void ShowMessageBox(string message) {
GameObject.Instantiate<GameObject>(Resources.Load<GameObject>("Common/Popup")).GetComponent<Popup>().Message = message;
}
public static void Purge(Transform obj) { public static void Purge(Transform obj) {
foreach (Transform i in obj) foreach (Transform i in obj)
GameObject.Destroy(i.gameObject); GameObject.Destroy(i.gameObject);

View File

@@ -4,7 +4,7 @@ using UnityEngine;
namespace Cryville.Common.Unity.Input { namespace Cryville.Common.Unity.Input {
public delegate void InputEventDelegate(InputIdentifier id, InputVector vec); public delegate void InputEventDelegate(InputIdentifier id, InputVector vec);
public abstract class InputHandler : IDisposable { public abstract class InputHandler : IDisposable {
public InputEventDelegate Callback { private get; set; } public event InputEventDelegate OnInput;
~InputHandler() { ~InputHandler() {
Dispose(false); Dispose(false);
@@ -14,15 +14,27 @@ namespace Cryville.Common.Unity.Input {
GC.SuppressFinalize(this); GC.SuppressFinalize(this);
} }
public abstract void Activate(); public bool Activated { get; private set; }
public abstract void Deactivate(); public void Activate() {
if (Activated) return;
Activated = true;
ActivateImpl();
}
protected abstract void ActivateImpl();
public void Deactivate() {
if (!Activated) return;
Activated = false;
DeactivateImpl();
}
protected abstract void DeactivateImpl();
public abstract void Dispose(bool disposing); public abstract void Dispose(bool disposing);
public abstract bool IsNullable(int type); public abstract bool IsNullable(int type);
public abstract byte GetDimension(int type); public abstract byte GetDimension(int type);
public abstract string GetTypeName(int type); public abstract string GetTypeName(int type);
public abstract double GetCurrentTimestamp(); public abstract double GetCurrentTimestamp();
protected void OnInput(int type, int id, InputVector vec) { protected void Feed(int type, int id, InputVector vec) {
if (Callback != null) Callback(new InputIdentifier { Source = new InputSource { Handler = this, Type = type }, Id = id }, vec); var del = OnInput;
if (del != null) del(new InputIdentifier { Source = new InputSource { Handler = this, Type = type }, Id = id }, vec);
} }
} }
@@ -74,15 +86,6 @@ namespace Cryville.Common.Unity.Input {
} }
} }
public struct InputEvent {
public InputIdentifier Id { get; set; }
public InputVector From { get; set; }
public InputVector To { get; set; }
public override string ToString() {
return string.Format("[{0}] {1} -> {2}", Id, From, To);
}
}
public struct InputVector { public struct InputVector {
public double Time { get; set; } public double Time { get; set; }
public bool IsNull { get; set; } public bool IsNull { get; set; }

View File

@@ -12,17 +12,18 @@ namespace Cryville.Common.Unity.Input {
typeof(UnityTouchHandler), typeof(UnityTouchHandler),
}; };
readonly List<InputHandler> _handlers = new List<InputHandler>(); readonly List<InputHandler> _handlers = new List<InputHandler>();
readonly Dictionary<Type, InputHandler> _typemap = new Dictionary<Type, InputHandler>();
readonly Dictionary<InputHandler, double> _timeOrigins = new Dictionary<InputHandler, double>(); readonly Dictionary<InputHandler, double> _timeOrigins = new Dictionary<InputHandler, double>();
readonly object _lock = new object(); readonly object _lock = new object();
readonly Dictionary<InputIdentifier, InputVector> _vectors = new Dictionary<InputIdentifier, InputVector>(); readonly Dictionary<InputIdentifier, InputVector> _vectors = new Dictionary<InputIdentifier, InputVector>();
readonly List<InputEvent> _events = new List<InputEvent>(); readonly List<InputEvent> _events = new List<InputEvent>();
public InputManager() { public InputManager() {
var cb = new InputEventDelegate(Callback);
foreach (var t in HandlerRegistries) { foreach (var t in HandlerRegistries) {
try { try {
if (!typeof(InputHandler).IsAssignableFrom(t)) continue; if (!typeof(InputHandler).IsAssignableFrom(t)) continue;
var h = (InputHandler)ReflectionHelper.InvokeEmptyConstructor(t); var h = (InputHandler)ReflectionHelper.InvokeEmptyConstructor(t);
h.Callback = Callback; _typemap.Add(t, h);
h.OnInput += OnInput;
_handlers.Add(h); _handlers.Add(h);
_timeOrigins.Add(h, 0); _timeOrigins.Add(h, 0);
Logger.Log("main", 1, "Input", "Initialized {0}", ReflectionHelper.GetSimpleName(t)); Logger.Log("main", 1, "Input", "Initialized {0}", ReflectionHelper.GetSimpleName(t));
@@ -32,6 +33,9 @@ namespace Cryville.Common.Unity.Input {
} }
} }
} }
public InputHandler GetHandler(string name) {
return _typemap[Type.GetType(name)];
}
public void Activate() { public void Activate() {
lock (_lock) { lock (_lock) {
_events.Clear(); _events.Clear();
@@ -46,7 +50,7 @@ namespace Cryville.Common.Unity.Input {
public void Deactivate() { public void Deactivate() {
foreach (var h in _handlers) h.Deactivate(); foreach (var h in _handlers) h.Deactivate();
} }
void Callback(InputIdentifier id, InputVector vec) { void OnInput(InputIdentifier id, InputVector vec) {
lock (_lock) { lock (_lock) {
double timeOrigin = _timeOrigins[id.Source.Handler]; double timeOrigin = _timeOrigins[id.Source.Handler];
vec.Time += timeOrigin; vec.Time += timeOrigin;
@@ -77,4 +81,13 @@ namespace Cryville.Common.Unity.Input {
} }
} }
} }
public struct InputEvent {
public InputIdentifier Id { get; set; }
public InputVector From { get; set; }
public InputVector To { get; set; }
public override string ToString() {
return string.Format("[{0}] {1} -> {2}", Id, From, To);
}
}
} }

View File

@@ -0,0 +1,12 @@
using UnityEngine;
namespace Cryville.Common.Unity.Input {
public static class UnityCameraUtils {
public static Vector2 ScreenToWorldPoint(Vector2 pos) {
Vector3 i = pos;
i.z = -Camera.main.transform.localPosition.z;
i = Camera.main.ScreenToWorldPoint(i);
return i;
}
}
}

View File

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

View File

@@ -9,19 +9,19 @@ namespace Cryville.Common.Unity.Input {
public UnityKeyHandler() { } public UnityKeyHandler() { }
public override void Activate() { protected override void ActivateImpl() {
receiver = new GameObject("__keyrecv__"); receiver = new GameObject("__keyrecv__");
recvcomp = receiver.AddComponent<T>(); recvcomp = receiver.AddComponent<T>();
recvcomp.SetCallback(OnInput); recvcomp.SetCallback(Feed);
} }
public override void Deactivate() { protected override void DeactivateImpl() {
if (receiver) GameObject.Destroy(receiver); if (receiver) GameObject.Destroy(receiver);
} }
public override void Dispose(bool disposing) { public override void Dispose(bool disposing) {
if (disposing) { if (disposing) {
Deactivate(); DeactivateImpl();
} }
} }
@@ -38,7 +38,7 @@ namespace Cryville.Common.Unity.Input {
} }
public override double GetCurrentTimestamp() { public override double GetCurrentTimestamp() {
return Time.timeAsDouble; return Time.realtimeSinceStartupAsDouble;
} }
} }
@@ -49,8 +49,11 @@ namespace Cryville.Common.Unity.Input {
Callback = h; Callback = h;
} }
public abstract string GetKeyName(int type); public abstract string GetKeyName(int type);
void Awake() {
useGUILayout = false;
}
void Update() { void Update() {
double time = Time.timeAsDouble; double time = Time.realtimeSinceStartupAsDouble;
foreach (var k in Keys) { foreach (var k in Keys) {
Callback(k, 0, new InputVector(time, Vector3.zero)); Callback(k, 0, new InputVector(time, Vector3.zero));
} }
@@ -64,7 +67,7 @@ namespace Cryville.Common.Unity.Input {
void OnGUI() { void OnGUI() {
var e = Event.current; var e = Event.current;
if (e.keyCode == KeyCode.None) return; if (e.keyCode == KeyCode.None) return;
double time = Time.timeAsDouble; double time = Time.realtimeSinceStartupAsDouble;
var key = (int)e.keyCode; var key = (int)e.keyCode;
switch (e.type) { switch (e.type) {
case EventType.KeyDown: case EventType.KeyDown:
@@ -92,7 +95,7 @@ namespace Cryville.Common.Unity.Input {
} }
void OnGUI() { void OnGUI() {
var e = Event.current; var e = Event.current;
double time = Time.timeAsDouble; double time = Time.realtimeSinceStartupAsDouble;
var key = e.button; var key = e.button;
switch (e.type) { switch (e.type) {
case EventType.MouseDown: case EventType.MouseDown:

View File

@@ -12,18 +12,18 @@ namespace Cryville.Common.Unity.Input {
} }
} }
public override void Activate() { protected override void ActivateImpl() {
receiver = new GameObject("__mouserecv__"); receiver = new GameObject("__mouserecv__");
receiver.AddComponent<UnityMouseReceiver>().SetHandler(this); receiver.AddComponent<UnityMouseReceiver>().SetHandler(this);
} }
public override void Deactivate() { protected override void DeactivateImpl() {
if (receiver) GameObject.Destroy(receiver); if (receiver) GameObject.Destroy(receiver);
} }
public override void Dispose(bool disposing) { public override void Dispose(bool disposing) {
if (disposing) { if (disposing) {
Deactivate(); DeactivateImpl();
} }
} }
@@ -45,7 +45,7 @@ namespace Cryville.Common.Unity.Input {
} }
public override double GetCurrentTimestamp() { public override double GetCurrentTimestamp() {
return Time.timeAsDouble; return Time.realtimeSinceStartupAsDouble;
} }
public class UnityMouseReceiver : MonoBehaviour { public class UnityMouseReceiver : MonoBehaviour {
@@ -54,10 +54,9 @@ namespace Cryville.Common.Unity.Input {
handler = h; handler = h;
} }
void Update() { void Update() {
double time = Time.timeAsDouble; double time = Time.realtimeSinceStartupAsDouble;
Vector2 pos = unity::Input.mousePosition; Vector3 pos = UnityCameraUtils.ScreenToWorldPoint(unity::Input.mousePosition);
pos.y = Screen.height - pos.y; handler.Feed(0, 0, new InputVector(time, pos));
handler.OnInput(0, 0, new InputVector(time, pos));
} }
} }
} }

View File

@@ -12,18 +12,18 @@ namespace Cryville.Common.Unity.Input {
} }
} }
public override void Activate() { protected override void ActivateImpl() {
receiver = new GameObject("__touchrecv__"); receiver = new GameObject("__touchrecv__");
receiver.AddComponent<UnityPointerReceiver>().SetHandler(this); receiver.AddComponent<UnityPointerReceiver>().SetHandler(this);
} }
public override void Deactivate() { protected override void DeactivateImpl() {
if (receiver) GameObject.Destroy(receiver); if (receiver) GameObject.Destroy(receiver);
} }
public override void Dispose(bool disposing) { public override void Dispose(bool disposing) {
if (disposing) { if (disposing) {
Deactivate(); DeactivateImpl();
} }
} }
@@ -45,7 +45,7 @@ namespace Cryville.Common.Unity.Input {
} }
public override double GetCurrentTimestamp() { public override double GetCurrentTimestamp() {
return Time.timeAsDouble; return Time.realtimeSinceStartupAsDouble;
} }
public class UnityPointerReceiver : MonoBehaviour { public class UnityPointerReceiver : MonoBehaviour {
@@ -54,18 +54,17 @@ namespace Cryville.Common.Unity.Input {
handler = h; handler = h;
} }
void Update() { void Update() {
double time = Time.timeAsDouble; double time = Time.realtimeSinceStartupAsDouble;
for (int i = 0; i < unity::Input.touchCount; i++) { for (int i = 0; i < unity::Input.touchCount; i++) {
var t = unity::Input.GetTouch(i); var t = unity::Input.GetTouch(i);
Vector2 pos = t.position; Vector2 pos = UnityCameraUtils.ScreenToWorldPoint(t.position);
pos.y = Screen.height - pos.y;
var vec = new InputVector(time, pos); var vec = new InputVector(time, pos);
if (t.phase == TouchPhase.Began || t.phase == TouchPhase.Stationary || t.phase == TouchPhase.Moved) { if (t.phase == TouchPhase.Began || t.phase == TouchPhase.Stationary || t.phase == TouchPhase.Moved) {
handler.OnInput(0, t.fingerId, vec); handler.Feed(0, t.fingerId, vec);
} }
else if (t.phase == TouchPhase.Ended || t.phase == TouchPhase.Canceled) { else if (t.phase == TouchPhase.Ended || t.phase == TouchPhase.Canceled) {
handler.OnInput(0, t.fingerId, vec); handler.Feed(0, t.fingerId, vec);
handler.OnInput(0, t.fingerId, new InputVector(time)); handler.Feed(0, t.fingerId, new InputVector(time));
} }
} }
} }

View File

@@ -56,40 +56,18 @@ namespace Cryville.Common.Unity.Input {
} }
} }
public override void Activate() {
RegisterWindowProc(WndProc);
if (!NativeMethods.RegisterTouchWindow(hMainWindow, NativeMethods.TOUCH_WINDOW_FLAGS.TWF_WANTPALM)) {
throw new InvalidOperationException("Failed to register touch window");
}
DisablePressAndHold();
}
public override void Deactivate() {
EnablePressAndHold();
if (!NativeMethods.UnregisterTouchWindow(hMainWindow)) {
throw new InvalidOperationException("Failed to unregister touch window");
}
UnregisterWindowProc();
}
void RegisterWindowProc(WndProcDelegate windowProc) {
newWndProc = windowProc;
newWndProcPtr = Marshal.GetFunctionPointerForDelegate(newWndProc);
oldWndProcPtr = SetWindowLongPtr(hMainWindow, -4, newWndProcPtr);
}
void UnregisterWindowProc() {
SetWindowLongPtr(hMainWindow, -4, oldWndProcPtr);
newWndProcPtr = IntPtr.Zero;
newWndProc = null;
}
public const int TABLET_DISABLE_PRESSANDHOLD = 0x00000001; public const int TABLET_DISABLE_PRESSANDHOLD = 0x00000001;
public const int TABLET_DISABLE_PENTAPFEEDBACK = 0x00000008; public const int TABLET_DISABLE_PENTAPFEEDBACK = 0x00000008;
public const int TABLET_DISABLE_PENBARRELFEEDBACK = 0x00000010; public const int TABLET_DISABLE_PENBARRELFEEDBACK = 0x00000010;
public const int TABLET_DISABLE_FLICKS = 0x00010000; public const int TABLET_DISABLE_FLICKS = 0x00010000;
protected void DisablePressAndHold() { protected override void ActivateImpl() {
newWndProc = WndProc;
newWndProcPtr = Marshal.GetFunctionPointerForDelegate(newWndProc);
oldWndProcPtr = SetWindowLongPtr(hMainWindow, -4, newWndProcPtr);
if (!NativeMethods.RegisterTouchWindow(hMainWindow, NativeMethods.TOUCH_WINDOW_FLAGS.TWF_WANTPALM)) {
throw new InvalidOperationException("Failed to register touch window");
}
pressAndHoldAtomID = NativeMethods.GlobalAddAtom(PRESS_AND_HOLD_ATOM); pressAndHoldAtomID = NativeMethods.GlobalAddAtom(PRESS_AND_HOLD_ATOM);
NativeMethods.SetProp(hMainWindow, PRESS_AND_HOLD_ATOM, NativeMethods.SetProp(hMainWindow, PRESS_AND_HOLD_ATOM,
TABLET_DISABLE_PRESSANDHOLD | // disables press and hold (right-click) gesture TABLET_DISABLE_PRESSANDHOLD | // disables press and hold (right-click) gesture
@@ -99,11 +77,17 @@ namespace Cryville.Common.Unity.Input {
); );
} }
protected void EnablePressAndHold() { protected override void DeactivateImpl() {
if (pressAndHoldAtomID != 0) { if (pressAndHoldAtomID != 0) {
NativeMethods.RemoveProp(hMainWindow, PRESS_AND_HOLD_ATOM); NativeMethods.RemoveProp(hMainWindow, PRESS_AND_HOLD_ATOM);
NativeMethods.GlobalDeleteAtom(pressAndHoldAtomID); NativeMethods.GlobalDeleteAtom(pressAndHoldAtomID);
} }
if (!NativeMethods.UnregisterTouchWindow(hMainWindow)) {
throw new InvalidOperationException("Failed to unregister touch window");
}
SetWindowLongPtr(hMainWindow, -4, oldWndProcPtr);
newWndProcPtr = IntPtr.Zero;
newWndProc = null;
} }
const string UnityWindowClassName = "UnityWndClass"; const string UnityWindowClassName = "UnityWndClass";
@@ -158,7 +142,7 @@ namespace Cryville.Common.Unity.Input {
} }
public override void Dispose(bool disposing) { public override void Dispose(bool disposing) {
Deactivate(); DeactivateImpl();
if (usePointerMessage) if (usePointerMessage)
NativeMethods.EnableMouseInPointer(false); NativeMethods.EnableMouseInPointer(false);
Instance = null; Instance = null;
@@ -230,7 +214,7 @@ namespace Cryville.Common.Unity.Input {
NativeMethods.POINT p = rawpinfo.ptPixelLocation; NativeMethods.POINT p = rawpinfo.ptPixelLocation;
NativeMethods.ScreenToClient(hMainWindow, ref p); NativeMethods.ScreenToClient(hMainWindow, ref p);
Vector2 _p = new Vector2(p.X, p.Y); Vector2 _p = UnityCameraUtils.ScreenToWorldPoint(new Vector2(p.X, Screen.height - p.Y));
double time = (double)rawpinfo.PerformanceCount / freq; double time = (double)rawpinfo.PerformanceCount / freq;
@@ -244,7 +228,7 @@ namespace Cryville.Common.Unity.Input {
default: type = 0; break; default: type = 0; break;
} }
if (rawpinfo.pointerFlags.HasFlag(NativeMethods.POINTER_FLAGS.POINTER_FLAG_CANCELED)) { if (rawpinfo.pointerFlags.HasFlag(NativeMethods.POINTER_FLAGS.POINTER_FLAG_CANCELED)) {
OnInput(type, id, new InputVector(time)); Feed(type, id, new InputVector(time));
return; return;
} }
@@ -253,11 +237,11 @@ namespace Cryville.Common.Unity.Input {
switch ((WindowMessages)msg) { switch ((WindowMessages)msg) {
case WindowMessages.WM_POINTERDOWN: case WindowMessages.WM_POINTERDOWN:
case WindowMessages.WM_POINTERUPDATE: case WindowMessages.WM_POINTERUPDATE:
OnInput(type, id, vec); Feed(type, id, vec);
break; break;
case WindowMessages.WM_POINTERUP: case WindowMessages.WM_POINTERUP:
OnInput(type, id, vec); Feed(type, id, vec);
OnInput(type, id, new InputVector(time)); Feed(type, id, new InputVector(time));
break; break;
} }
} }
@@ -316,7 +300,7 @@ namespace Cryville.Common.Unity.Input {
Y = touch.y / 100 Y = touch.y / 100
}; };
NativeMethods.ScreenToClient(hMainWindow, ref p); NativeMethods.ScreenToClient(hMainWindow, ref p);
Vector2 _p = new Vector2(p.X, p.Y); Vector2 _p = UnityCameraUtils.ScreenToWorldPoint(new Vector2(p.X, Screen.height - p.Y));
/*Vector2? _cs = null; /*Vector2? _cs = null;
if (touch.dwMask.HasFlag(NativeMethods.TOUCHINPUT_Mask.TOUCHINPUTMASKF_CONTACTAREA)) { if (touch.dwMask.HasFlag(NativeMethods.TOUCHINPUT_Mask.TOUCHINPUTMASKF_CONTACTAREA)) {
@@ -332,11 +316,11 @@ namespace Cryville.Common.Unity.Input {
if (touch.dwFlags.HasFlag(NativeMethods.TOUCHINPUT_Flags.TOUCHEVENTF_MOVE) || if (touch.dwFlags.HasFlag(NativeMethods.TOUCHINPUT_Flags.TOUCHEVENTF_MOVE) ||
touch.dwFlags.HasFlag(NativeMethods.TOUCHINPUT_Flags.TOUCHEVENTF_DOWN)) { touch.dwFlags.HasFlag(NativeMethods.TOUCHINPUT_Flags.TOUCHEVENTF_DOWN)) {
OnInput(255, id, vec); Feed(255, id, vec);
} }
else if (touch.dwFlags.HasFlag(NativeMethods.TOUCHINPUT_Flags.TOUCHEVENTF_UP)) { else if (touch.dwFlags.HasFlag(NativeMethods.TOUCHINPUT_Flags.TOUCHEVENTF_UP)) {
OnInput(255, id, vec); Feed(255, id, vec);
OnInput(255, id, new InputVector(time)); Feed(255, id, new InputVector(time));
} }
} }

View File

@@ -1,29 +0,0 @@
using UnityEngine;
using UnityEngine.UI;
namespace Cryville.Common.Unity {
public class Popup : MonoBehaviour {
public string Message = "";
LayoutElement layout;
float timer = 0;
#pragma warning disable IDE0051
void Start() {
layout = GetComponent<LayoutElement>();
GetComponentInChildren<Text>().text = Message;
transform.SetParent(GameObject.Find("PopupList").transform);
layout.minHeight = 0;
}
void Update() {
if (timer <= 0.8f) layout.minHeight = timer * 50;
else if (timer >= 5f) GameObject.Destroy(gameObject);
else if (timer >= 4.2f) layout.minHeight = (300 - timer) * 50;
timer += Time.deltaTime;
}
#pragma warning restore IDE0051
}
}

View File

@@ -133,10 +133,10 @@ namespace Cryville.Common.Unity {
prop.SetValue(Target, v, new object[]{ }); prop.SetValue(Target, v, new object[]{ });
} }
catch (TargetInvocationException ex) { catch (TargetInvocationException ex) {
CallHelper.ShowMessageBox(ex.InnerException.Message); // CallHelper.ShowMessageBox(ex.InnerException.Message);
} }
catch (Exception ex) { catch (Exception ex) {
CallHelper.ShowMessageBox(ex.Message); // CallHelper.ShowMessageBox(ex.Message);
} }
} }
UpdateValue(); UpdateValue();

View File

@@ -126,8 +126,8 @@ namespace Cryville.Common.Unity.UI {
void Update() { void Update() {
Vector2 cprectsize = ((RectTransform)transform.parent).rect.size; Vector2 cprectsize = ((RectTransform)transform.parent).rect.size;
if (cprectsize != pprectsize) { if (cprectsize != pprectsize) {
OnFrameUpdate();
pprectsize = cprectsize; pprectsize = cprectsize;
OnFrameUpdate();
} }
} }
#pragma warning restore IDE0051 #pragma warning restore IDE0051
@@ -200,8 +200,7 @@ namespace Cryville.Common.Unity.UI {
void GenerateLine(int index, int line) { void GenerateLine(int index, int line) {
for (int j = 0; j < LineItemCount; j++) { for (int j = 0; j < LineItemCount; j++) {
var child = GameObject.Instantiate(m_itemTemplate); var child = GameObject.Instantiate(m_itemTemplate, transform, false);
child.transform.SetParent(transform, false);
lines[index][j] = child; lines[index][j] = child;
} }
LoadLine(index, line); LoadLine(index, line);

View File

@@ -0,0 +1,22 @@
using Newtonsoft.Json;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace Cryville.Crtr.Browsing {
public class ChartResourceImporter : ResourceConverter {
static readonly string[] SUPPORTED_FORMATS = { ".umgc" };
public override string[] GetSupportedFormats() {
return SUPPORTED_FORMATS;
}
public override IEnumerable<Resource> ConvertFrom(FileInfo file) {
var meta = Path.Combine(file.Directory.FullName, "meta.json");
if (!File.Exists(meta)) throw new FileNotFoundException("Meta file for the chart not found");
using (StreamReader reader = new StreamReader(meta, Encoding.UTF8)) {
var data = JsonConvert.DeserializeObject<ChartMeta>(reader.ReadToEnd());
return new Resource[] { new ChartResource(data.name, file) };
}
}
}
}

View File

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

View File

@@ -47,11 +47,11 @@ namespace Cryville.Crtr.Browsing {
_cover.sprite = m_coverPlaceholder; _cover.sprite = m_coverPlaceholder;
if (data.Cover != null) data.Cover.Destination = DisplayCover; if (data.Cover != null) data.Cover.Destination = DisplayCover;
var meta = data.Meta; var meta = data.Meta;
_title.text = string.Format("{0}\n{1}", meta.song.name, meta.chart.name); _title.text = string.Format("{0}\n{1}", meta.song.name, meta.name);
_desc.text = string.Format( _desc.text = string.Format(
"Music artist: {0}\nCharter: {1}\nLength: {2}\nNote Count: {3}", "Music artist: {0}\nCharter: {1}\nLength: {2}\nNote Count: {3}",
meta.song.author, meta.chart.author, meta.song.author, meta.author,
TimeSpan.FromSeconds(meta.chart.length).ToString(3), meta.note_count TimeSpan.FromSeconds(meta.length).ToString(3), meta.note_count
); );
} }
private void DisplayCover(bool succeeded, Texture2D tex) { private void DisplayCover(bool succeeded, Texture2D tex) {
@@ -60,10 +60,10 @@ namespace Cryville.Crtr.Browsing {
} }
} }
public void OnPlay() { public void OnPlay() {
Master.Open(_id); Master.Open(_id, _data);
} }
public void OnConfig() { public void OnConfig() {
Master.OpenConfig(_id); Master.OpenConfig(_id, _data);
} }
} }
} }

View File

@@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using UnityEngine; using UnityEngine;
using Logger = Cryville.Common.Logger;
namespace Cryville.Crtr.Browsing { namespace Cryville.Crtr.Browsing {
internal class LegacyResourceManager : IResourceManager<ChartDetail> { internal class LegacyResourceManager : IResourceManager<ChartDetail> {
@@ -58,22 +59,25 @@ namespace Cryville.Crtr.Browsing {
public ResourceItemMeta GetItemMeta(int id) { public ResourceItemMeta GetItemMeta(int id) {
var item = items[id]; var item = items[id];
AsyncDelivery<Texture2D> cover = null; var meta = new ChartMeta();
var coverFile = item.GetFiles("cover.*");
if (coverFile.Length > 0) {
cover = new AsyncDelivery<Texture2D>();
var task = new LoadTextureTask(Game.FileProtocolPrefix + coverFile[0].FullName, cover.Deliver);
cover.CancelSource = task.Cancel;
Game.NetworkTaskWorker.SubmitNetworkTask(task);
}
string name = item.Name; string name = item.Name;
string desc = "(Unknown)"; string desc = "(Unknown)";
var metaFile = new FileInfo(item.FullName + "/meta.json"); var metaFile = new FileInfo(item.FullName + "/.umgc");
if (metaFile.Exists) { if (metaFile.Exists) {
using (var reader = new StreamReader(metaFile.FullName)) { using (var reader = new StreamReader(metaFile.FullName)) {
var meta = JsonConvert.DeserializeObject<ChartMeta>(reader.ReadToEnd()); meta = JsonConvert.DeserializeObject<ChartMeta>(reader.ReadToEnd());
name = meta.song.name; name = meta.song.name;
desc = meta.chart.name; desc = meta.name;
}
}
AsyncDelivery<Texture2D> cover = null;
if (meta.cover != null && meta.cover != "") {
var coverFile = item.GetFiles(meta.cover);
if (coverFile.Length > 0) {
cover = new AsyncDelivery<Texture2D>();
var task = new LoadTextureTask(Game.FileProtocolPrefix + coverFile[0].FullName, cover.Deliver);
cover.CancelSource = task.Cancel;
Game.NetworkTaskWorker.SubmitNetworkTask(task);
} }
} }
return new ResourceItemMeta { return new ResourceItemMeta {
@@ -86,21 +90,23 @@ namespace Cryville.Crtr.Browsing {
public ChartDetail GetItemDetail(int id) { public ChartDetail GetItemDetail(int id) {
var item = items[id]; var item = items[id];
AsyncDelivery<Texture2D> cover = null; var meta = new ChartMeta();
var coverFile = item.GetFiles("cover.*"); var metaFile = new FileInfo(item.FullName + "/.umgc");
if (coverFile.Length > 0) {
cover = new AsyncDelivery<Texture2D>();
var task = new LoadTextureTask(Game.FileProtocolPrefix + coverFile[0].FullName, cover.Deliver);
cover.CancelSource = task.Cancel;
Game.NetworkTaskWorker.SubmitNetworkTask(task);
}
ChartMeta meta = new ChartMeta();
var metaFile = new FileInfo(item.FullName + "/meta.json");
if (metaFile.Exists) { if (metaFile.Exists) {
using (var reader = new StreamReader(metaFile.FullName)) { using (var reader = new StreamReader(metaFile.FullName)) {
meta = JsonConvert.DeserializeObject<ChartMeta>(reader.ReadToEnd()); meta = JsonConvert.DeserializeObject<ChartMeta>(reader.ReadToEnd());
} }
} }
AsyncDelivery<Texture2D> cover = null;
if (meta.cover != null && meta.cover != "") {
var coverFile = item.GetFiles(meta.cover);
if (coverFile.Length > 0) {
cover = new AsyncDelivery<Texture2D>();
var task = new LoadTextureTask(Game.FileProtocolPrefix + coverFile[0].FullName, cover.Deliver);
cover.CancelSource = task.Cancel;
Game.NetworkTaskWorker.SubmitNetworkTask(task);
}
}
return new ChartDetail { return new ChartDetail {
Cover = cover, Cover = cover,
Meta = meta, Meta = meta,
@@ -108,39 +114,74 @@ namespace Cryville.Crtr.Browsing {
} }
public string GetItemPath(int id) { public string GetItemPath(int id) {
return items[id].Name + "/.umgc"; var item = items[id];
var meta = new ChartMeta();
var metaFile = new FileInfo(item.FullName + "/.umgc");
using (var reader = new StreamReader(metaFile.FullName)) {
meta = JsonConvert.DeserializeObject<ChartMeta>(reader.ReadToEnd());
}
return string.Format("{0}/{1}.json", items[id].Name, meta.data);
} }
public bool ImportItemFrom(string path) { public bool ImportItemFrom(string path) {
var file = new FileInfo(path); var file = new FileInfo(path);
if (!converters.ContainsKey(file.Extension)) return false; if (!converters.ContainsKey(file.Extension)) return false;
foreach (var converter in converters[file.Extension]) { foreach (var converter in converters[file.Extension]) {
var resources = converter.ConvertFrom(file); IEnumerable<Resource> resources = null;
try {
resources = converter.ConvertFrom(file);
}
catch (Exception ex) {
LogAndPopup(4, ex.Message);
return false;
}
foreach (var res in resources) { foreach (var res in resources) {
if (res is ChartResource) { if (!res.Valid) {
var tres = (ChartResource)res; LogAndPopup(3, "Attempt to import invalid resource: {0}", res);
}
else if (res is RawChartResource) {
var tres = (RawChartResource)res;
var dir = new DirectoryInfo(_rootPath + "/charts/" + res.Name); var dir = new DirectoryInfo(_rootPath + "/charts/" + res.Name);
if (!dir.Exists) dir.Create(); if (!dir.Exists) dir.Create();
using (var writer = new StreamWriter(dir.FullName + "/.umgc")) { using (var writer = new StreamWriter(dir.FullName + "/.json")) {
writer.Write(JsonConvert.SerializeObject(tres.Main, Game.GlobalJsonSerializerSettings)); writer.Write(JsonConvert.SerializeObject(tres.Main, Game.GlobalJsonSerializerSettings));
} }
using (var writer = new StreamWriter(dir.FullName + "/meta.json")) { using (var writer = new StreamWriter(dir.FullName + "/.umgc")) {
tres.Meta.data = "";
writer.Write(JsonConvert.SerializeObject(tres.Meta, Game.GlobalJsonSerializerSettings)); writer.Write(JsonConvert.SerializeObject(tres.Meta, Game.GlobalJsonSerializerSettings));
} }
if (tres.Meta.cover != null) {
var coverFile = new FileInfo(Path.Combine(file.Directory.FullName, tres.Meta.cover));
if (coverFile.Exists)
coverFile.CopyTo(Path.Combine(dir.FullName, tres.Meta.cover), true);
}
} }
else if (res is CoverResource) { else if (res is FileResource) {
var tres = (CoverResource)res; var tres = (FileResource)res;
var dir = new DirectoryInfo(_rootPath + "/charts/" + res.Name); DirectoryInfo dest;
if (!dir.Exists) dir.Create(); if (res is ChartResource)
var dest = new FileInfo(_rootPath + "/charts/" + res.Name + "/cover" + tres.Source.Extension); dest = new DirectoryInfo(_rootPath + "/charts/" + res.Name);
if (!dest.Exists) tres.Source.CopyTo(dest.FullName); else if (res is RulesetResource)
dest = new DirectoryInfo(_rootPath + "/rulesets/" + res.Name);
else if (res is SkinResource)
dest = new DirectoryInfo(_rootPath + "/skins/" + (res as SkinResource).RulesetName + "/" + res.Name);
else if (res is SongResource)
dest = new DirectoryInfo(_rootPath + "/songs/" + res.Name);
else {
LogAndPopup(3, "Attempt to import unsupported file resource: {0}", res);
continue;
}
if (!dest.Exists) {
dest.Create();
tres.Master.CopyTo(Path.Combine(dest.FullName, tres.Master.Extension));
foreach (var attachment in tres.Attachments) {
attachment.CopyTo(Path.Combine(dest.FullName, attachment.Name));
}
}
else LogAndPopup(1, "Resource already exists: {0}", res);
} }
else if (res is SongResource) { else {
var tres = (SongResource)res; LogAndPopup(3, "Attempt to import unsupported resource: {0}", res);
var dir = new DirectoryInfo(_rootPath + "/songs/" + res.Name);
if (!dir.Exists) dir.Create();
var dest = new FileInfo(_rootPath + "/songs/" + res.Name + "/.ogg");
if (!dest.Exists) tres.Source.CopyTo(dest.FullName);
} }
} }
return true; return true;
@@ -148,6 +189,12 @@ namespace Cryville.Crtr.Browsing {
return false; return false;
} }
void LogAndPopup(int level, string format, params object[] args) {
var msg = string.Format(format, args);
Logger.Log("main", level, "Resource", msg);
Popup.Create(msg);
}
public string[] GetSupportedFormats() { public string[] GetSupportedFormats() {
return converters.Keys.ToArray(); return converters.Keys.ToArray();
} }

View File

@@ -24,10 +24,6 @@ namespace Cryville.Crtr.Browsing {
const float SPEED = 8; const float SPEED = 8;
float _ratio; float _ratio;
#pragma warning disable IDE0051 #pragma warning disable IDE0051
void Start() {
m_handleArea.sizeDelta = new Vector2(m_handle.rect.height - m_handle.rect.width, 0);
}
void Update() { void Update() {
if (_value && _ratio != 1) { if (_value && _ratio != 1) {
_ratio += SPEED * Time.deltaTime; _ratio += SPEED * Time.deltaTime;
@@ -40,6 +36,10 @@ namespace Cryville.Crtr.Browsing {
UpdateGraphics(); UpdateGraphics();
} }
} }
void OnRectTransformDimensionsChange() {
m_handleArea.sizeDelta = new Vector2(m_handle.rect.height - m_handle.rect.width, 0);
}
#pragma warning restore IDE0051 #pragma warning restore IDE0051
void UpdateGraphics() { void UpdateGraphics() {

View File

@@ -60,7 +60,6 @@ namespace Cryville.Crtr.Browsing {
ev.callback.AddListener(e => OnPointerClick((PointerEventData)e)); ev.callback.AddListener(e => OnPointerClick((PointerEventData)e));
m_ctn.triggers.Add(ev); m_ctn.triggers.Add(ev);
m_handleArea.sizeDelta = new Vector2(m_handle.rect.height - m_handle.rect.width, 0);
if (MaxStep != 0) SetRatio(0.5f); if (MaxStep != 0) SetRatio(0.5f);
} }
@@ -70,6 +69,10 @@ namespace Cryville.Crtr.Browsing {
SetValueFromPos(pp); SetValueFromPos(pp);
} }
} }
void OnRectTransformDimensionsChange() {
m_handleArea.sizeDelta = new Vector2(m_handle.rect.height - m_handle.rect.width, 0);
}
#pragma warning restore IDE0051 #pragma warning restore IDE0051
Vector2 pp; Vector2 pp;

View File

@@ -0,0 +1,28 @@
using UnityEngine.UI;
namespace Cryville.Crtr.Browsing {
public class PVPString : PropertyValuePanel {
string m_value;
public override object Value {
get {
return m_value;
}
set {
m_value = (string)value;
_inputField.text = m_value;
}
}
InputField _inputField;
void Awake() {
_inputField = GetComponent<InputField>();
_inputField.onValueChanged.AddListener(OnValueChanged);
}
void OnValueChanged(string value) {
m_value = value;
Callback(Value);
}
}
}

View File

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

View File

@@ -32,8 +32,7 @@ namespace Cryville.Crtr.Browsing {
public void Load(string name, IEnumerable<PropertyInfo> props, object target) { public void Load(string name, IEnumerable<PropertyInfo> props, object target) {
Name = name.ToUpper(); Name = name.ToUpper();
foreach (var prop in props) { foreach (var prop in props) {
var obj = GameObject.Instantiate<GameObject>(m_propertyPrefab); var obj = GameObject.Instantiate<GameObject>(m_propertyPrefab, transform, false);
obj.transform.SetParent(transform, false);
obj.GetComponent<PropertyPanel>().Load(prop, target); obj.GetComponent<PropertyPanel>().Load(prop, target);
} }
} }

View File

@@ -10,6 +10,8 @@ namespace Cryville.Crtr.Browsing {
GameObject m_bool; GameObject m_bool;
[SerializeField] [SerializeField]
GameObject m_number; GameObject m_number;
[SerializeField]
GameObject m_string;
PropertyInfo _property; PropertyInfo _property;
object _target; object _target;
@@ -32,8 +34,9 @@ namespace Cryville.Crtr.Browsing {
GameObject vp; GameObject vp;
if (prop.PropertyType == typeof(bool)) vp = m_bool; if (prop.PropertyType == typeof(bool)) vp = m_bool;
else if (prop.PropertyType == typeof(float) || prop.PropertyType == typeof(int)) vp = m_number; else if (prop.PropertyType == typeof(float) || prop.PropertyType == typeof(int)) vp = m_number;
else if (prop.PropertyType == typeof(string)) vp = m_string;
else return; else return;
_value = GameObject.Instantiate(vp, _valueContainer).GetComponent<PropertyValuePanel>(); _value = GameObject.Instantiate(vp, _valueContainer, false).GetComponent<PropertyValuePanel>();
if (_value is PVPNumber) { if (_value is PVPNumber) {
var t = (PVPNumber)_value; var t = (PVPNumber)_value;
t.IntegerMode = prop.PropertyType == typeof(int); t.IntegerMode = prop.PropertyType == typeof(int);

View File

@@ -1,5 +1,6 @@
using Cryville.Common.Unity; using Cryville.Common.Unity;
using Cryville.Common.Unity.UI; using Cryville.Common.Unity.UI;
using System;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
@@ -29,9 +30,13 @@ namespace Cryville.Crtr.Browsing {
private bool LoadItem(int id, GameObject obj) { private bool LoadItem(int id, GameObject obj) {
var bi = obj.GetComponent<BrowserItem>(); var bi = obj.GetComponent<BrowserItem>();
if (bi.Id == id) return true; try {
var item = ResourceManager.GetItemMeta(id); var item = ResourceManager.GetItemMeta(id);
bi.Load(id, item); bi.Load(id, item);
}
catch (Exception) {
bi.Load(id, new ResourceItemMeta { Name = "<color=#ff0000>Invalid resource</color>" });
}
return true; return true;
} }
@@ -60,11 +65,11 @@ namespace Cryville.Crtr.Browsing {
private void OnAddDialogClosed() { private void OnAddDialogClosed() {
if (_dialog.FileName == null) return; if (_dialog.FileName == null) return;
if (ResourceManager.ImportItemFrom(_dialog.FileName)) { if (ResourceManager.ImportItemFrom(_dialog.FileName)) {
Debug.Log("Import succeeded"); // TODO Popup.Create("Import succeeded");
OnPathClicked(ResourceManager.CurrentDirectory.Length - 1); OnPathClicked(ResourceManager.CurrentDirectory.Length - 1);
} }
else { else {
Debug.Log("Import failed"); // TODO Popup.Create("Import failed");
} }
} }
} }

View File

@@ -1,5 +1,6 @@
using Cryville.Common; using Cryville.Common;
using Cryville.Common.Unity.UI; using Cryville.Common.Unity.UI;
using Newtonsoft.Json;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
using UnityEngine.SceneManagement; using UnityEngine.SceneManagement;
@@ -64,8 +65,8 @@ namespace Cryville.Crtr.Browsing {
_units[_slideDest + 1].SlideToRight(); _units[_slideDest + 1].SlideToRight();
} }
public void Open(int id) { public void Open(int id, ChartDetail detail) {
SetDataSettings(id); SetDataSettings(id, detail);
#if UNITY_5_3_OR_NEWER #if UNITY_5_3_OR_NEWER
SceneManager.LoadScene("Play", LoadSceneMode.Additive); SceneManager.LoadScene("Play", LoadSceneMode.Additive);
#else #else
@@ -74,8 +75,8 @@ namespace Cryville.Crtr.Browsing {
GameObject.Find("/Master").GetComponent<Master>().HideMenu(); GameObject.Find("/Master").GetComponent<Master>().HideMenu();
} }
public void OpenConfig(int id) { public void OpenConfig(int id, ChartDetail detail) {
SetDataSettings(id); SetDataSettings(id, detail);
#if UNITY_5_3_OR_NEWER #if UNITY_5_3_OR_NEWER
SceneManager.LoadScene("Config", LoadSceneMode.Additive); SceneManager.LoadScene("Config", LoadSceneMode.Additive);
#else #else
@@ -84,9 +85,9 @@ namespace Cryville.Crtr.Browsing {
GameObject.Find("/Master").GetComponent<Master>().HideMenu(); GameObject.Find("/Master").GetComponent<Master>().HideMenu();
} }
void SetDataSettings(int id) { void SetDataSettings(int id, ChartDetail detail) {
Settings.Default.LoadRuleset = "key/.umgr"; Settings.Default.LoadRuleset = detail.Meta.ruleset + "/.umgr";
Settings.Default.LoadSkin = "key/0/.umgs"; Settings.Default.LoadRulesetConfig = detail.Meta.ruleset + ".json";
Settings.Default.LoadChart = MainBrowser.ResourceManager.GetItemPath(id); Settings.Default.LoadChart = MainBrowser.ResourceManager.GetItemPath(id);
} }
} }
@@ -97,16 +98,22 @@ namespace Cryville.Crtr.Browsing {
} }
#pragma warning disable IDE1006 #pragma warning disable IDE1006
public struct ChartMeta { public class MetaInfo {
public MetaInfo song { get; set; } public string name { get; set; }
public MetaInfo chart { get; set; } public string author { get; set; }
public struct MetaInfo { [JsonRequired]
public string name { get; set; } public string data { get; set; }
public string author { get; set; } }
public float length { get; set; } public class SongMetaInfo {
} public string name { get; set; }
public string author { get; set; }
}
public class ChartMeta : MetaInfo {
public SongMetaInfo song { get; set; }
public float length { get; set; }
public string ruleset { get; set; } public string ruleset { get; set; }
public int note_count { get; set; } public int note_count { get; set; }
public string cover { get; set; }
} }
#pragma warning restore IDE1006 #pragma warning restore IDE1006
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,5 @@
using Newtonsoft.Json; using Cryville.Common;
using Newtonsoft.Json;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
@@ -112,19 +113,19 @@ namespace Cryville.Crtr {
} }
[JsonIgnore] [JsonIgnore]
public Dictionary<string, PropSrc> PropSrcs { get; private set; } public Dictionary<int, PropSrc> PropSrcs { get; private set; }
protected void SubmitPropSrc(string name, PropSrc property) { protected void SubmitPropSrc(string name, PropSrc property) {
PropSrcs.Add(name, property); PropSrcs.Add(IdentifierManager.SharedInstance.Request(name), property);
} }
[JsonIgnore] [JsonIgnore]
public Dictionary<string, PropOp> PropOps { get; private set; } public Dictionary<int, PropOp> PropOps { get; private set; }
protected void SubmitPropOp(string name, PropOp property) { protected void SubmitPropOp(string name, PropOp property) {
PropOps.Add(name, property); PropOps.Add(IdentifierManager.SharedInstance.Request(name), property);
} }
protected ChartEvent() { protected ChartEvent() {
PropSrcs = new Dictionary<string, PropSrc>(); PropSrcs = new Dictionary<int, PropSrc>();
PropOps = new Dictionary<string, PropOp>(); PropOps = new Dictionary<int, PropOp>();
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));
@@ -231,7 +232,7 @@ namespace Cryville.Crtr {
} }
public override int Priority { public override int Priority {
get { return 0; } get { return 10; }
} }
public class Group : EventContainer { public class Group : EventContainer {
@@ -253,13 +254,13 @@ namespace Cryville.Crtr {
} }
} }
public override int Priority { public override int Priority {
get { return 0; } get { return 10; }
} }
} }
public class Track : EventContainer { public class Track : EventContainer {
public override int Priority { public override int Priority {
get { return 0; } get { return 10; }
} }
} }
@@ -274,9 +275,9 @@ namespace Cryville.Crtr {
private void LoadFromString(string s) { private void LoadFromString(string s) {
Match m = Regex.Match(s, @"^(.+?)(#(\d+))?(@(.+?))?(\^(.+?))?(\*(.+?))?(:(.+))?$"); Match m = Regex.Match(s, @"^(.+?)(#(\d+))?(@(.+?))?(\^(.+?))?(\*(.+?))?(:(.+))?$");
if (!m.Success) throw new ArgumentException(); // TODO if (!m.Success) throw new ArgumentException("Invalid motion string format");
name = new MotionName(m.Groups[1].Value); name = new Identifier(m.Groups[1].Value);
var registry = ChartPlayer.motionRegistry[name.MainName]; var registry = ChartPlayer.motionRegistry[name];
if (m.Groups[3].Success) { if (m.Groups[3].Success) {
ushort id = ushort.Parse(m.Groups[3].Value); ushort id = ushort.Parse(m.Groups[3].Value);
Vec1 time = m.Groups[5].Success ? new Vec1(m.Groups[5].Value) : null; Vec1 time = m.Groups[5].Success ? new Vec1(m.Groups[5].Value) : null;
@@ -312,15 +313,15 @@ namespace Cryville.Crtr {
return result; return result;
} }
private MotionName name; private Identifier name;
[JsonIgnore] [JsonIgnore]
public MotionName Name { public Identifier Name {
get { get {
return name; return name;
} }
private set { private set {
MotionRegistry reg; MotionRegistry reg;
if (!ChartPlayer.motionRegistry.TryGetValue(value.MainName, out reg)) if (!ChartPlayer.motionRegistry.TryGetValue(value, out reg))
throw new ArgumentException("Invalid motion name"); throw new ArgumentException("Invalid motion name");
if (RelativeNode != null) RelativeNode.Value = reg.InitValue; if (RelativeNode != null) RelativeNode.Value = reg.InitValue;
else AbsoluteValue = reg.InitValue; else AbsoluteValue = reg.InitValue;
@@ -341,7 +342,7 @@ namespace Cryville.Crtr {
public float sumfix = 0.0f; public float sumfix = 0.0f;
public override int Priority { public override int Priority {
get { return -4; } get { return -2; }
} }
public Motion() { public Motion() {
@@ -350,16 +351,16 @@ namespace Cryville.Crtr {
else return AbsoluteValue; else return AbsoluteValue;
})); }));
SubmitPropOp("motion", new PropOp.String(v => motion = v)); SubmitPropOp("motion", new PropOp.String(v => motion = v));
SubmitPropOp("name", new PropOp.String(v => { SubmitPropOp("name", new PropOp.Identifier(v => {
var n = new MotionName(v); var n = new Identifier(v);
if (Name.Equals(n)) { } if (Name.Equals(n)) { }
else if (Name.Equals(default(MotionName))) Name = n; else if (Name.Equals(default(Identifier))) Name = n;
else throw new RulesetViolationException(string.Format( else throw new RulesetViolationException(string.Format(
"Motion name not matched, expected {0}, got {1}", n, Name "Motion name not matched, expected {0}, got {1}", n, Name
)); ));
})); }));
SubmitPropOp("value", new VectorOp(v => { SubmitPropOp("value", new VectorOp(v => {
var vec = Vector.Construct(ChartPlayer.motionRegistry[Name.MainName].Type, v); var vec = Vector.Construct(ChartPlayer.motionRegistry[Name].Type, v);
if (RelativeNode != null) RelativeNode.Value = vec; if (RelativeNode != null) RelativeNode.Value = vec;
else AbsoluteValue = vec; else AbsoluteValue = vec;
})); }));
@@ -376,14 +377,6 @@ namespace Cryville.Crtr {
} }
} }
public Note() {
SubmitPropSrc("track", new PropSrc.Float(() => {
var i = motions.FirstOrDefault(m => m.RelativeNode == null && m.Name.MainName == "track");
if (i == null) return ((Vec1)ChartPlayer.motionRegistry["track"].InitValue).Value;
else return ((Vec1)i.AbsoluteValue).Value;
}));
}
public override EventList GetEventsOfType(string type) { public override EventList GetEventsOfType(string type) {
switch (type) { switch (type) {
case "judges": return new EventList<Judge>(judges); case "judges": return new EventList<Judge>(judges);
@@ -391,19 +384,25 @@ namespace Cryville.Crtr {
} }
} }
public override int Priority { public override int Priority {
get { return 2; } get { return 12; }
} }
} }
public class Judge : ChartEvent { public class Judge : ChartEvent {
public string name; [JsonIgnore]
public Identifier Id;
public string name {
get { return Id.ToString(); }
set { Id = new Identifier(value); }
}
public override int Priority { public override int Priority {
get { return -2; } get { return 0; }
} }
public Judge() { public Judge() {
SubmitPropSrc("name", new PropSrc.String(() => name)); SubmitPropSrc("name", new PropSrc.Identifier(() => Id.Key));
SubmitPropOp("name", new PropOp.String(v => name = v)); SubmitPropOp("name", new PropOp.Identifier(v => Id = new Identifier(v)));
} }
} }
@@ -414,7 +413,7 @@ namespace Cryville.Crtr {
public float? tempo; public float? tempo;
public override int Priority { public override int Priority {
get { return -6; } get { return -4; }
} }
} }

View File

@@ -37,9 +37,9 @@ namespace Cryville.Crtr {
else if (ev.Unstamped == null) { } else if (ev.Unstamped == null) { }
else if (ev.Unstamped is Chart.Sound) { else if (ev.Unstamped is Chart.Sound) {
Chart.Sound tev = (Chart.Sound)ev.Unstamped; Chart.Sound tev = (Chart.Sound)ev.Unstamped;
var source = new LibavFileAudioSource( var dir = new DirectoryInfo(Game.GameDataPath + "/songs/" + tev.id);
Game.GameDataPath + "/songs/" + tev.id + "/.ogg" var files = dir.GetFiles();
); var source = new LibavFileAudioSource(files[0].FullName);
source.SelectStream(); source.SelectStream();
sounds.Add(source); sounds.Add(source);
Game.AudioSession.Sequence( Game.AudioSession.Sequence(

View File

@@ -1,8 +1,7 @@
//#define NO_THREAD
#define BUILD #define BUILD
using Cryville.Common; using Cryville.Common;
using Cryville.Common.Plist; using Cryville.Crtr.Config;
using Cryville.Crtr.Event; using Cryville.Crtr.Event;
using Newtonsoft.Json; using Newtonsoft.Json;
using System; using System;
@@ -26,8 +25,7 @@ namespace Cryville.Crtr {
Ruleset ruleset; Ruleset ruleset;
PdtRuleset pruleset; PdtRuleset pruleset;
Dictionary<string, Texture2D> texs; Dictionary<string, Texture2D> texs;
public static Dictionary<string, Cocos2dFrames.Frame> frames; public static Dictionary<string, SpriteFrame> frames;
List<Cocos2dFrames> plists;
readonly Queue<string> texLoadQueue = new Queue<string>(); readonly Queue<string> texLoadQueue = new Queue<string>();
#if UNITY_5_4_OR_NEWER #if UNITY_5_4_OR_NEWER
@@ -52,6 +50,7 @@ namespace Cryville.Crtr {
public static Rect hitRect; public static Rect hitRect;
public static Plane[] frustumPlanes; public static Plane[] frustumPlanes;
RulesetConfig _rscfg;
static bool disableGC = true; static bool disableGC = true;
static float clippingDist = 1f; static float clippingDist = 1f;
static float renderDist = 6f; static float renderDist = 6f;
@@ -62,20 +61,11 @@ namespace Cryville.Crtr {
static float startOffset = 0; static float startOffset = 0;
public static float sv = 16f; public static float sv = 16f;
public static Dictionary<string, MotionRegistry> motionRegistry = new Dictionary<string, MotionRegistry>(); public static Dictionary<Identifier, MotionRegistry> motionRegistry = new Dictionary<Identifier, MotionRegistry>();
public static PdtEvaluator etor; public static PdtEvaluator etor;
~ChartPlayer() { InputProxy inputProxy;
Dispose();
}
public void Dispose() {
#if !NO_THREAD
if (loadThread != null) loadThread.Abort();
#endif
if (texLoader != null) texLoader.Dispose();
}
#region MonoBehaviour #region MonoBehaviour
void Start() { void Start() {
@@ -93,140 +83,153 @@ namespace Cryville.Crtr {
texHandler = new DownloadHandlerTexture(); texHandler = new DownloadHandlerTexture();
#if BUILD #if BUILD
Play(); try {
Play();
}
catch (Exception ex) {
Game.LogException("Load/WorkerThread", "An error occured while loading the data", ex);
Popup.CreateException(ex);
ReturnToMenu();
}
#endif #endif
// Camera.main.RenderToCubemap(); // Camera.main.RenderToCubemap();
} }
void OnDestroy() {
if (cbus != null) cbus.Dispose();
if (bbus != null) bbus.Dispose();
if (tbus != null) tbus.Dispose();
if (nbus != null) nbus.Dispose();
if (loadThread != null) loadThread.Abort();
if (texLoader != null) texLoader.Dispose();
if (inputProxy != null) inputProxy.Dispose();
if (texs != null) foreach (var t in texs) Texture.Destroy(t.Value);
Camera.onPostRender -= OnCameraPostRender;
GC.Collect();
}
bool texloaddone; bool texloaddone;
diag::Stopwatch texloadtimer = new diag::Stopwatch(); diag::Stopwatch texloadtimer = new diag::Stopwatch();
bool firstFrame; bool firstFrame;
double atime0;
void Update() { void Update() {
// if (Input.GetKeyDown(KeyCode.Return)) TogglePlay(); if (started) GameUpdate();
if (started) { else if (loadThread != null) LoadUpdate();
try { if (logEnabled) LogUpdate();
if (Screen.width != screenSize.x || Screen.height != screenSize.y) else Game.MainLogger.Enumerate((level, module, msg) => { });
throw new InvalidOperationException("Window resized while playing"); }
float dt = firstFrame void GameUpdate() {
try {
if (Screen.width != screenSize.x || Screen.height != screenSize.y)
throw new InvalidOperationException("Window resized while playing");
float dt = firstFrame
? 1f / Application.targetFrameRate ? 1f / Application.targetFrameRate
: Time.deltaTime; : Time.deltaTime;
firstFrame = false; firstFrame = false;
cbus.ForwardByTime(dt); inputProxy.ForceTick();
bbus.ForwardByTime(dt); cbus.ForwardByTime(dt);
UnityEngine.Profiling.Profiler.BeginSample("ChartPlayer.FeedJudge"); bbus.ForwardByTime(dt);
judge.StartFrame(); UnityEngine.Profiling.Profiler.BeginSample("ChartPlayer.Forward");
Game.InputManager.EnumerateEvents(ev => { UnityEngine.Profiling.Profiler.BeginSample("EventBus.Copy");
// Logger.Log("main", 0, "Input", ev.ToString()); bbus.CopyTo(2, tbus);
judge.Feed(ev); bbus.CopyTo(3, nbus);
}); UnityEngine.Profiling.Profiler.EndSample();
judge.EndFrame(); float step = autoRenderStep ? ( firstFrame
UnityEngine.Profiling.Profiler.EndSample();
UnityEngine.Profiling.Profiler.BeginSample("ChartPlayer.Forward");
UnityEngine.Profiling.Profiler.BeginSample("EventBus.Copy");
bbus.CopyTo(2, tbus);
bbus.CopyTo(3, nbus);
UnityEngine.Profiling.Profiler.EndSample();
float step = autoRenderStep ? ( firstFrame
? 1f / Application.targetFrameRate ? 1f / Application.targetFrameRate
: Time.smoothDeltaTime : Time.smoothDeltaTime
) : renderStep; ) : renderStep;
actualRenderStep = step; actualRenderStep = step;
nbus.ForwardStepByTime(clippingDist, step); nbus.ForwardStepByTime(clippingDist, step);
nbus.BroadcastEndUpdate(); nbus.BroadcastEndUpdate();
nbus.Anchor(); nbus.Anchor();
tbus.ForwardStepByTime(clippingDist, step); tbus.ForwardStepByTime(clippingDist, step);
tbus.ForwardStepByTime(renderDist, step); tbus.ForwardStepByTime(renderDist, step);
tbus.BroadcastEndUpdate(); tbus.BroadcastEndUpdate();
UnityEngine.Profiling.Profiler.EndSample(); UnityEngine.Profiling.Profiler.EndSample();
}
catch (Exception ex) {
Game.LogException("Game", "An error occured while playing", ex);
Stop();
}
} }
#if !NO_THREAD catch (Exception ex) {
else if (loadThread != null) { Game.LogException("Game", "An error occured while playing", ex);
if (texLoader != null) { Popup.CreateException(ex);
string url = texLoader.url; Stop();
string name = StringUtils.TrimExt(url.Substring(url.LastIndexOfAny(new char[] {'/', '\\'}) + 1)); }
}
void LoadUpdate() {
if (texLoader != null) {
string url = texLoader.url;
string name = StringUtils.TrimExt(url.Substring(url.LastIndexOfAny(new char[] {'/', '\\'}) + 1));
#if UNITY_5_4_OR_NEWER #if UNITY_5_4_OR_NEWER
if (texHandler.isDone) { if (texHandler.isDone) {
var tex = texHandler.texture; var tex = texHandler.texture;
texs.Add(name, tex); tex.wrapMode = TextureWrapMode.Clamp;
Logger.Log("main", 0, "Load/MainThread", "Loaded texture {0} ({1} bytes)", name, texLoader.downloadedBytes); texs.Add(name, tex);
texLoader.Dispose(); texLoader.Dispose();
texHandler.Dispose(); texHandler.Dispose();
texLoader = null; texLoader = null;
}
else if (texLoader.downloadProgress != 0) {
Logger.Log("main", 0, "Load/MainThread", "Loading texture {0} {1:P0}", name, texLoader.downloadProgress);
}
#else
if (texLoader.isDone) {
var tex = texLoader.texture;
texs.Add(name, tex);
Logger.Log("main", 0, "Load/MainThread", "Loaded texture {0} ({1} bytes)", name, texLoader.bytesDownloaded);
texLoader.Dispose();
texLoader = null;
}
else if (texLoader.progress != 0) {
Logger.Log("main", 0, "Load/MainThread", "Loading texture {0} {1:P0}", name, texLoader.progress);
}
#endif
} }
if (texLoader == null) #else
if (texLoadQueue.Count > 0) { if (texLoader.isDone) {
var tex = texLoader.texture;
tex.wrapMode = TextureWrapMode.Clamp;
texs.Add(name, tex);
texLoader.Dispose();
texLoader = null;
}
#endif
}
if (texLoader == null)
if (texLoadQueue.Count > 0) {
#if UNITY_5_4_OR_NEWER #if UNITY_5_4_OR_NEWER
texHandler = new DownloadHandlerTexture(); texHandler = new DownloadHandlerTexture();
texLoader = new UnityWebRequest(Game.FileProtocolPrefix + texLoadQueue.Dequeue(), "GET", texHandler, null); texLoader = new UnityWebRequest(Game.FileProtocolPrefix + texLoadQueue.Dequeue(), "GET", texHandler, null);
texLoader.SendWebRequest(); texLoader.SendWebRequest();
#else #else
texLoader = new WWW(Game.FileProtocolPrefix + texLoadQueue.Dequeue()); texLoader = new WWW(Game.FileProtocolPrefix + texLoadQueue.Dequeue());
#endif #endif
} }
else if (!texloaddone) { else if (!texloaddone) {
texloaddone = true; texloaddone = true;
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 (cbus == null) { if (threadException != null) {
Logger.Log("main", 4, "Load/MainThread", "Load failed"); Logger.Log("main", 4, "Load/MainThread", "Load failed");
loadThread = null; loadThread = null;
Popup.CreateException(threadException);
#if BUILD #if BUILD
ReturnToMenu(); ReturnToMenu();
#endif #endif
} }
else if (texLoader == null) { else if (texLoader == null) {
Prehandle(); Prehandle();
loadThread = null; loadThread = null;
}
} }
} }
#endif }
if (logEnabled) { string timetext = string.Empty;
string _logs = logs.text; void LogUpdate() {
Game.MainLogger.Enumerate((level, module, msg) => { string _logs = logs.text;
string color; Game.MainLogger.Enumerate((level, module, msg) => {
switch (level) { string color;
case 0: color = "#888888"; break; switch (level) {
case 1: color = "#bbbbbb"; break; case 0: color = "#888888"; break;
case 2: color = "#0088ff"; break; case 1: color = "#bbbbbb"; break;
case 3: color = "#ffff00"; break; case 2: color = "#0088ff"; break;
case 4: color = "#ff0000"; break; case 3: color = "#ffff00"; break;
case 5: color = "#bb0000"; break; case 4: color = "#ff0000"; break;
default: color = "#ff00ff"; break; case 5: color = "#bb0000"; break;
} default: color = "#ff00ff"; break;
_logs += string.Format( }
"\r\n<color={1}bb><{2}> {3}</color>", _logs += string.Format(
DateTime.UtcNow.ToString("s"), color, module, msg "\r\n<color={1}bb><{2}> {3}</color>",
); DateTime.UtcNow.ToString("s"), color, module, msg
}); );
logs.text = _logs.Substring(Mathf.Max(0, _logs.IndexOf('\n', Mathf.Max(0, _logs.Length - 4096)))); });
var sttext = string.Format( logs.text = _logs.Substring(Mathf.Max(0, _logs.IndexOf('\n', Mathf.Max(0, _logs.Length - 4096))));
var sttext = string.Format(
"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}",
1 / Time.deltaTime, 1 / Time.deltaTime,
1 / Time.smoothDeltaTime, 1 / Time.smoothDeltaTime,
@@ -242,12 +245,19 @@ namespace Cryville.Crtr {
UnityEngine.Profiling.Profiler.GetTotalReservedMemory() UnityEngine.Profiling.Profiler.GetTotalReservedMemory()
#endif #endif
); );
if (judge != null) sttext += "\n== Scores ==\n" + judge.GetFullFormattedScoreString(); sttext += timetext;
status.text = sttext; if (judge != null) sttext += "\n== Scores ==\n" + judge.GetFullFormattedScoreString();
} status.text = sttext;
else { }
Game.MainLogger.Enumerate((level, module, msg) => { }); void OnCameraPostRender(Camera cam) {
} if (!logEnabled) return;
if (started) timetext = string.Format(
"\nSTime: {0:R}\nATime: {1:R}\nITime: {2:R}",
cbus.Time,
Game.AudioClient.Position - atime0,
inputProxy.GetTimestampAverage()
);
else timetext = string.Empty;
} }
#endregion #endregion
@@ -298,14 +308,13 @@ namespace Cryville.Crtr {
autoRenderStep = renderStep == 0; autoRenderStep = renderStep == 0;
soundOffset = Settings.Default.SoundOffset; soundOffset = Settings.Default.SoundOffset;
startOffset = Settings.Default.StartOffset; startOffset = Settings.Default.StartOffset;
sv = Settings.Default.ScrollVelocity;
firstFrame = true; firstFrame = true;
#if !NO_THREAD
texloaddone = false; texloaddone = false;
#endif
Game.NetworkTaskWorker.SuspendBackgroundTasks(); Game.NetworkTaskWorker.SuspendBackgroundTasks();
Game.AudioSession = Game.AudioSequencer.NewSession(); Game.AudioSession = Game.AudioSequencer.NewSession();
Camera.onPostRender += OnCameraPostRender;
var hitPlane = new Plane(Vector3.forward, Vector3.zero); var hitPlane = new Plane(Vector3.forward, Vector3.zero);
var r0 = Camera.main.ViewportPointToRay(new Vector3(0, 0, 1)); var r0 = Camera.main.ViewportPointToRay(new Vector3(0, 0, 1));
float dist; float dist;
@@ -322,66 +331,74 @@ namespace Cryville.Crtr {
FileInfo chartFile = new FileInfo( FileInfo chartFile = new FileInfo(
Game.GameDataPath + "/charts/" + Settings.Default.LoadChart Game.GameDataPath + "/charts/" + Settings.Default.LoadChart
); );
FileInfo rulesetFile = new FileInfo( FileInfo rulesetFile = new FileInfo(
Game.GameDataPath + "/rulesets/" + Settings.Default.LoadRuleset Game.GameDataPath + "/rulesets/" + Settings.Default.LoadRuleset
); );
FileInfo skinFile = new FileInfo( if (!rulesetFile.Exists) throw new FileNotFoundException("Ruleset for the chart not found\nMake sure you have imported the ruleset");
Game.GameDataPath + "/skins/" + Settings.Default.LoadSkin
);
Logger.Log("main", 0, "Load/MainThread", "Loading textures..."); FileInfo rulesetConfigFile = new FileInfo(
texloadtimer = new diag::Stopwatch(); Game.GameDataPath + "/config/rulesets/" + Settings.Default.LoadRulesetConfig
texloadtimer.Start(); );
texs = new Dictionary<string, Texture2D>(); if (!rulesetConfigFile.Exists) throw new FileNotFoundException("Ruleset config not found\nPlease open the config to generate");
var flist = skinFile.Directory.GetFiles("*.png"); using (StreamReader cfgreader = new StreamReader(rulesetConfigFile.FullName, Encoding.UTF8)) {
foreach (FileInfo f in flist) { _rscfg = JsonConvert.DeserializeObject<RulesetConfig>(cfgreader.ReadToEnd(), new JsonSerializerSettings() {
#if NO_THREAD MissingMemberHandling = MissingMemberHandling.Error
using (WWW w = new WWW("file:///" + f.FullName)) { });
string name = StringUtils.TrimExt(f.Name);
while (!w.isDone);
texs.Add(name, w.texture);
}
#else
texLoadQueue.Enqueue(f.FullName);
#endif
} }
#if NO_THREAD sv = _rscfg.generic.ScrollVelocity;
texloadtimer.Stop();
Logger.LogFormat("main", 0, "Load/MainThread", "Textures loaded successfully ({0}ms)", texloadtimer.Elapsed.TotalMilliseconds); FileInfo skinFile = new FileInfo(
Load(new LoadInfo(){ string.Format("{0}/skins/{1}/{2}/.umgs", Game.GameDataPath, rulesetFile.Directory.Name, _rscfg.generic.Skin)
chartFile = chartFile, );
rulesetFile = rulesetFile, if (!skinFile.Exists) throw new FileNotFoundException("Skin not found\nPlease specify an available skin in the config");
skinFile = skinFile, using (StreamReader reader = new StreamReader(skinFile.FullName, Encoding.UTF8)) {
}); skin = JsonConvert.DeserializeObject<Skin>(reader.ReadToEnd(), new JsonSerializerSettings() {
Prehandle(); MissingMemberHandling = MissingMemberHandling.Error
#else });
if (skin.format != Skin.CURRENT_FORMAT) throw new FormatException("Invalid skin file version");
}
loadThread = new Thread(new ParameterizedThreadStart(Load)); loadThread = new Thread(new ParameterizedThreadStart(Load));
loadThread.Start(new LoadInfo() { loadThread.Start(new LoadInfo() {
chartFile = chartFile, chartFile = chartFile,
rulesetFile = rulesetFile, rulesetFile = rulesetFile,
skinFile = skinFile, skinFile = skinFile,
}); });
#endif
Logger.Log("main", 0, "Load/MainThread", "Loading textures...");
texloadtimer = new diag::Stopwatch();
texloadtimer.Start();
frames = new Dictionary<string, SpriteFrame>();
texs = new Dictionary<string, Texture2D>();
foreach (var f in skin.frames) {
texLoadQueue.Enqueue(Path.Combine(skinFile.Directory.FullName, f));
}
} }
void Prehandle() { void Prehandle() {
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", "Prehandling (iteration 3)"); Logger.Log("main", 0, "Load/Prehandle", "Initializing textures");
foreach (var i in plists) i.Init(texs);
foreach (var t in texs) { foreach (var t in texs) {
if (frames.ContainsKey(t.Key)) { if (frames.ContainsKey(t.Key)) {
Logger.Log("main", 3, "Load/Prehandle", "Duplicated texture name: {0}", t.Key); Logger.Log("main", 3, "Load/Prehandle", "Duplicated texture name: {0}", t.Key);
continue; continue;
} }
var f = new Cocos2dFrames.Frame(t.Value); var f = new SpriteFrame(t.Value);
f.Init(); f.Init();
frames.Add(t.Key, f); frames.Add(t.Key, f);
} }
Logger.Log("main", 0, "Load/Prehandle", "Initializing states"); Logger.Log("main", 0, "Load/Prehandle", "Prehandling (iteration 2)");
cbus.BroadcastInit(); cbus.BroadcastPreInit();
Game.InputManager.Activate(); Logger.Log("main", 0, "Load/Prehandle", "Prehandling (iteration 3)");
using (var pbus = cbus.Clone(17)) {
pbus.Forward();
}
Logger.Log("main", 0, "Load/Prehandle", "Prehandling (iteration 4)");
cbus.BroadcastPostInit();
inputProxy.Activate();
if (logEnabled) ToggleLogs(); if (logEnabled) ToggleLogs();
Logger.Log("main", 0, "Load/Prehandle", "Cleaning up"); Logger.Log("main", 0, "Load/Prehandle", "Cleaning up");
GC.Collect(); GC.Collect();
@@ -389,12 +406,14 @@ namespace Cryville.Crtr {
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);
Game.AudioSequencer.Playing = true; Game.AudioSequencer.Playing = true;
Thread.Sleep((int)(Game.AudioClient.BufferPosition - Game.AudioClient.Position)); atime0 = Game.AudioClient.BufferPosition;
Game.InputManager.SyncTime(cbus.Time); Thread.Sleep((int)((atime0 - Game.AudioClient.Position) * 1000));
inputProxy.SyncTime(cbus.Time);
started = true; started = true;
} }
catch (Exception ex) { catch (Exception ex) {
Game.LogException("Load/Prehandle", "An error occured while prehandling the data", ex); Game.LogException("Load/Prehandle", "An error occured while prehandling the data", ex);
Popup.CreateException(ex);
Stop(); Stop();
} }
} }
@@ -402,19 +421,18 @@ namespace Cryville.Crtr {
public void Stop() { public void Stop() {
try { try {
Logger.Log("main", 1, "Game", "Stopping"); Logger.Log("main", 1, "Game", "Stopping");
chart = null;
Game.AudioSession = Game.AudioSequencer.NewSession(); Game.AudioSession = Game.AudioSequencer.NewSession();
if (cbus != null) cbus.Dispose(); inputProxy.Deactivate();
if (bbus != null) bbus.Dispose(); if (cbus != null) { cbus.Dispose(); cbus = null; }
if (tbus != null) tbus.Dispose(); if (bbus != null) { bbus.Dispose(); bbus = null; }
if (nbus != null) nbus.Dispose(); if (tbus != null) { tbus.Dispose(); tbus = null; }
// Game.InputManager.Deactivate(); if (nbus != null) { nbus.Dispose(); nbus = null; }
foreach (var t in texs) Texture.Destroy(t.Value);
Logger.Log("main", 1, "Game", "Stopped"); Logger.Log("main", 1, "Game", "Stopped");
} }
catch (Exception ex) { catch (Exception ex) {
if (!logEnabled) ToggleLogs(); if (!logEnabled) ToggleLogs();
Game.LogException("Game", "An error occured while stopping", ex); Game.LogException("Game", "An error occured while stopping", ex);
Popup.CreateException(ex);
} }
finally { finally {
if (started) { if (started) {
@@ -442,6 +460,7 @@ namespace Cryville.Crtr {
public FileInfo skinFile; public FileInfo skinFile;
} }
Exception threadException;
#if !NO_THREAD #if !NO_THREAD
Thread loadThread = null; Thread loadThread = null;
diag::Stopwatch workerTimer; diag::Stopwatch workerTimer;
@@ -458,6 +477,7 @@ namespace Cryville.Crtr {
} }
catch (Exception ex) { catch (Exception ex) {
Game.LogException("Load/WorkerThread", "An error occured while loading the data", ex); Game.LogException("Load/WorkerThread", "An error occured while loading the data", ex);
threadException = ex;
} }
} }
@@ -484,12 +504,17 @@ namespace Cryville.Crtr {
cbus = batcher.Batch(); cbus = batcher.Batch();
Logger.Log("main", 0, "Load/WorkerThread", "Batched {0} event batches", cbus.events.Count); Logger.Log("main", 0, "Load/WorkerThread", "Batched {0} event batches", cbus.events.Count);
LoadSkin(info.skinFile);
judge = new Judge(pruleset); judge = new Judge(pruleset);
etor.ContextJudge = judge; etor.ContextJudge = judge;
LoadSkin(info.skinFile); inputProxy = new InputProxy(pruleset, judge);
inputProxy.LoadFrom(_rscfg.inputs);
if (!inputProxy.IsCompleted) {
throw new ArgumentException("Input config not completed\nPlease complete the input settings");
}
cbus.AttachSystems(pskin, judge);
Logger.Log("main", 0, "Load/WorkerThread", "Attaching handlers"); Logger.Log("main", 0, "Load/WorkerThread", "Attaching handlers");
var ch = new ChartHandler(chart, dir); var ch = new ChartHandler(chart, dir);
cbus.RootState.AttachHandler(ch); cbus.RootState.AttachHandler(ch);
@@ -499,7 +524,7 @@ namespace Cryville.Crtr {
foreach (var ts in gs.Value.Children) { foreach (var ts in gs.Value.Children) {
ContainerHandler th; ContainerHandler th;
if (ts.Key is Chart.Note) { if (ts.Key is Chart.Note) {
th = new NoteHandler(gh, (Chart.Note)ts.Key, judge); th = new NoteHandler(gh, (Chart.Note)ts.Key, pruleset, judge);
} }
else { else {
th = new TrackHandler(gh, (Chart.Track)ts.Key); th = new TrackHandler(gh, (Chart.Track)ts.Key);
@@ -507,12 +532,13 @@ namespace Cryville.Crtr {
ts.Value.AttachHandler(th); ts.Value.AttachHandler(th);
} }
} }
cbus.AttachSystems(pskin, judge);
Logger.Log("main", 0, "Load/WorkerThread", "Prehandling (iteration 1)"); Logger.Log("main", 0, "Load/WorkerThread", "Prehandling (iteration 1)");
cbus.Clone(16).Forward(); using (var pbus = cbus.Clone(16)) {
pbus.Forward();
}
Logger.Log("main", 0, "Load/WorkerThread", "Patching events"); Logger.Log("main", 0, "Load/WorkerThread", "Patching events");
cbus.DoPatch(); cbus.DoPatch();
Logger.Log("main", 0, "Load/WorkerThread", "Prehandling (iteration 2)");
cbus.Clone(17).Forward();
Logger.Log("main", 0, "Load/WorkerThread", "Cloning states (type 1)"); Logger.Log("main", 0, "Load/WorkerThread", "Cloning states (type 1)");
bbus = cbus.Clone(1, -clippingDist); bbus = cbus.Clone(1, -clippingDist);
@@ -530,7 +556,7 @@ namespace Cryville.Crtr {
ruleset = JsonConvert.DeserializeObject<Ruleset>(reader.ReadToEnd(), new JsonSerializerSettings() { ruleset = JsonConvert.DeserializeObject<Ruleset>(reader.ReadToEnd(), new JsonSerializerSettings() {
MissingMemberHandling = MissingMemberHandling.Error MissingMemberHandling = MissingMemberHandling.Error
}); });
if (ruleset.format != 1) throw new FormatException("Invalid ruleset file version"); if (ruleset.format != Ruleset.CURRENT_FORMAT) throw new FormatException("Invalid ruleset file version");
ruleset.LoadPdt(dir); ruleset.LoadPdt(dir);
pruleset = ruleset.Root; pruleset = ruleset.Root;
pruleset.Optimize(etor); pruleset.Optimize(etor);
@@ -540,23 +566,9 @@ namespace Cryville.Crtr {
void LoadSkin(FileInfo file) { void LoadSkin(FileInfo file) {
DirectoryInfo dir = file.Directory; DirectoryInfo dir = file.Directory;
Logger.Log("main", 0, "Load/WorkerThread", "Loading skin: {0}", file); Logger.Log("main", 0, "Load/WorkerThread", "Loading skin: {0}", file);
using (StreamReader reader = new StreamReader(file.FullName, Encoding.UTF8)) { skin.LoadPdt(dir);
skin = JsonConvert.DeserializeObject<Skin>(reader.ReadToEnd(), new JsonSerializerSettings() { pskin = skin.Root;
MissingMemberHandling = MissingMemberHandling.Error pskin.Optimize(etor);
});
if (skin.format != 1) throw new FormatException("Invalid skin file version");
skin.LoadPdt(dir);
pskin = skin.Root;
pskin.Optimize(etor);
}
plists = new List<Cocos2dFrames>();
frames = new Dictionary<string, Cocos2dFrames.Frame>();
foreach (FileInfo f in file.Directory.GetFiles("*.plist")) {
var pobj = PlistConvert.Deserialize<Cocos2dFrames>(f.FullName);
plists.Add(pobj);
foreach (var i in pobj.frames)
frames.Add(StringUtils.TrimExt(i.Key), i.Value);
}
} }
#endregion #endregion
} }

View File

@@ -1,176 +0,0 @@
using Cryville.Common;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Text.RegularExpressions;
using UnityEngine;
namespace Cryville.Crtr {
[BinderAttribute(typeof(Cocos2dFramesBinder))]
public class Cocos2dFrames {
public Metadata metadata;
public class Metadata {
public int format;
public Vector2 size;
public string textureFileName;
}
public Dictionary<string, Frame> frames;
public class Frame {
#pragma warning disable IDE1006
Rect _frame;
public Rect frame {
get { return _frame; }
set { _frame = value; }
}
public Rect textureRect {
get { return _frame; }
set { _frame = value; }
}
bool _rotated = false;
public bool rotated {
get { return _rotated; }
set { _rotated = value; }
}
public bool textureRotated {
get { return _rotated; }
set { _rotated = value; }
}
#pragma warning restore IDE1006
public Vector2 offset;
public Rect sourceColorRect;
public Vector2 sourceSize;
private Rect _uv;
private Vector2[] cuv;
public Rect UV {
get {
return _uv;
}
private set {
_uv = value;
float x0 = Mathf.Min(_uv.xMin, _uv.xMax);
float x1 = Mathf.Max(_uv.xMin, _uv.xMax);
float y0 = Mathf.Min(_uv.yMin, _uv.yMax);
float y1 = Mathf.Max(_uv.yMin, _uv.yMax);
if (_rotated) cuv = new Vector2[]{
new Vector2(x0, y1),
new Vector2(x1, y0),
new Vector2(x0, y0),
new Vector2(x1, y1),
};
else cuv = new Vector2[]{
new Vector2(x0, y0),
new Vector2(x1, y1),
new Vector2(x1, y0),
new Vector2(x0, y1),
};
}
}
public Vector2 GetUV(Vector2 uv) {
return GetUV(uv.x, uv.y);
}
public Vector2 GetUV(float u, float v) {
Vector2 uv00 = cuv[0], uv11 = cuv[1],
uv10 = cuv[2], uv01 = cuv[3];
return (1 - u - v) * uv00
+ u * uv10
+ v * uv01
+ u * v * (uv00 + uv11 - uv10 - uv01);
}
public Texture2D Texture {
get;
private set;
}
public Vector2 Size {
get {
return new Vector2(Texture.width, Texture.height);
}
}
public void Init() {
if (Texture == null)
throw new InvalidOperationException(); // TODO
_frame = new Rect(Vector2.zero, Size);
var w = _frame.width;
var h = _frame.height;
float x = _frame.x / w;
float y = 1 - _frame.y / h;
float tw = (_rotated ? _frame.height : _frame.width) / w;
float th = (_rotated ? _frame.width : _frame.height) / h;
if (_rotated) UV = new Rect(x, y, tw, -th);
else UV = new Rect(x, y, tw, -th);
}
public void Init(int w, int h, Texture2D _base) {
if (Texture != null)
throw new InvalidOperationException(); // TODO
Texture = _base;
float x = _frame.x / w;
float y = 1 - _frame.y / h;
float tw = (_rotated ? _frame.height : _frame.width) / w;
float th = (_rotated ? _frame.width : _frame.height) / h;
if (_rotated) UV = new Rect(x, y, tw, -th);
else UV = new Rect(x, y, tw, -th);
}
public Frame() { }
public Frame(Texture2D tex) {
Texture = tex;
}
}
Texture2D _base;
public void Init(Dictionary<string, Texture2D> texs) {
_base = texs[StringUtils.TrimExt(metadata.textureFileName)];
var w = (int)metadata.size.x;
var h = (int)metadata.size.y;
if (w == 0 || h == 0) {
w = _base.width;
h = _base.height;
}
foreach (var f in frames) {
f.Value.Init(w, h, _base);
}
}
}
public class Cocos2dFramesBinder : EmptyBinder {
public override object ChangeType(object value, Type type, CultureInfo culture) {
if (value is string) {
var str = (string)value;
if (type == typeof(Rect)) {
var m = Regex.Match(str, @"^{({.*?}),({.*?})}$");
var p = (Vector2)ChangeType(m.Groups[1].Value, typeof(Vector2), culture);
var s = (Vector2)ChangeType(m.Groups[2].Value, typeof(Vector2), culture);
return new Rect(p, s);
}
else if (type == typeof(Vector2)) {
var m = Regex.Match(str, @"^{(.*?),(.*?)}$");
var w = float.Parse(m.Groups[1].Value);
var h = float.Parse(m.Groups[2].Value);
return new Vector2(w, h);
}
}
else if (typeof(IDictionary).IsAssignableFrom(value.GetType())) {
var dict = (IDictionary)value;
if (type == typeof(Rect)) {
var x = float.Parse((string)dict["x"]);
var y = float.Parse((string)dict["y"]);
var w = float.Parse((string)dict["w"]);
var h = float.Parse((string)dict["h"]);
return new Rect(x, y, w, h);
}
else if (type == typeof(Vector2)) {
var w = float.Parse((string)dict["w"]);
var h = float.Parse((string)dict["h"]);
return new Vector2(w, h);
}
}
return base.ChangeType(value, type, culture);
}
}
}

View File

@@ -0,0 +1,28 @@
using System;
namespace Cryville.Crtr.Components {
public abstract class MeshBase : SkinComponent {
public MeshBase() {
SubmitProperty("zindex", new PropOp.Integer(v => ZIndex = (short)v));
}
protected MeshWrapper mesh = new MeshWrapper();
short _zindex;
public short ZIndex {
get {
return _zindex;
}
set {
if (value < 0 || value > 5000)
throw new ArgumentOutOfRangeException("value", "Z-index must be in [0..5000]");
_zindex = value;
UpdateZIndex();
}
}
protected void UpdateZIndex() {
if (!mesh.Initialized) return;
mesh.Renderer.material.renderQueue = _zindex;
}
}
}

View File

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

View File

@@ -5,11 +5,10 @@ using System.Collections.Generic;
using UnityEngine; using UnityEngine;
namespace Cryville.Crtr.Components { namespace Cryville.Crtr.Components {
public abstract class SectionalGameObject : SkinComponent { public abstract class SectionalGameObject : MeshBase {
protected Vector3? prevpt; protected Vector3? prevpt;
protected Quaternion? prevrot; protected Quaternion? prevrot;
protected int vertCount = 0; protected int vertCount = 0;
protected MeshWrapper mesh = new MeshWrapper();
protected override void OnDestroy() { protected override void OnDestroy() {
mesh.Destroy(); mesh.Destroy();
@@ -56,8 +55,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("transparent", new PropOp.Boolean(v => transparent = v)); SubmitProperty("shape", new op_set_shape(this), 2);
SubmitProperty("shape", new op_set_shape(this));
} }
#pragma warning disable IDE1006 #pragma warning disable IDE1006
@@ -94,7 +92,6 @@ namespace Cryville.Crtr.Components {
public SpriteInfo body = new SpriteInfo(); public SpriteInfo body = new SpriteInfo();
public SpriteInfo tail = new SpriteInfo(); public SpriteInfo tail = new SpriteInfo();
public bool transparent;
List<Vector3> vertices; List<Vector3> vertices;
List<float> lengths; List<float> lengths;
float sumLength = 0; float sumLength = 0;
@@ -106,7 +103,7 @@ namespace Cryville.Crtr.Components {
body.Load(); body.Load();
tail.Load(); tail.Load();
mesh.Init(transform, transparent); mesh.Init(transform);
List<Material> materials = new List<Material>(); List<Material> materials = new List<Material>();
if (head.FrameName != null) AddMat(materials, head.FrameName); if (head.FrameName != null) AddMat(materials, head.FrameName);
@@ -132,7 +129,6 @@ namespace Cryville.Crtr.Components {
} }
} }
// Vector3 prevp = Vector3.zero;
protected override void AppendPointInternal(Vector3 p, Quaternion r) { protected override void AppendPointInternal(Vector3 p, Quaternion r) {
if (vertices == null) { if (vertices == null) {
vertices = _ptPool.Rent(); vertices = _ptPool.Rent();

View File

@@ -7,25 +7,32 @@ namespace Cryville.Crtr.Components {
/// <summary> /// <summary>
/// The property operators of the component. /// The property operators of the component.
/// </summary> /// </summary>
public Dictionary<string, PdtOperator> PropOps { get; private set; } public Dictionary<string, SkinProperty> Properties { get; private set; }
/// <summary> /// <summary>
/// Submits a property. /// Submits a property.
/// </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 operator.</param> /// <param name="property">The property.</param>
protected void SubmitProperty(string name, PdtOperator property) { protected void SubmitProperty(string name, PdtOperator property, int uct = 1) {
PropOps.Add(name, property); Properties.Add(name, new SkinProperty(property, uct));
} }
/// <summary> /// <summary>
/// Create a skin component /// Creates a skin component.
/// </summary> /// </summary>
protected SkinComponent() { protected SkinComponent() {
// Properties = new Dictionary<string, Property>(); Properties = new Dictionary<string, SkinProperty>();
PropOps = new Dictionary<string, PdtOperator>();
} }
public virtual void Init() { } public virtual void Init() { }
protected abstract void OnDestroy(); protected abstract void OnDestroy();
} }
public struct SkinProperty {
public PdtOperator Operator { get; set; }
public int UpdateCloneType { get; set; }
public SkinProperty(PdtOperator op, int uct = 1) {
Operator = op;
UpdateCloneType = uct;
}
}
} }

View File

@@ -2,14 +2,12 @@
using UnityEngine; using UnityEngine;
namespace Cryville.Crtr.Components { namespace Cryville.Crtr.Components {
public abstract class SpriteBase : SkinComponent { public abstract class SpriteBase : MeshBase {
public SpriteBase() { public SpriteBase() {
SubmitProperty("bound", new op_set_bound(this)); SubmitProperty("bound", new op_set_bound(this));
SubmitProperty("transparent", new PropOp.Boolean(v => transparent = v));
SubmitProperty("pivot", new PropOp.Vector2(v => Pivot = v)); SubmitProperty("pivot", new PropOp.Vector2(v => Pivot = v));
SubmitProperty("scale", new PropOp.Vector2(v => Scale = v)); SubmitProperty("scale", new PropOp.Vector2(v => Scale = v));
SubmitProperty("ui", new PropOp.Boolean(v => UI = v)); SubmitProperty("ui", new PropOp.Boolean(v => UI = v));
SubmitProperty("zindex", new PropOp.Integer(v => ZIndex = (short)v));
} }
#pragma warning disable IDE1006 #pragma warning disable IDE1006
@@ -27,8 +25,6 @@ namespace Cryville.Crtr.Components {
} }
#pragma warning restore IDE1006 #pragma warning restore IDE1006
protected MeshWrapper mesh = new MeshWrapper();
protected override void OnDestroy() { protected override void OnDestroy() {
mesh.Destroy(); mesh.Destroy();
} }
@@ -83,21 +79,6 @@ namespace Cryville.Crtr.Components {
if (da.y != 0) _scale.y = dp.z / da.y; if (da.y != 0) _scale.y = dp.z / da.y;
} }
short _zindex;
public short ZIndex {
get {
return _zindex;
}
set {
_zindex = value;
UpdateZIndex();
}
}
protected void UpdateZIndex() {
if (!mesh.Initialized) return;
mesh.Renderer.sortingOrder = _zindex;
}
static readonly Quaternion uirot static readonly Quaternion uirot
= Quaternion.Euler(new Vector3(-90, 0, 0)); = Quaternion.Euler(new Vector3(-90, 0, 0));
bool _ui; bool _ui;
@@ -109,10 +90,8 @@ namespace Cryville.Crtr.Components {
} }
} }
public bool transparent = false;
protected void InternalInit(string meshName = "quad") { protected void InternalInit(string meshName = "quad") {
mesh.Init(transform, transparent); mesh.Init(transform);
mesh.Mesh = GenericResources.Meshes[meshName]; mesh.Mesh = GenericResources.Meshes[meshName];
UpdateScale(); UpdateScale();
UpdateZIndex(); UpdateZIndex();

View File

@@ -5,7 +5,7 @@ using Logger = Cryville.Common.Logger;
namespace Cryville.Crtr.Components { namespace Cryville.Crtr.Components {
public class SpriteInfo { public class SpriteInfo {
public string FrameName; public string FrameName;
public Cocos2dFrames.Frame Frame { public SpriteFrame Frame {
get; get;
private set; private set;
} }

View File

@@ -4,8 +4,6 @@ namespace Cryville.Crtr.Components {
public class SpriteRect : SpriteBase { public class SpriteRect : SpriteBase {
public SpriteRect() { public SpriteRect() {
SubmitProperty("color", new PropOp.Color(v => Color = v)); SubmitProperty("color", new PropOp.Color(v => Color = v));
transparent = true;
} }
Color _color; Color _color;

View File

@@ -1,4 +1,5 @@
using Cryville.Common.Pdt; using Cryville.Common.Buffers;
using Cryville.Common.Pdt;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
@@ -7,7 +8,7 @@ namespace Cryville.Crtr.Components {
public class SpriteText : SpriteBase { public class SpriteText : SpriteBase {
public SpriteText() { public SpriteText() {
SubmitProperty("frames", new op_set_frames(this)); SubmitProperty("frames", new op_set_frames(this));
SubmitProperty("value", new PropOp.String(v => Value = v)); 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)); SubmitProperty("opacity", new PropOp.Float(v => Opacity = v));
@@ -41,21 +42,14 @@ namespace Cryville.Crtr.Components {
foreach (var m in meshes) m.Value.Destroy(); foreach (var m in meshes) m.Value.Destroy();
} }
readonly Dictionary<Texture2D, MeshWrapper> meshes = new Dictionary<Texture2D, MeshWrapper>();
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(); UpdateScale(); }
} }
public string m_value; readonly TargetString m_value = new TargetString();
public string Value { public TargetString Value { get { return m_value; } }
get { return m_value; }
set {
if (m_value == value) return;
m_value = value; UpdateScale();
}
}
public float m_size; public float m_size;
public float Size { public float Size {
@@ -80,30 +74,38 @@ namespace Cryville.Crtr.Components {
float frameHeight = 0; float frameHeight = 0;
foreach (var m in meshes) m.Value.Destroy(); foreach (var m in meshes) m.Value.Destroy();
meshes.Clear(); meshes.Clear();
verts.Clear();
uvs.Clear();
foreach (var f in m_frames) { foreach (var f in m_frames) {
f.Value.Load(); f.Value.Load();
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"); else if (frameHeight != f.Value.Rect.height) throw new Exception("Inconsistent frame height");
if (!meshes.ContainsKey(f.Value.Frame.Texture)) { var tex = f.Value.Frame.Texture;
if (!meshes.ContainsKey(tex)) {
var m = new MeshWrapper(); var m = new MeshWrapper();
m.Init(mesh.MeshTransform, transparent); m.Init(mesh.MeshTransform);
m.Mesh = new Mesh(); m.Mesh = new Mesh();
m.Renderer.material.mainTexture = f.Value.Frame.Texture; m.Renderer.material.mainTexture = tex;
meshes.Add(f.Value.Frame.Texture, m); meshes.Add(tex, m);
verts.Add(tex, new List<Vector3>());
uvs.Add(tex, new List<Vector2>());
tris.Add(tex, new List<int>());
} }
} }
} }
float sum_x; float sum_x;
readonly Dictionary<Texture2D, MeshWrapper> meshes = new Dictionary<Texture2D, MeshWrapper>();
readonly Dictionary<Texture2D, List<Vector3>> verts = new Dictionary<Texture2D, List<Vector3>>();
readonly Dictionary<Texture2D, List<Vector2>> uvs = new Dictionary<Texture2D, List<Vector2>>();
readonly Dictionary<Texture2D, List<int>> tris = new Dictionary<Texture2D, List<int>>();
void UpdateMeshes() { void UpdateMeshes() {
if (meshes.Count == 0) return; if (meshes.Count == 0) return;
sum_x = 0; sum_x = 0;
int vc = m_value.Length * 4;
Dictionary<Texture2D, List<Vector3>> verts = new Dictionary<Texture2D, List<Vector3>>();
Dictionary<Texture2D, List<Vector2>> uvs = new Dictionary<Texture2D, List<Vector2>>();
foreach (var t in meshes.Keys) { foreach (var t in meshes.Keys) {
verts.Add(t, new List<Vector3>(vc)); verts[t].Clear();
uvs.Add(t, new List<Vector2>(vc)); uvs[t].Clear();
tris[t].Clear();
} }
foreach (var c in m_value) { foreach (var c in m_value) {
var f = m_frames[c]; var f = m_frames[c];
@@ -123,18 +125,18 @@ namespace Cryville.Crtr.Components {
var m = meshes[t].Mesh; var m = meshes[t].Mesh;
m.Clear(); m.Clear();
int cc = verts[t].Count / 4; int cc = verts[t].Count / 4;
int[] tris = new int[cc * 6]; var _tris = tris[t];
for (int i = 0; i < cc; i++) { for (int i = 0; i < cc; i++) {
tris[i * 6 ] = i * 4 ; _tris.Add(i * 4);
tris[i * 6 + 1] = i * 4 + 3; _tris.Add(i * 4 + 3);
tris[i * 6 + 2] = i * 4 + 1; _tris.Add(i * 4 + 1);
tris[i * 6 + 3] = i * 4 + 1; _tris.Add(i * 4 + 1);
tris[i * 6 + 4] = i * 4 + 3; _tris.Add(i * 4 + 3);
tris[i * 6 + 5] = i * 4 + 2; _tris.Add(i * 4 + 2);
} }
m.vertices = verts[t].ToArray(); m.SetVertices(verts[t]);
m.uv = uvs[t].ToArray(); m.SetUVs(0, uvs[t]);
m.triangles = tris; m.SetTriangles(tris[t], 0);
m.RecalculateNormals(); m.RecalculateNormals();
} }
sum_x -= m_spacing; sum_x -= m_spacing;
@@ -174,6 +176,7 @@ namespace Cryville.Crtr.Components {
UpdateFrames(); UpdateFrames();
mesh.Mesh.Clear(); mesh.Mesh.Clear();
UpdateScale(); UpdateScale();
Value.OnUpdate += UpdateScale;
} }
} }
} }

View File

@@ -1,8 +1,84 @@
using UnityEngine; using Newtonsoft.Json;
using System;
using System.IO;
using System.Text;
using UnityEngine;
using UnityEngine.SceneManagement; using UnityEngine.SceneManagement;
namespace Cryville.Crtr.Config { namespace Cryville.Crtr.Config {
public class ConfigScene : MonoBehaviour { public class ConfigScene : MonoBehaviour {
[SerializeField]
Transform m_content;
[SerializeField]
SettingsPanel m_genericConfigPanel;
[SerializeField]
InputConfigPanel m_inputConfigPanel;
public Ruleset ruleset;
RulesetConfig _rscfg;
void Awake() {
ChartPlayer.etor = new PdtEvaluator();
FileInfo file = new FileInfo(
Game.GameDataPath + "/rulesets/" + Settings.Default.LoadRuleset
);
if (!file.Exists) {
Popup.Create("Ruleset for the chart not found\nMake sure you have imported the ruleset");
ReturnToMenu();
return;
}
DirectoryInfo dir = file.Directory;
using (StreamReader reader = new StreamReader(file.FullName, Encoding.UTF8)) {
ruleset = JsonConvert.DeserializeObject<Ruleset>(reader.ReadToEnd(), new JsonSerializerSettings() {
MissingMemberHandling = MissingMemberHandling.Error
});
if (ruleset.format != Ruleset.CURRENT_FORMAT) throw new FormatException("Invalid ruleset file version");
ruleset.LoadPdt(dir);
}
FileInfo cfgfile = new FileInfo(
Game.GameDataPath + "/config/rulesets/" + Settings.Default.LoadRulesetConfig
);
if (!cfgfile.Exists) {
if (!cfgfile.Directory.Exists) cfgfile.Directory.Create();
_rscfg = new RulesetConfig();
}
else {
using (StreamReader cfgreader = new StreamReader(cfgfile.FullName, Encoding.UTF8)) {
_rscfg = JsonConvert.DeserializeObject<RulesetConfig>(cfgreader.ReadToEnd(), new JsonSerializerSettings() {
MissingMemberHandling = MissingMemberHandling.Error
});
}
}
m_genericConfigPanel.Target = _rscfg.generic;
var proxy = new InputProxy(ruleset.Root, null);
proxy.LoadFrom(_rscfg.inputs);
m_inputConfigPanel.proxy = proxy;
Game.InputManager.Activate();
}
public void SwitchCategory(GameObject cat) {
foreach (Transform c in m_content) {
c.gameObject.SetActive(false);
}
cat.SetActive(true);
}
public void SaveAndReturnToMenu() {
Game.InputManager.Deactivate();
m_inputConfigPanel.proxy.SaveTo(_rscfg.inputs);
m_inputConfigPanel.proxy.Dispose();
FileInfo cfgfile = new FileInfo(
Game.GameDataPath + "/config/rulesets/" + Settings.Default.LoadRulesetConfig
);
using (StreamWriter cfgwriter = new StreamWriter(cfgfile.FullName, false, Encoding.UTF8)) {
cfgwriter.Write(JsonConvert.SerializeObject(_rscfg, Game.GlobalJsonSerializerSettings));
}
ReturnToMenu();
}
public void ReturnToMenu() { public void ReturnToMenu() {
GameObject.Find("Master").GetComponent<Master>().ShowMenu(); GameObject.Find("Master").GetComponent<Master>().ShowMenu();
#if UNITY_5_5_OR_NEWER #if UNITY_5_5_OR_NEWER

View File

@@ -1,15 +1,14 @@
using Cryville.Common.Unity; using Cryville.Common.Unity;
using Cryville.Common.Unity.Input; using Cryville.Common.Unity.Input;
using Newtonsoft.Json;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Text;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
namespace Cryville.Crtr.Config { namespace Cryville.Crtr.Config {
public class InputConfig : MonoBehaviour { public class InputConfigPanel : MonoBehaviour {
[SerializeField]
ConfigScene m_configScene;
[SerializeField] [SerializeField]
GameObject m_inputDialog; GameObject m_inputDialog;
@@ -25,14 +24,13 @@ namespace Cryville.Crtr.Config {
[SerializeField] [SerializeField]
GameObject m_prefabInputConfigEntry; GameObject m_prefabInputConfigEntry;
InputProxy _proxy; public InputProxy proxy;
Dictionary<string, InputConfigEntry> _entries = new Dictionary<string, InputConfigEntry>(); Dictionary<string, InputConfigPanelEntry> _entries = new Dictionary<string, InputConfigPanelEntry>();
string _sel; string _sel;
public void OpenDialog(string entry) { public void OpenDialog(string entry) {
_sel = entry; _sel = entry;
m_inputDialog.SetActive(true); m_inputDialog.SetActive(true);
Game.InputManager.Activate();
CallHelper.Purge(m_deviceList); CallHelper.Purge(m_deviceList);
_recvsrcs.Clear(); _recvsrcs.Clear();
AddSourceItem(null); AddSourceItem(null);
@@ -40,39 +38,24 @@ namespace Cryville.Crtr.Config {
public void CloseDialog() { public void CloseDialog() {
m_inputDialog.SetActive(false); m_inputDialog.SetActive(false);
Game.InputManager.Deactivate();
} }
public void CloseDialog(InputSource? src) { public void CloseDialog(InputSource? src) {
_proxy.Set(new InputProxyEntry { proxy.Set(new InputProxyEntry {
Target = _sel, Target = _sel,
Source = src, Source = src,
}); });
m_inputDialog.SetActive(false); m_inputDialog.SetActive(false);
Game.InputManager.Deactivate();
} }
void Start() { void Start() {
ChartPlayer.etor = new PdtEvaluator(); foreach (var i in m_configScene.ruleset.Root.inputs) {
FileInfo file = new FileInfo( var e = GameObject.Instantiate(m_prefabInputConfigEntry, m_entryList.transform).GetComponent<InputConfigPanelEntry>();
Game.GameDataPath + "/rulesets/" + Settings.Default.LoadRuleset _entries.Add(i.Key, e);
); e.SetKey(this, i.Key);
DirectoryInfo dir = file.Directory; OnProxyChanged(this, proxy[i.Key]);
using (StreamReader reader = new StreamReader(file.FullName, Encoding.UTF8)) {
var ruleset = JsonConvert.DeserializeObject<Ruleset>(reader.ReadToEnd(), new JsonSerializerSettings() {
MissingMemberHandling = MissingMemberHandling.Error
});
if (ruleset.format != 1) throw new FormatException("Invalid ruleset file version");
ruleset.LoadPdt(dir);
_proxy = new InputProxy(ruleset.Root);
foreach (var i in ruleset.Root.inputs) {
var e = GameObject.Instantiate(m_prefabInputConfigEntry).GetComponent<InputConfigEntry>();
e.transform.SetParent(m_entryList.transform);
_entries.Add(i.Key, e);
e.SetKey(this, i.Key);
}
_proxy.ProxyChanged += OnProxyChanged;
} }
proxy.ProxyChanged += OnProxyChanged;
} }
void OnProxyChanged(object sender, ProxyChangedEventArgs e) { void OnProxyChanged(object sender, ProxyChangedEventArgs e) {
@@ -92,11 +75,10 @@ namespace Cryville.Crtr.Config {
void AddSourceItem(InputSource? src) { void AddSourceItem(InputSource? src) {
if (_recvsrcs.Contains(src)) return; if (_recvsrcs.Contains(src)) return;
_recvsrcs.Add(src); _recvsrcs.Add(src);
var obj = Instantiate(m_prefabListItem); var obj = Instantiate(m_prefabListItem, m_deviceList);
obj.transform.SetParent(m_deviceList);
obj.transform.Find("Text").GetComponent<Text>().text = src == null ? "None" : src.Value.Handler.GetTypeName(src.Value.Type); obj.transform.Find("Text").GetComponent<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) btn.interactable = !proxy.IsUsed(src.Value);
btn.onClick.AddListener(() => { btn.onClick.AddListener(() => {
CloseDialog(src); CloseDialog(src);
}); });

View File

@@ -2,7 +2,7 @@
using UnityEngine.UI; using UnityEngine.UI;
namespace Cryville.Crtr.Config { namespace Cryville.Crtr.Config {
public class InputConfigEntry : MonoBehaviour { public class InputConfigPanelEntry : MonoBehaviour {
[SerializeField] [SerializeField]
Text m_key; Text m_key;
@@ -12,7 +12,7 @@ namespace Cryville.Crtr.Config {
[SerializeField] [SerializeField]
Button m_button; Button m_button;
public void SetKey(InputConfig master, string name) { public void SetKey(InputConfigPanel master, string name) {
m_key.text = name; m_key.text = name;
m_value.text = "None"; m_value.text = "None";
m_button.onClick.AddListener(() => { m_button.onClick.AddListener(() => {

View File

@@ -0,0 +1,32 @@
using Cryville.Common.ComponentModel;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
namespace Cryville.Crtr.Config {
public class RulesetConfig {
public Generic generic = new Generic();
public class Generic {
[Category("basic")]
[JsonProperty("skin")]
public string Skin { get; set; }
[Category("deprecated")][Obsolete]
[JsonProperty("scroll_velocity")][DefaultValue(1)]
[LogarithmicScale][Step(0.5f)][Precision(1e-1)]
public float ScrollVelocity { get; set; }
public Generic() {
Skin = "";
ScrollVelocity = 1;
}
}
public Dictionary<string, InputEntry> inputs
= new Dictionary<string, InputEntry>();
public class InputEntry {
public string handler;
public int type;
}
}
}

View File

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

View File

@@ -63,6 +63,13 @@ namespace Cryville.Crtr.Event {
get { return cs.Container; } get { return cs.Container; }
} }
public SkinContainer skinContainer;
public Judge judge;
public void AttachSystems(PdtSkin skin, Judge judge) {
skinContainer = new SkinContainer(skin);
this.judge = judge;
}
public ContainerHandler() { } public ContainerHandler() { }
public abstract string TypeName { public abstract string TypeName {
get; get;
@@ -79,10 +86,10 @@ namespace Cryville.Crtr.Event {
Anchors.Add("tail", new Anchor() { Transform = a_tail }); Anchors.Add("tail", new Anchor() { Transform = a_tail });
} }
/// <summary> /// <summary>
/// Called upon initialization of <see cref="cs" />. /// Called upon StartUpdate of ps 17.
/// </summary> /// </summary>
public virtual void Init() { public virtual void Init() {
cs.skinContainer.MatchStatic(cs); skinContainer.MatchStatic(ps);
foreach (var i in gogroup.GetComponentsInChildren<SkinComponent>()) foreach (var i in gogroup.GetComponentsInChildren<SkinComponent>())
i.Init(); i.Init();
} }
@@ -111,11 +118,14 @@ namespace Cryville.Crtr.Event {
PreAwake(s); PreAwake(s);
Awake(s); Awake(s);
} }
else if (s.CloneType == 17) {
Init();
}
} }
public virtual void Update(ContainerState s, StampedEvent ev) { public virtual void Update(ContainerState s, StampedEvent ev) {
bool flag = !Awoken && s.CloneType >= 2 && s.CloneType < 16; bool flag = !Awoken && s.CloneType >= 2 && s.CloneType < 16;
if (flag) PreAwake(s); if (flag) PreAwake(s);
if (Awoken && s.CloneType <= 2) if (gogroup) cs.skinContainer.MatchDynamic(s); if (s.CloneType <= 2) if (gogroup) skinContainer.MatchDynamic(s);
if (flag) Awake(s); if (flag) Awake(s);
} }
public virtual void ExUpdate(ContainerState s, StampedEvent ev) { } public virtual void ExUpdate(ContainerState s, StampedEvent ev) { }
@@ -123,7 +133,7 @@ namespace Cryville.Crtr.Event {
public virtual void EndUpdate(ContainerState s) { public virtual void EndUpdate(ContainerState s) {
if (s.CloneType < 16) { if (s.CloneType < 16) {
Awoken = false; Awoken = false;
if (gogroup && s.CloneType <= 2) cs.skinContainer.MatchDynamic(s); if (gogroup && s.CloneType <= 2) skinContainer.MatchDynamic(s);
} }
} }
public virtual void Anchor() { } public virtual void Anchor() { }

View File

@@ -50,8 +50,6 @@ namespace Cryville.Crtr.Event {
public byte CloneType; public byte CloneType;
private ContainerState rootPrototype = null; private ContainerState rootPrototype = null;
private ContainerState prototype = null; private ContainerState prototype = null;
public SkinContainer skinContainer;
public Judge judge;
public ContainerHandler Handler { public ContainerHandler Handler {
get; get;
@@ -66,9 +64,15 @@ namespace Cryville.Crtr.Event {
readonly RMVPool RMVPool = new RMVPool(); readonly RMVPool RMVPool = new RMVPool();
protected Dictionary<StampedEvent, RealtimeMotionValue> PlayingMotions = new Dictionary<StampedEvent, RealtimeMotionValue>(); protected Dictionary<StampedEvent, RealtimeMotionValue> PlayingMotions = new Dictionary<StampedEvent, RealtimeMotionValue>();
protected Dictionary<MotionName, RealtimeMotionValue> Values = new Dictionary<MotionName, RealtimeMotionValue>(); protected Dictionary<Identifier, RealtimeMotionValue> Values;
protected Dictionary<MotionName, Vector> CachedValues = new Dictionary<MotionName, Vector>(); protected Dictionary<Identifier, CacheEntry> CachedValues;
protected Dictionary<MotionName, bool> CachedValueStates = new Dictionary<MotionName, bool>(); protected class CacheEntry {
public bool Valid { get; set; }
public Vector Value { get; set; }
public CacheEntry Clone() {
return new CacheEntry { Valid = Valid, Value = Value == null ? null : Value.Clone() };
}
}
/// <summary> /// <summary>
/// Gets a motion value. /// Gets a motion value.
@@ -76,12 +80,12 @@ namespace Cryville.Crtr.Event {
/// <param name="name">The motion name.</param> /// <param name="name">The motion name.</param>
/// <param name="clone">Returns a cloned motion value instead.</param> /// <param name="clone">Returns a cloned motion value instead.</param>
/// <returns>A motion value.</returns> /// <returns>A motion value.</returns>
RealtimeMotionValue GetMotionValue(MotionName name, bool clone = false) { RealtimeMotionValue GetMotionValue(Identifier name, bool clone = false) {
RealtimeMotionValue value; RealtimeMotionValue value;
if (!Values.TryGetValue(name, out value)) { if (!Values.TryGetValue(name, out value)) {
value = new RealtimeMotionValue().Init(Parent == null value = new RealtimeMotionValue().Init(Parent == null
? ChartPlayer.motionRegistry[name.MainName].GlobalInitValue ? ChartPlayer.motionRegistry[name].GlobalInitValue
: ChartPlayer.motionRegistry[name.MainName].InitValue : ChartPlayer.motionRegistry[name].InitValue
); );
Values.Add(name, value); Values.Add(name, value);
} }
@@ -89,8 +93,11 @@ namespace Cryville.Crtr.Event {
return value; return value;
} }
void InvalidateMotion(MotionName name) { void InvalidateMotion(Identifier name) {
CachedValueStates[name] = false; CacheEntry cache;
if (!CachedValues.TryGetValue(name, out cache))
CachedValues.Add(name, cache = new CacheEntry());
cache.Valid = false;
foreach (var c in Children) foreach (var c in Children)
c.Value.InvalidateMotion(name); c.Value.InvalidateMotion(name);
} }
@@ -103,8 +110,10 @@ namespace Cryville.Crtr.Event {
Parent = parent; Parent = parent;
} }
Values = new Dictionary<Identifier, RealtimeMotionValue>(ChartPlayer.motionRegistry.Count);
CachedValues = new Dictionary<Identifier, CacheEntry>(ChartPlayer.motionRegistry.Count);
foreach (var m in ChartPlayer.motionRegistry) foreach (var m in ChartPlayer.motionRegistry)
Values.Add(new MotionName(m.Key), new RealtimeMotionValue().Init(Parent == null ? m.Value.GlobalInitValue : m.Value.InitValue)); Values.Add(m.Key, new RealtimeMotionValue().Init(Parent == null ? m.Value.GlobalInitValue : m.Value.InitValue));
} }
static void AddChild(EventContainer c, ContainerState s, ContainerState target) { static void AddChild(EventContainer c, ContainerState s, ContainerState target) {
@@ -117,24 +126,18 @@ namespace Cryville.Crtr.Event {
public ContainerState Clone(byte ct) { public ContainerState Clone(byte ct) {
var r = (ContainerState)MemberwiseClone(); var r = (ContainerState)MemberwiseClone();
var mvs = new Dictionary<MotionName, RealtimeMotionValue>(Values.Count); var mvs = new Dictionary<Identifier, RealtimeMotionValue>(ChartPlayer.motionRegistry.Count);
foreach (var mv in Values) { foreach (var mv in Values) {
mvs.Add(mv.Key, mv.Value.Clone()); mvs.Add(mv.Key, mv.Value.Clone());
} }
r.Values = mvs; r.Values = mvs;
var cvs = new Dictionary<MotionName, Vector>(CachedValues.Count); var cvs = new Dictionary<Identifier, CacheEntry>(ChartPlayer.motionRegistry.Count);
foreach (var cv in CachedValues) { foreach (var cv in CachedValues) {
cvs.Add(cv.Key, cv.Value.Clone()); cvs.Add(cv.Key, cv.Value.Clone());
} }
r.CachedValues = cvs; r.CachedValues = cvs;
var cvss = new Dictionary<MotionName, bool>(CachedValueStates.Count);
foreach (var cv in CachedValueStates) {
cvss.Add(cv.Key, cv.Value);
}
r.CachedValueStates = cvss;
r.Children = new Dictionary<EventContainer, ContainerState>(); r.Children = new Dictionary<EventContainer, ContainerState>();
foreach (var child in Children) { foreach (var child in Children) {
var cc = child.Value.Clone(ct); var cc = child.Value.Clone(ct);
@@ -169,11 +172,13 @@ namespace Cryville.Crtr.Event {
} }
foreach (var cv in CachedValues) { foreach (var cv in CachedValues) {
Vector dv; CacheEntry dv;
if(dest.CachedValues.TryGetValue(cv.Key, out dv)) cv.Value.CopyTo(dv); if (dest.CachedValues.TryGetValue(cv.Key, out dv)) {
dv.Valid = cv.Value.Valid;
if (cv.Value.Value != null) cv.Value.Value.CopyTo(dv.Value);
}
else dest.CachedValues.Add(cv.Key, cv.Value.Clone()); else dest.CachedValues.Add(cv.Key, cv.Value.Clone());
} }
foreach (var cvs in CachedValueStates) dest.CachedValueStates[cvs.Key] = cvs.Value;
if (ct != 1) foreach (var cev in WorkingChildren) if (ct != 1) foreach (var cev in WorkingChildren)
Children[cev].CopyTo(ct, dest.Children[cev]); Children[cev].CopyTo(ct, dest.Children[cev]);
@@ -193,7 +198,7 @@ namespace Cryville.Crtr.Event {
public void Dispose() { public void Dispose() {
if (Disposed) return; if (Disposed) return;
Disposed = true; Disposed = true;
if (Handler != null) Handler.Dispose(); if (CloneType < 16 && Handler != null) Handler.Dispose();
foreach (var s in Children) foreach (var s in Children)
s.Value.Dispose(); s.Value.Dispose();
RMVPool.ReturnAll(); RMVPool.ReturnAll();
@@ -207,32 +212,42 @@ namespace Cryville.Crtr.Event {
} }
public void AttachSystems(PdtSkin skin, Judge judge) { public void AttachSystems(PdtSkin skin, Judge judge) {
skinContainer = new SkinContainer(skin); Handler.AttachSystems(skin, judge);
this.judge = judge;
} }
public T GetRawValue<T>(MotionName key) where T : Vector { public Vector GetRawValue(Identifier key) {
Vector tr; CacheEntry tr;
if (!CachedValues.TryGetValue(key, out tr)) { if (!CachedValues.TryGetValue(key, out tr))
tr = (Vector)ReflectionHelper.InvokeEmptyConstructor(typeof(T)); CachedValues.Add(key, tr = new CacheEntry { Valid = false });
CachedValues.Add(key, tr); if (tr.Value == null)
CachedValueStates[key] = false; tr.Value = (Vector)ReflectionHelper.InvokeEmptyConstructor(ChartPlayer.motionRegistry[key].Type);
} Vector r = tr.Value;
T r = (T)tr;
#if !DISABLE_CACHE #if !DISABLE_CACHE
if (CachedValueStates[key]) return r; if (tr.Valid) return r;
#endif #endif
float reltime = 0; float reltime = 0;
if (rootPrototype != null) reltime = Time - rootPrototype.Time; if (rootPrototype != null) reltime = Time - rootPrototype.Time;
GetMotionValue(key).GetValue(reltime, ref r); GetMotionValue(key).GetValue(reltime, ref r);
if (Parent != null) r.ApplyFrom(Parent.GetRawValue<T>(key)); if (Parent != null) r.ApplyFrom(Parent.GetRawValue(key));
#if !DISABLE_CACHE #if !DISABLE_CACHE
CachedValueStates[key] = true; tr.Valid = true;
#endif #endif
return r; return r;
} }
static readonly MotionName n_dir = new MotionName("dir"); public T GetRawValue<T>(Identifier key) where T : Vector {
return (T)GetRawValue(key);
}
static readonly Identifier n_pt = new Identifier("pt");
public Vector2 ScreenPoint {
get {
var mv = GetRawValue<VecPt>(n_pt);
return mv.ToVector2(ChartPlayer.hitRect);
}
}
static readonly Identifier n_dir = new Identifier("dir");
public Vector3 Direction { public Vector3 Direction {
get { get {
Vec3 r = GetRawValue<Vec3>(n_dir); Vec3 r = GetRawValue<Vec3>(n_dir);
@@ -240,7 +255,7 @@ namespace Cryville.Crtr.Event {
} }
} }
static readonly MotionName n_normal = new MotionName("normal"); static readonly Identifier n_normal = new Identifier("normal");
public Vector3 Normal { public Vector3 Normal {
get { get {
Vec3 r = GetRawValue<Vec3>(n_normal); Vec3 r = GetRawValue<Vec3>(n_normal);
@@ -254,16 +269,8 @@ namespace Cryville.Crtr.Event {
} }
} }
static readonly MotionName n_pt = new MotionName("pt"); static readonly Identifier n_sv = new Identifier("sv");
public Vector2 ScreenPoint { static readonly Identifier n_svm = new Identifier("svm");
get {
var mv = GetRawValue<VecPt>(n_pt);
return mv.ToVector2(ChartPlayer.hitRect);
}
}
static readonly MotionName n_sv = new MotionName("sv");
static readonly MotionName n_svm = new MotionName("svm");
public float ScrollVelocity { public float ScrollVelocity {
get { get {
return GetRawValue<VecPtComp>(n_sv).ToFloat(ChartPlayer.hitRect) return GetRawValue<VecPtComp>(n_sv).ToFloat(ChartPlayer.hitRect)
@@ -271,7 +278,7 @@ namespace Cryville.Crtr.Event {
} }
} }
static readonly MotionName n_dist = new MotionName("dist"); static readonly Identifier n_dist = new Identifier("dist");
public float Distance { public float Distance {
get { get {
var mv = GetRawValue<VecPtComp>(n_dist); var mv = GetRawValue<VecPtComp>(n_dist);
@@ -279,15 +286,15 @@ namespace Cryville.Crtr.Event {
} }
} }
static readonly MotionName n_corner = new MotionName("corner"); static readonly Identifier n_corner = new Identifier("corner");
public bool Corner { public bool Corner {
get { get {
return GetRawValue<VecI1>(n_corner).Value % 2 >= 1; return GetRawValue<VecI1>(n_corner).Value % 2 >= 1;
} }
} }
static readonly MotionName n_ctrl0 = new MotionName("ctrl0"); static readonly Identifier n_ctrl0 = new Identifier("ctrl0");
static readonly MotionName n_ctrl1 = new MotionName("ctrl1"); static readonly Identifier n_ctrl1 = new Identifier("ctrl1");
public Vector3 GetControlPoint(bool alt1, float deltaz) { public Vector3 GetControlPoint(bool alt1, float deltaz) {
var mv = GetRawValue<VecCtrl>(alt1 ? n_ctrl1 : n_ctrl0); var mv = GetRawValue<VecCtrl>(alt1 ? n_ctrl1 : n_ctrl0);
if (alt1 && mv.IsZero()) { if (alt1 && mv.IsZero()) {
@@ -296,7 +303,7 @@ namespace Cryville.Crtr.Event {
return mv.ToVector3(ChartPlayer.hitRect, deltaz); return mv.ToVector3(ChartPlayer.hitRect, deltaz);
} }
static readonly MotionName n_track = new MotionName("track"); static readonly Identifier n_track = new Identifier("track");
public float Track { public float Track {
get { get {
return GetRawValue<Vec1>(n_track).Value; return GetRawValue<Vec1>(n_track).Value;
@@ -314,7 +321,6 @@ namespace Cryville.Crtr.Event {
public void Handle(StampedEvent ev, Action<StampedEvent> callback = null) { public void Handle(StampedEvent ev, Action<StampedEvent> callback = null) {
if (breakflag) return; if (breakflag) return;
if (ev != null) { if (ev != null) {
bool flag = false;
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 = RMVPool.Rent(tev.Name);
@@ -354,18 +360,9 @@ namespace Cryville.Crtr.Event {
} }
} }
} }
if (ev.Unstamped == null) { Callback(ev.Unstamped == null || ev.Unstamped.Priority >= 0 ? ev : null, callback);
Callback(ev, callback);
flag = true;
}
else if (ev.Unstamped.Priority >= 0) {
Callback(ev, callback);
flag = true;
}
if (!flag) Callback(null, callback);
return;
} }
Callback(null, callback); else Callback(null, callback);
} }
void Callback(StampedEvent ev, Action<StampedEvent> callback) { void Callback(StampedEvent ev, Action<StampedEvent> callback) {
@@ -407,13 +404,17 @@ namespace Cryville.Crtr.Event {
} }
} }
public void BroadcastInit() { public void BroadcastPreInit() {
Handler.PreInit(); Handler.PreInit();
Handler.Init(); foreach (var c in Children.Values) {
foreach (var s in Children) { c.BroadcastPreInit();
s.Value.BroadcastInit();
} }
}
public void BroadcastPostInit() {
Handler.PostInit(); Handler.PostInit();
foreach (var c in Children.Values) {
c.BroadcastPostInit();
}
} }
public void StartUpdate() { public void StartUpdate() {

View File

@@ -35,6 +35,7 @@ namespace Cryville.Crtr.Event {
r.invalidatedStates = new HashSet<ContainerState>(); r.invalidatedStates = new HashSet<ContainerState>();
r.Time += offsetTime; r.Time += offsetTime;
r.RootState = RootState.Clone(ct); r.RootState = RootState.Clone(ct);
r.RootState.StartUpdate();
r.Expand(); r.Expand();
r.AttachBus(); r.AttachBus();
foreach (var s in r.states) r.invalidatedStates.Add(s.Value); foreach (var s in r.states) r.invalidatedStates.Add(s.Value);
@@ -146,8 +147,11 @@ namespace Cryville.Crtr.Event {
invalidatedStates.Clear(); invalidatedStates.Clear();
} }
public void BroadcastInit() { public void BroadcastPreInit() {
RootState.BroadcastInit(); RootState.BroadcastPreInit();
}
public void BroadcastPostInit() {
RootState.BroadcastPostInit();
} }
public void BroadcastEndUpdate() { public void BroadcastEndUpdate() {

View File

@@ -1,4 +1,5 @@
using Cryville.Common.Buffers; using Cryville.Common;
using Cryville.Common.Buffers;
using System.Collections.Generic; using System.Collections.Generic;
namespace Cryville.Crtr.Event { namespace Cryville.Crtr.Event {
@@ -12,16 +13,16 @@ namespace Cryville.Crtr.Event {
return new RealtimeMotionValue().Init(_reg.InitValue); return new RealtimeMotionValue().Init(_reg.InitValue);
} }
} }
static Dictionary<string, Bucket> _buckets; static Dictionary<Identifier, Bucket> _buckets;
public static void Prepare() { public static void Prepare() {
_buckets = new Dictionary<string, Bucket>(ChartPlayer.motionRegistry.Count); _buckets = new Dictionary<Identifier, Bucket>(ChartPlayer.motionRegistry.Count);
foreach (var reg in ChartPlayer.motionRegistry) foreach (var reg in ChartPlayer.motionRegistry)
_buckets.Add(reg.Key, new Bucket(reg.Key, 4096)); _buckets.Add(reg.Key, new Bucket(reg.Key, 4096));
} }
readonly Dictionary<RealtimeMotionValue, string> _rented = new Dictionary<RealtimeMotionValue, string>(); readonly Dictionary<RealtimeMotionValue, Identifier> _rented = new Dictionary<RealtimeMotionValue, Identifier>();
public RealtimeMotionValue Rent(MotionName name) { public RealtimeMotionValue Rent(Identifier name) {
var n = name.MainName; var n = name;
var obj = _buckets[n].Rent(); var obj = _buckets[n].Rent();
_rented.Add(obj, n); _rented.Add(obj, n);
return obj; return obj;

View File

@@ -1,9 +1,8 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 925f95cb7c6644a4695b2701d42e1ea2 guid: b9bd9e24d7c553341a2a12391843542f
folderAsset: yes folderAsset: yes
timeCreated: 1606989037
licenseType: Free
DefaultImporter: DefaultImporter:
externalObjects: {}
userData: userData:
assetBundleName: assetBundleName:
assetBundleVariant: assetBundleVariant:

View File

@@ -0,0 +1,183 @@
using Cryville.Common;
using Cryville.Common.Math;
using Cryville.Crtr.Browsing;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
namespace Cryville.Crtr.Extensions.Bestdori {
public class BestdoriChartConverter : ResourceConverter {
static readonly string[] SUPPORTED_FORMATS = { ".json" };
public override string[] GetSupportedFormats() {
return SUPPORTED_FORMATS;
}
public override IEnumerable<Resource> ConvertFrom(FileInfo file) {
List<Resource> result = new List<Resource>();
List<BestdoriChartEvent> src;
using (var reader = new StreamReader(file.FullName)) {
src = JsonConvert.DeserializeObject<List<BestdoriChartEvent>>(reader.ReadToEnd());
}
var group = new Chart.Group() {
tracks = new List<Chart.Track>(),
notes = new List<Chart.Note>(),
motions = new List<Chart.Motion>(),
};
Chart chart = new Chart {
format = 2,
time = new BeatTime(0, 0, 1),
ruleset = "bang_dream_girls_band_party",
sigs = new List<Chart.Signature>(),
sounds = new List<Chart.Sound>(),
motions = new List<Chart.Motion>(),
groups = new List<Chart.Group> { group },
};
string bgm = null;
double? cbpm = null;
double pbeat = 0, ctime = 0;
double endbeat = 0;
foreach (var ev in src) {
double cbeat = ev.StartBeat;
ctime += cbpm == null ? 0 : (cbeat - pbeat) / cbpm.Value * 60;
pbeat = cbeat;
if (cbeat > endbeat) endbeat = cbeat;
if (ev is BestdoriChartEvent.System) {
if (bgm != null) continue;
var tev = (BestdoriChartEvent.System)ev;
bgm = StringUtils.TrimExt(tev.data);
var name = "bang_dream_girls_band_party__" + bgm;
result.Add(new SongResource(name, new FileInfo(Path.Combine(file.Directory.FullName, tev.data))));
chart.sounds.Add(new Chart.Sound { time = ToBeatTime(tev.beat), id = name });
}
else if (ev is BestdoriChartEvent.BPM) {
var tev = (BestdoriChartEvent.BPM)ev;
cbpm = tev.bpm;
chart.sigs.Add(new Chart.Signature { time = ToBeatTime(tev.beat), tempo = (float)tev.bpm });
}
else if (ev is BestdoriChartEvent.Single) {
var tev = (BestdoriChartEvent.Single)ev;
group.notes.Add(new Chart.Note {
time = ToBeatTime(tev.beat),
judges = new List<Chart.Judge> { new Chart.Judge { name = tev.flick ? "single_flick" : "single" } },
motions = new List<Chart.Motion> { new Chart.Motion { motion = "track:" + tev.lane.ToString() } },
});
}
else if (ev is BestdoriChartEvent.Long) {
var tev = (BestdoriChartEvent.Long)ev;
var c1 = tev.connections[tev.connections.Count - 1];
var note = new Chart.Note {
time = ToBeatTime(tev.connections[0].beat),
endtime = ToBeatTime(c1.beat),
judges = new List<Chart.Judge>(),
};
for (int i = 0; i < tev.connections.Count; i++) {
BestdoriChartEvent.Connection c = tev.connections[i];
note.motions.Add(new Chart.Motion { motion = "track:" + c.lane.ToString() });
if (i == 0)
note.judges.Add(new Chart.Judge { name = "single" });
else if (i == tev.connections.Count - 1)
note.judges.Add(new Chart.Judge { time = ToBeatTime(c.beat), name = c.flick ? "longend_flick" : "longend" });
else if (!c.hidden)
note.judges.Add(new Chart.Judge { time = ToBeatTime(c.beat), name = "longnode" });
}
if (c1.beat > endbeat) endbeat = c1.beat;
group.notes.Add(note);
}
else throw new NotImplementedException("Unsupported event: " + ev.type);
}
if (bgm == null) throw new FormatException("Chart contains no song");
chart.endtime = ToBeatTime(endbeat);
result.Add(new RawChartResource(string.Format("bang_dream_girls_band_party__{0}__{1}", bgm, StringUtils.TrimExt(file.Name)), chart, new ChartMeta {
name = string.Format("Bandori {0} {1}", bgm, StringUtils.TrimExt(file.Name)),
author = "©BanG Dream! Project ©Craft Egg Inc. ©bushiroad",
ruleset = "bang_dream_girls_band_party",
note_count = group.notes.Count,
length = (float)ctime,
song = new SongMetaInfo {
name = bgm,
author = "©BanG Dream! Project ©Craft Egg Inc. ©bushiroad",
}
}));
return result;
}
BeatTime ToBeatTime(double beat, double error = 1e-4) {
int i, n, d;
FractionUtils.ToFraction(beat, error, out n, out d);
i = n / d; n %= d;
return new BeatTime(i, n, d);
}
}
#pragma warning disable IDE1006
[JsonConverter(typeof(BestdoriChartEventCreator))]
abstract class BestdoriChartEvent {
public abstract string type { get; }
public abstract double StartBeat { get; }
public abstract class InstantEvent : BestdoriChartEvent {
public double beat;
public override double StartBeat { get { return beat; } }
}
public class BPM : InstantEvent {
public override string type { get { return "BPM"; } }
public double bpm;
}
public class System : InstantEvent {
public override string type { get { return "System"; } }
public string data;
}
public abstract class SingleBase : InstantEvent {
public double lane;
public bool skill;
public bool flick;
}
public class Single : SingleBase {
public override string type { get { return "Single"; } }
}
public class Directional : SingleBase {
public override string type { get { return "Directional"; } }
public string direction;
public int width;
}
public class Connection : SingleBase {
public override string type { get { return null; } }
public bool hidden;
}
public class Long : BestdoriChartEvent {
public override string type { get { return "Long"; } }
public List<Connection> connections;
public override double StartBeat { get { return connections[0].beat; } }
}
public class Slide : Long {
public override string type { get { return "Slide"; } }
}
}
#pragma warning restore IDE1006
class BestdoriChartEventCreator : CustomCreationConverter<BestdoriChartEvent> {
string _currentType;
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
var obj = JObject.ReadFrom(reader);
var type = obj["type"];
if (type == null) _currentType = null;
else _currentType = obj["type"].ToObject<string>();
return base.ReadJson(obj.CreateReader(), objectType, existingValue, serializer);
}
public override BestdoriChartEvent Create(Type objectType) {
switch (_currentType) {
case "BPM": return new BestdoriChartEvent.BPM();
case "System": return new BestdoriChartEvent.System();
case "Single": return new BestdoriChartEvent.Single();
case "Directional": return new BestdoriChartEvent.Directional();
case null: return new BestdoriChartEvent.Connection();
case "Long": return new BestdoriChartEvent.Long();
case "Slide": return new BestdoriChartEvent.Slide();
default: throw new ArgumentException("Unknown event type: " + _currentType);
}
}
}
}

View File

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

View File

@@ -2,6 +2,7 @@ using Cryville.Crtr.Browsing;
using Newtonsoft.Json; using Newtonsoft.Json;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@@ -17,23 +18,32 @@ namespace Cryville.Crtr.Extensions.Malody {
public override IEnumerable<Resource> ConvertFrom(FileInfo file) { public override IEnumerable<Resource> ConvertFrom(FileInfo file) {
List<Resource> result = new List<Resource>(); List<Resource> result = new List<Resource>();
MalodyChart src; MalodyChart src;
if (file.Extension != ".mc") throw new NotImplementedException("mcz file is not supported");
using (var reader = new StreamReader(file.FullName)) { using (var reader = new StreamReader(file.FullName)) {
src = JsonConvert.DeserializeObject<MalodyChart>(reader.ReadToEnd()); src = JsonConvert.DeserializeObject<MalodyChart>(reader.ReadToEnd());
} }
if (src.meta.mode != 0) throw new NotImplementedException("The chart mode is not supported"); if (src.meta.mode != 0) throw new NotImplementedException("The chart mode is not supported");
if (src.meta.mode_ext.column != 4) throw new NotImplementedException("The key count is not supported");
var ruleset = "malody!" + MODES[src.meta.mode];
if (src.meta.mode == 0) {
ruleset += "." + src.meta.mode_ext.column.ToString(CultureInfo.InvariantCulture) + "k";
}
ChartMeta meta = new ChartMeta() { ChartMeta meta = new ChartMeta() {
song = new ChartMeta.MetaInfo() { name = src.meta.version,
author = src.meta.creator,
song = new SongMetaInfo() {
name = src.meta.song.titleorg != null ? src.meta.song.titleorg : src.meta.song.title, name = src.meta.song.titleorg != null ? src.meta.song.titleorg : src.meta.song.title,
author = src.meta.song.artistorg != null ? src.meta.song.artistorg : src.meta.song.artist, author = src.meta.song.artistorg != null ? src.meta.song.artistorg : src.meta.song.artist,
}, },
ruleset = "malody!" + MODES[src.meta.mode], ruleset = ruleset,
}; };
Chart chart = new Chart { Chart chart = new Chart {
format = 2, format = 2,
time = new BeatTime(-4, 0, 1), time = new BeatTime(-4, 0, 1),
ruleset = "malody!" + MODES[src.meta.mode], ruleset = ruleset,
sigs = new List<Chart.Signature>(), sigs = new List<Chart.Signature>(),
sounds = new List<Chart.Sound>(), sounds = new List<Chart.Sound>(),
motions = new List<Chart.Motion>(), motions = new List<Chart.Motion>(),
@@ -64,16 +74,17 @@ namespace Cryville.Crtr.Extensions.Malody {
Dictionary<MalodyChart.IEvent, StartEventState> longEvents Dictionary<MalodyChart.IEvent, StartEventState> longEvents
= new Dictionary<MalodyChart.IEvent, StartEventState>(); = new Dictionary<MalodyChart.IEvent, StartEventState>();
float? baseBpm = null; float? baseBpm = null, cbpm = null;
float pbeat = 0f, ctime = 0f; float pbeat = 0f, ctime = 0f;
int[] endbeat = new int[] { 0, 0, 1 }; int[] endbeat = new int[] { 0, 0, 1 };
foreach (var ev in events) { foreach (var ev in events) {
float cbeat = bp(ev.beat); float cbeat = ConvertBeat(ev.beat);
ctime += baseBpm == null ? 0 : (cbeat - pbeat) / baseBpm.Value * 60f; ctime += cbpm == null ? 0 : (cbeat - pbeat) / cbpm.Value * 60f;
pbeat = cbeat; pbeat = cbeat;
if (ev is MalodyChart.Time) { if (ev is MalodyChart.Time) {
var tev = (MalodyChart.Time)ev; var tev = (MalodyChart.Time)ev;
if (baseBpm == null) baseBpm = tev.bpm; if (baseBpm == null) baseBpm = tev.bpm;
cbpm = tev.bpm;
chart.sigs.Add(new Chart.Signature { chart.sigs.Add(new Chart.Signature {
time = new BeatTime(ev.beat[0], ev.beat[1], ev.beat[2]), time = new BeatTime(ev.beat[0], ev.beat[1], ev.beat[2]),
tempo = tev.bpm, tempo = tev.bpm,
@@ -94,17 +105,18 @@ namespace Cryville.Crtr.Extensions.Malody {
var tev = (MalodyChart.Note)ev; var tev = (MalodyChart.Note)ev;
if (tev.type == 1) { if (tev.type == 1) {
if (tev.beat[0] == 0 && tev.beat[1] == 0) { if (tev.beat[0] == 0 && tev.beat[1] == 0) {
result.Add(new SongResource(meta.song.name, new FileInfo(file.DirectoryName + "/" + tev.sound))); var res = new SongResource(meta.song.name, new FileInfo(file.DirectoryName + "/" + tev.sound));
result.Add(res);
chart.sounds.Add(new Chart.Sound { chart.sounds.Add(new Chart.Sound {
time = new BeatTime(0, 0, 1), time = new BeatTime(0, 0, 1),
id = meta.song.name, id = res.Name,
offset = -tev.offset / 1000f, offset = -tev.offset / 1000f,
}); });
} }
else throw new NotImplementedException(); else throw new NotImplementedException();
} }
else { else {
if (bp(tev.beat) > bp(endbeat)) endbeat = tev.beat; if (ConvertBeat(tev.beat) > ConvertBeat(endbeat)) endbeat = tev.beat;
var rn = new Chart.Note() { var rn = new Chart.Note() {
time = new BeatTime(tev.beat[0], tev.beat[1], tev.beat[2]), time = new BeatTime(tev.beat[0], tev.beat[1], tev.beat[2]),
motions = new List<Chart.Motion> { motions = new List<Chart.Motion> {
@@ -112,7 +124,7 @@ namespace Cryville.Crtr.Extensions.Malody {
}, },
}; };
if (tev.endbeat != null) { if (tev.endbeat != null) {
if (bp(tev.endbeat) > bp(endbeat)) endbeat = tev.endbeat; if (ConvertBeat(tev.endbeat) > ConvertBeat(endbeat)) endbeat = tev.endbeat;
rn.endtime = new BeatTime(tev.endbeat[0], tev.endbeat[1], tev.endbeat[2]); rn.endtime = new BeatTime(tev.endbeat[0], tev.endbeat[1], tev.endbeat[2]);
longEvents.Add(ev, new StartEventState { longEvents.Add(ev, new StartEventState {
Destination = rn, Destination = rn,
@@ -133,16 +145,13 @@ namespace Cryville.Crtr.Extensions.Malody {
else throw new NotSupportedException(); else throw new NotSupportedException();
} }
chart.endtime = new BeatTime(endbeat[0] + 4, endbeat[1], endbeat[2]); chart.endtime = new BeatTime(endbeat[0] + 4, endbeat[1], endbeat[2]);
meta.chart = new ChartMeta.MetaInfo() { meta.length = ctime;
name = src.meta.version,
author = src.meta.creator,
length = ctime,
};
meta.note_count = group.notes.Count; meta.note_count = group.notes.Count;
string chartName = string.Format("{0} - {1}", meta.song.name, meta.chart.name); string chartName = string.Format("{0} - {1}", meta.song.name, meta.name);
result.Add(new ChartResource(chartName, chart, meta)); if (src.meta.background != null) {
if (src.meta.background != null) meta.cover = src.meta.background;
result.Add(new CoverResource(chartName, new FileInfo(file.DirectoryName + "/" + src.meta.background))); }
result.Add(new RawChartResource(chartName, chart, meta));
return result; return result;
} }
@@ -151,13 +160,13 @@ namespace Cryville.Crtr.Extensions.Malody {
public ChartEvent Destination { get; set; } public ChartEvent Destination { get; set; }
} }
float bp(int[] beat) { float ConvertBeat(int[] beat) {
return beat[0] + (float)beat[1] / beat[2]; return beat[0] + (float)beat[1] / beat[2];
} }
} }
#pragma warning disable IDE1006 #pragma warning disable IDE1006
public struct MalodyChart { struct MalodyChart {
public interface IEvent { public interface IEvent {
int[] beat { get; set; } int[] beat { get; set; }
int[] endbeat { get; set; } int[] endbeat { get; set; }

View File

@@ -76,21 +76,35 @@ namespace Cryville.Crtr {
#if UNITY_ANDROID #if UNITY_ANDROID
Cryville.Audio.OpenSL.OutputClient.CallbackFunction = audioCallback; Cryville.Audio.OpenSL.OutputClient.CallbackFunction = audioCallback;
#endif #endif
AudioManager = EngineBuilder.Create(); while (true) {
Logger.Log("main", 1, "Audio", "Using audio API: {0}", AudioManager.GetType().Namespace); try {
AudioClient = AudioManager.GetDefaultDevice(DataFlow.Out).Connect(); AudioManager = EngineBuilder.Create();
AudioClient.Init(AudioClient.DefaultFormat); if (AudioManager == null) {
AudioClient.Source = AudioSequencer = new SimpleSequencerSource(); Popup.Create("Cannot initialize audio engine");
AudioSession = AudioSequencer.NewSession(); Logger.Log("main", 5, "Audio", "Cannot initialize audio engine");
AudioSequencer.Playing = true; }
AudioClient.Start(); else {
Logger.Log("main", 1, "Audio", "Using audio API: {0}", AudioManager.GetType().Namespace);
AudioClient = AudioManager.GetDefaultDevice(DataFlow.Out).Connect();
AudioClient.Init(AudioClient.DefaultFormat);
AudioClient.Source = AudioSequencer = new SimpleSequencerSource();
AudioSession = AudioSequencer.NewSession();
AudioSequencer.Playing = true;
AudioClient.Start();
}
break;
}
catch (Exception ex) {
Logger.Log("main", 4, "Audio", "An error occured when initializing the audio engine: {0}", ex);
Logger.Log("main", 3, "Audio", "Trying to use fallback audio engines");
EngineBuilder.Engines.Remove(AudioManager.GetType());
}
}
ChartPlayer.motionRegistry = new Dictionary<string, MotionRegistry> { ChartPlayer.motionRegistry = new Dictionary<Identifier, MotionRegistry> {
{ "pt" , new MotionRegistry(typeof(VecPt)) },
{ "dir" , new MotionRegistry(typeof(Vec3)) }, { "dir" , new MotionRegistry(typeof(Vec3)) },
{ "normal" , new MotionRegistry(typeof(Vec3)) }, { "normal" , new MotionRegistry(typeof(Vec3)) },
// { "pdirz", new MotionRegistry(typeof(Vec1)) },
{ "pt" , new MotionRegistry(typeof(VecPt)) },
// { "visible", new MotionRegistry(typeof(VecI1)) },
{ "sv" , new MotionRegistry(new VecPtComp(0f, 0f), new VecPtComp(0f, 1f)) }, { "sv" , new MotionRegistry(new VecPtComp(0f, 0f), new VecPtComp(0f, 1f)) },
{ "svm" , new MotionRegistry(new Vec1m(1f)) }, { "svm" , new MotionRegistry(new Vec1m(1f)) },
{ "dist" , new MotionRegistry(new VecPtComp(0f, 0f), new VecPtComp(0f, float.PositiveInfinity)) }, { "dist" , new MotionRegistry(new VecPtComp(0f, 0f), new VecPtComp(0f, float.PositiveInfinity)) },
@@ -98,8 +112,6 @@ namespace Cryville.Crtr {
{ "ctrl0" , new MotionRegistry(typeof(VecCtrl)) }, { "ctrl0" , new MotionRegistry(typeof(VecCtrl)) },
{ "ctrl1" , new MotionRegistry(typeof(VecCtrl)) }, { "ctrl1" , new MotionRegistry(typeof(VecCtrl)) },
{ "track" , new MotionRegistry(typeof(Vec1)) }, { "track" , new MotionRegistry(typeof(Vec1)) },
// { "judge" , new MotionRegistry(typeof(Vec1)) },
// { "width" , new MotionRegistry(new Vec1(0), new Vec1(1)) },
}; };
var dir = new DirectoryInfo(Settings.Default.GameDataPath + "/charts"); var dir = new DirectoryInfo(Settings.Default.GameDataPath + "/charts");

View File

@@ -19,6 +19,7 @@ namespace Cryville.Crtr {
public static void LoadDefault() { public static void LoadDefault() {
if (loaded) return; if (loaded) return;
Components.Add("image", typeof(SpritePlane)); Components.Add("image", typeof(SpritePlane));
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));
@@ -29,8 +30,7 @@ namespace Cryville.Crtr {
Meshes.Add("quad_scale3h", Resources.Load<Mesh>("quad_scale3h")); Meshes.Add("quad_scale3h", Resources.Load<Mesh>("quad_scale3h"));
Meshes.Add("quad_scale9", Resources.Load<Mesh>("quad_scale9")); Meshes.Add("quad_scale9", Resources.Load<Mesh>("quad_scale9"));
Materials.Add("-CutoutMat", Resources.Load<Material>("CutoutMat")); Materials.Add("-SpriteMat", Resources.Load<Material>("SpriteMat"));
Materials.Add("-TransparentMat", Resources.Load<Material>("TransparentMat"));
loaded = true; loaded = true;
} }

View File

@@ -1,17 +1,26 @@
using Cryville.Common.Unity.Input; using Cryville.Common;
using Cryville.Common.Pdt;
using Cryville.Common.Unity.Input;
using Cryville.Crtr.Config;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine;
namespace Cryville.Crtr { namespace Cryville.Crtr {
public class InputProxy { public class InputProxy : IDisposable {
readonly PdtEvaluator _etor;
readonly PdtRuleset _ruleset; readonly PdtRuleset _ruleset;
readonly Dictionary<string, InputProxyEntry> _hash1 = new Dictionary<string, InputProxyEntry>(); readonly Judge _judge;
readonly Dictionary<InputSource, InputProxyEntry> _hash2 = new Dictionary<InputSource, InputProxyEntry>(); public InputProxy(PdtRuleset ruleset, Judge judge) {
readonly Dictionary<string, int> _use = new Dictionary<string, int>(); unsafe {
readonly Dictionary<string, List<string>> _rev = new Dictionary<string, List<string>>(); fixed (byte* ptr = _vecbuf) {
public event EventHandler<ProxyChangedEventArgs> ProxyChanged; *(int*)(ptr + 3 * sizeof(float)) = PdtInternalType.Number;
public InputProxy(PdtRuleset ruleset) { }
}
_vecsrc = new PropSrc.Arbitrary(PdtInternalType.Vector, _vecbuf);
_etor = ChartPlayer.etor;
_ruleset = ruleset; _ruleset = ruleset;
_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<string>());
@@ -23,27 +32,66 @@ namespace Cryville.Crtr {
} }
} }
} }
#region Settings
readonly Dictionary<string, InputProxyEntry> _tproxies = new Dictionary<string, InputProxyEntry>();
readonly Dictionary<InputSource, InputProxyEntry> _sproxies = new Dictionary<InputSource, InputProxyEntry>();
readonly Dictionary<string, int> _use = new Dictionary<string, int>();
readonly Dictionary<string, List<string>> _rev = new Dictionary<string, List<string>>();
public event EventHandler<ProxyChangedEventArgs> ProxyChanged;
public void LoadFrom(Dictionary<string, RulesetConfig.InputEntry> config) {
foreach (var cfg in config) {
Set(new InputProxyEntry {
Target = cfg.Key,
Source = new InputSource {
Handler = Game.InputManager.GetHandler(cfg.Value.handler),
Type = cfg.Value.type
}
});
}
}
public void SaveTo(Dictionary<string, RulesetConfig.InputEntry> config) {
config.Clear();
foreach (var p in _tproxies) {
config.Add(p.Key, new RulesetConfig.InputEntry {
handler = ReflectionHelper.GetNamespaceQualifiedName(p.Value.Source.Value.Handler.GetType()),
type = p.Value.Source.Value.Type
});
}
}
public void Set(InputProxyEntry proxy) { public void Set(InputProxyEntry proxy) {
var name = proxy.Target; var target = proxy.Target;
if (_hash1.ContainsKey(name)) Remove(proxy); if (!_ruleset.inputs.ContainsKey(target)) throw new ArgumentException("Invalid input name");
if (_use[proxy.Target] > 0) if (_tproxies.ContainsKey(target)) Remove(proxy);
if (_use[target] > 0)
throw new InvalidOperationException("Input already assigned"); throw new InvalidOperationException("Input already assigned");
if (proxy.Source != null) { if (proxy.Source != null) {
_hash1.Add(proxy.Target, proxy); if (_judge != null) {
_hash2.Add(proxy.Source.Value, proxy); proxy.Source.Value.Handler.OnInput -= OnInput; // Prevent duplicated hooks, no exception will be thrown
IncrementUseRecursive(name); proxy.Source.Value.Handler.OnInput += OnInput;
IncrementReversedUseRecursive(name); }
_tproxies.Add(target, proxy);
_sproxies.Add(proxy.Source.Value, proxy);
IncrementUseRecursive(target);
IncrementReversedUseRecursive(target);
} }
} }
void Remove(InputProxyEntry proxy) { void Remove(InputProxyEntry proxy) {
var name = proxy.Target; var target = proxy.Target;
_hash2.Remove(_hash1[name].Source.Value); if (_judge != null) _tproxies[target].Source.Value.Handler.OnInput -= OnInput;
_hash1.Remove(name); _sproxies.Remove(_tproxies[target].Source.Value);
DecrementUseRecursive(name); _tproxies.Remove(target);
DecrementReversedUseRecursive(name); DecrementUseRecursive(target);
DecrementReversedUseRecursive(target);
} }
public bool IsUsed(InputSource src) { public bool IsUsed(InputSource src) {
return _hash2.ContainsKey(src); return _sproxies.ContainsKey(src);
}
public bool IsCompleted {
get {
foreach (var i in _use)
if (i.Value == 0 && !_tproxies.ContainsKey(i.Key)) return false;
return true;
}
} }
void IncrementUseRecursive(string name) { void IncrementUseRecursive(string name) {
BroadcastProxyChanged(name); BroadcastProxyChanged(name);
@@ -80,8 +128,129 @@ namespace Cryville.Crtr {
} }
} }
void BroadcastProxyChanged(string name) { void BroadcastProxyChanged(string name) {
ProxyChanged(this, new ProxyChangedEventArgs(name, _hash1.ContainsKey(name) ? _hash1[name].Source : null, _use[name] > 0)); var del = ProxyChanged;
if (del != null) del(this, this[name]);
} }
public ProxyChangedEventArgs this[string name] {
get {
return new ProxyChangedEventArgs(name, _tproxies.ContainsKey(name) ? _tproxies[name].Source : null, _use[name] > 0);
}
}
#endregion
#region Handling
public void Activate() {
_activeCounts.Clear();
_vect.Clear(); _vecs.Clear();
foreach (var src in _sproxies.Keys) {
_activeCounts.Add(src, 0);
src.Handler.Activate();
}
}
public void Deactivate() { foreach (var src in _sproxies.Keys) src.Handler.Deactivate(); }
~InputProxy() {
Dispose(false);
GC.SuppressFinalize(this);
}
public void Dispose() {
Dispose(true);
}
protected void Dispose(bool disposing) {
if (disposing) {
Deactivate();
foreach (var proxy in _tproxies.Values) {
proxy.Source.Value.Handler.OnInput -= OnInput;
}
}
}
readonly object _lock = new object();
static readonly int _var_value = IdentifierManager.SharedInstance.Request("value");
static readonly PropOp.Arbitrary _arbop = new PropOp.Arbitrary();
readonly byte[] _vecbuf = new byte[3 * sizeof(float) + sizeof(int)];
readonly PropSrc.Arbitrary _vecsrc;
readonly Dictionary<InputHandler, double> _timeOrigins = new Dictionary<InputHandler, double>();
readonly Dictionary<InputSource, int> _activeCounts = new Dictionary<InputSource, int>();
readonly Dictionary<InputIdentifier, float> _vect = new Dictionary<InputIdentifier, float>();
readonly Dictionary<ProxiedInputIdentifier, PropSrc.Arbitrary> _vecs = new Dictionary<ProxiedInputIdentifier, PropSrc.Arbitrary>();
static readonly PropSrc.Arbitrary _nullsrc = new PropSrc.Arbitrary(PdtInternalType.Null, new byte[0]);
unsafe void OnInput(InputIdentifier id, InputVector vec) {
lock (_lock) {
InputProxyEntry proxy;
if (_sproxies.TryGetValue(id.Source, out proxy)) {
_etor.ContextCascadeInsert();
float ft, tt = (float)(vec.Time - _timeOrigins[id.Source.Handler]);
if (!_vect.TryGetValue(id, out ft)) ft = tt;
if (vec.IsNull) {
_etor.ContextCascadeUpdate(_var_value, _nullsrc);
OnInput(id, proxy.Target, ft, tt, true);
}
else {
fixed (byte* ptr = _vecbuf) {
*(Vector3*)ptr = vec.Vector;
}
_vecsrc.Invalidate();
_etor.ContextCascadeUpdate(_var_value, _vecsrc);
OnInput(id, proxy.Target, ft, tt, false);
}
_vect[id] = tt;
_etor.ContextCascadeDiscard();
}
}
}
static readonly int _var_fv = IdentifierManager.SharedInstance.Request("fv");
static readonly int _var_tv = IdentifierManager.SharedInstance.Request("tv");
unsafe void OnInput(InputIdentifier id, Identifier target, float ft, float tt, bool nullflag) {
var def = _ruleset.inputs[target];
if (def.pass != null) {
foreach (var p in def.pass) {
_etor.ContextCascadeInsert();
_arbop.Name = _var_value;
if (!nullflag) _etor.Evaluate(_arbop, p.Value);
OnInput(id, p.Key, ft, tt, nullflag);
_etor.ContextCascadeDiscard();
}
}
else {
var pid = new ProxiedInputIdentifier { Source = id, Target = target };
PropSrc.Arbitrary fv, tv = _etor.ContextCascadeLookup(_var_value);
if (!_vecs.TryGetValue(pid, out fv)) fv = _nullsrc;
if (fv.Type != PdtInternalType.Null || tv.Type != PdtInternalType.Null) {
if (fv.Type == PdtInternalType.Null) _activeCounts[id.Source]++;
_etor.ContextCascadeInsert();
_etor.ContextCascadeUpdate(_var_fv, fv);
_etor.ContextCascadeUpdate(_var_tv, tv);
_judge.Feed(target, ft, tt);
_etor.ContextCascadeDiscard();
if (tv.Type == PdtInternalType.Null) _activeCounts[id.Source]--;
}
_judge.Cleanup(target, ft, tt);
_vecs[pid] = tv;
}
}
public void SyncTime(double time) {
foreach (var s in _sproxies.Keys) {
var h = s.Handler;
if (!_timeOrigins.ContainsKey(h))
_timeOrigins.Add(h, h.GetCurrentTimestamp() - time);
}
}
public void ForceTick() {
foreach (var src in _sproxies.Keys) {
if (_activeCounts[src] == 0) {
OnInput(new InputIdentifier { Source = src, Id = 0 }, new InputVector(src.Handler.GetCurrentTimestamp()));
}
}
}
public double GetTimestampAverage() {
double result = 0;
foreach (var src in _sproxies.Keys) {
result += src.Handler.GetCurrentTimestamp() - _timeOrigins[src.Handler];
}
return result / _sproxies.Count;
}
#endregion
} }
public class ProxyChangedEventArgs : EventArgs { public class ProxyChangedEventArgs : EventArgs {
@@ -101,44 +270,27 @@ namespace Cryville.Crtr {
public byte[] Mapping { get; private set; } public byte[] Mapping { get; private set; }
} }
public sealed class InputProxyHandler : InputHandler { public struct ProxiedInputIdentifier : IEquatable<ProxiedInputIdentifier> {
readonly InputDefinition _def; public InputIdentifier Source { get; set; }
public Identifier Target { get; set; }
public InputProxyHandler(InputDefinition def, InputHandler src) : base() { public override bool Equals(object obj) {
_def = def; if (obj == null || !(obj is ProxiedInputIdentifier)) return false;
src.Callback = OnInput; return Equals((ProxiedInputIdentifier)obj);
} }
public bool Equals(ProxiedInputIdentifier other) {
public override void Activate() { return Source == other.Source && Target == other.Target;
throw new NotImplementedException();
} }
public override int GetHashCode() {
public override void Deactivate() { return Source.GetHashCode() ^ Target.GetHashCode();
throw new NotImplementedException();
} }
public override string ToString() {
public override void Dispose(bool disposing) { return string.Format("{0}->{1}", Source, Target);
throw new NotImplementedException();
} }
public static bool operator ==(ProxiedInputIdentifier lhs, ProxiedInputIdentifier rhs) {
public override bool IsNullable(int type) { return lhs.Equals(rhs);
throw new NotImplementedException();
} }
public static bool operator !=(ProxiedInputIdentifier lhs, ProxiedInputIdentifier rhs) {
public override byte GetDimension(int type) { return !lhs.Equals(rhs);
throw new NotImplementedException();
}
public override string GetTypeName(int type) {
throw new NotImplementedException();
}
public override double GetCurrentTimestamp() {
throw new NotImplementedException();
}
void OnInput(InputIdentifier id, InputVector vec) {
} }
} }
} }

View File

@@ -1,58 +1,279 @@
using Cryville.Common;
using Cryville.Common.Buffers;
using Cryville.Common.Pdt; using Cryville.Common.Pdt;
using Cryville.Common.Unity.Input; using Cryville.Crtr.Event;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
namespace Cryville.Crtr { namespace Cryville.Crtr {
public class Judge { public class Judge {
readonly PdtEvaluator _etor;
readonly PdtRuleset _rs; readonly PdtRuleset _rs;
public Judge(PdtRuleset rs) { readonly Dictionary<Identifier, float> ct
_rs = rs; = new Dictionary<Identifier, float>();
foreach (var s in rs.scores) readonly Dictionary<Identifier, List<JudgeEvent>> evs
scores.Add(s.Key, s.Value.init); = new Dictionary<Identifier, List<JudgeEvent>>();
readonly Dictionary<Identifier, List<JudgeEvent>> activeEvs
= new Dictionary<Identifier, List<JudgeEvent>>();
struct JudgeEvent {
public float StartTime { get; set; }
public float EndTime { get; set; }
public float StartClip { get; set; }
public float EndClip { get; set; }
public JudgeDefinition Definition { get; set; }
public ContainerState State { get; set; }
} }
public void StartFrame() { static readonly IComparer<JudgeEvent> _stcmp = new JudgeEventStartTimeComparer();
class JudgeEventStartTimeComparer : IComparer<JudgeEvent> {
} public int Compare(JudgeEvent x, JudgeEvent y) {
public void Feed(InputEvent ev) { return x.StartClip.CompareTo(y.StartClip);
}
public void EndFrame() {
}
public readonly Dictionary<string, float> scores = new Dictionary<string, float>();
readonly Dictionary<string, string> ScoreCache = new Dictionary<string, string>();
public Dictionary<string, string> GetFormattedScoreStrings() {
if (ScoreCache.Count == 0) {
foreach (var s in scores)
ScoreCache.Add(s.Key, s.Value.ToString(_rs.scores[s.Key].format));
} }
return ScoreCache; }
public Judge(PdtRuleset rs) {
_etor = ChartPlayer.etor;
_rs = rs;
InitScores();
}
public void Prepare(float st, float et, Identifier input, JudgeDefinition def, ContainerState container) {
List<JudgeEvent> list;
if (!evs.TryGetValue(input, out list)) {
ct.Add(input, 0);
evs.Add(input, list = new List<JudgeEvent>());
activeEvs.Add(input, new List<JudgeEvent>());
}
var ev = new JudgeEvent {
StartTime = st,
EndTime = et,
StartClip = st + def.clip[0],
EndClip = et + def.clip[1],
Definition = def,
State = container,
};
var index = list.BinarySearch(ev, _stcmp);
if (index < 0) index = ~index;
list.Insert(index, ev);
}
static bool _flag;
static readonly PropOp.Boolean _flagop = new PropOp.Boolean(v => _flag = v);
static readonly int _var_fn = IdentifierManager.SharedInstance.Request("fn");
static readonly int _var_tn = IdentifierManager.SharedInstance.Request("tn");
static readonly int _var_ft = IdentifierManager.SharedInstance.Request("ft");
static readonly int _var_tt = IdentifierManager.SharedInstance.Request("tt");
readonly byte[] _numbuf1 = new byte[sizeof(float)];
readonly byte[] _numbuf2 = new byte[sizeof(float)];
readonly byte[] _numbuf3 = new byte[sizeof(float)];
readonly byte[] _numbuf4 = new byte[sizeof(float)];
unsafe void LoadNum(byte[] buffer, float value) {
fixed (byte* ptr = buffer) *(float*)ptr = value;
}
// Adopted from System.Collections.Generic.ArraySortHelper<T>.InternalBinarySearch(T[] array, int index, int length, T value, IComparer<T> comparer)
int BinarySearch(List<JudgeEvent> list, float time, int stack) {
int num = 0;
int num2 = list.Count - 1;
while (num <= num2) {
int num3 = num + (num2 - num >> 1);
int num4 = -list[num3].Definition.stack.CompareTo(stack);
if (num4 == 0) num4 = list[num3].StartClip.CompareTo(time);
if (num4 == 0) return num3;
else if (num4 < 0) num = num3 + 1;
else num2 = num3 - 1;
}
return ~num;
}
int BinarySearchFirst(List<JudgeEvent> list, float time, int stack) {
if (list[0].Definition.stack == stack && list[0].StartClip == time) return 0;
int num = 0;
int num2 = list.Count - 1;
while (num <= num2) {
int num3 = num + (num2 - num >> 1);
int num4 = -list[num3].Definition.stack.CompareTo(stack);
if (num4 == 0) num4 = list[num3].StartClip.CompareTo(time);
if (num4 >= 0) num2 = num3 - 1;
else num = num3 + 1;
}
return num + 1;
}
public void Feed(Identifier target, float ft, float tt) {
Forward(target, tt);
var actlist = activeEvs[target];
if (actlist.Count > 0) {
LoadNum(_numbuf3, ft); _etor.ContextCascadeUpdate(_var_ft, new PropSrc.Arbitrary(PdtInternalType.Number, _numbuf3));
LoadNum(_numbuf4, tt); _etor.ContextCascadeUpdate(_var_tt, new PropSrc.Arbitrary(PdtInternalType.Number, _numbuf4));
var index = 0;
while (index >= 0 && index < actlist.Count) {
var ev = actlist[index];
LoadNum(_numbuf1, ev.StartTime); _etor.ContextCascadeUpdate(_var_fn, new PropSrc.Arbitrary(PdtInternalType.Number, _numbuf1));
LoadNum(_numbuf2, ev.EndTime); _etor.ContextCascadeUpdate(_var_tn, new PropSrc.Arbitrary(PdtInternalType.Number, _numbuf2));
var def = ev.Definition;
if (def.hit != null) _etor.Evaluate(_flagop, def.hit);
else _flag = true;
if (_flag) {
if (def.scores != null) UpdateScore(def.scores);
if (def.pass != null) Pass(def.pass);
actlist.RemoveAt(index);
if (def.prop != 0 && actlist.Count > 0) {
index = BinarySearchFirst(actlist, ev.StartClip, def.stack - def.prop);
if (index < 0) index = ~index;
}
else index++;
}
else index++;
}
}
}
bool Pass(Identifier[] ids) {
foreach (var i in ids) {
var def = _rs.judges[i];
if (def.hit != null) _etor.Evaluate(_flagop, def.hit);
else _flag = true;
if (_flag) {
if (def.scores != null) UpdateScore(def.scores);
if (def.pass != null) Pass(def.pass);
return true;
}
}
return false;
}
public void Cleanup(Identifier target, float ft, float tt) {
Forward(target, tt);
var actlist = activeEvs[target];
for (int i = actlist.Count - 1; i >= 0; i--) {
JudgeEvent ev = actlist[i];
if (tt > ev.EndClip) {
actlist.RemoveAt(i);
if (ev.Definition.miss != null) Pass(ev.Definition.miss);
}
}
}
void Forward(Identifier target, float tt) {
var list = evs[target];
var actlist = activeEvs[target];
JudgeEvent ev;
while (list.Count > 0 && (ev = list[0]).StartClip <= tt) {
list.RemoveAt(0);
var index = BinarySearch(actlist, ev.StartClip, ev.Definition.stack);
if (index < 0) index = ~index;
actlist.Insert(index, ev);
}
}
void UpdateScore(Dictionary<ScoreOperation, PdtExpression> scoreops) {
foreach (var scoreop in scoreops) {
var key = scoreop.Key;
_etor.ContextSelfValue = scoreSrcs[key.name.Key];
_etor.Evaluate(scoreOps[key.name.Key], scoreop.Value);
InvalidateScore(key.name.Key);
foreach (var s in _rs.scores) {
if (s.Value.value != null) {
_etor.ContextSelfValue = scoreSrcs[s.Key.Key];
_etor.Evaluate(scoreOps[s.Key.Key], s.Value.value);
InvalidateScore(s.Key.Key);
}
}
}
}
readonly Dictionary<int, int> scoreStringKeys = new Dictionary<int, int>();
readonly Dictionary<int, int> scoreStringKeysRev = new Dictionary<int, int>();
readonly Dictionary<int, PropSrc> scoreSrcs = new Dictionary<int, PropSrc>();
readonly Dictionary<int, PropOp> scoreOps = new Dictionary<int, PropOp>();
readonly Dictionary<int, ScoreDefinition> scoreDefs = new Dictionary<int, ScoreDefinition>();
readonly Dictionary<int, float> scores = new Dictionary<int, float>();
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>();
void InitScores() {
foreach (var s in _rs.scores) {
var key = s.Key.Key;
var strkey = IdentifierManager.SharedInstance.Request("_score_" + (string)s.Key.Name);
scoreStringKeys.Add(key, strkey);
scoreStringKeysRev.Add(strkey, key);
scoreSrcs.Add(key, new PropSrc.Float(() => scores[key]));
scoreOps.Add(key, new PropOp.Float(v => scores[key] = v));
scoreDefs.Add(key, s.Value);
scores.Add(key, s.Value.init);
scoreStringCache.Add(scoreStringKeys[key], null);
scoreStringSrcs.Add(scoreStringKeys[key], new ScoreStringSrc(scoreStringPool, () => GetScoreString(strkey)));
}
}
void InvalidateScore(int key) {
scoreSrcs[key].Invalidate();
scoreStringCache[scoreStringKeys[key]] = null;
scoreStringSrcs[scoreStringKeys[key]].Invalidate();
}
string GetScoreString(int key) {
var result = scoreStringCache[key];
if (result == null) {
var rkey = scoreStringKeysRev[key];
return scoreStringCache[key] = scores[rkey].ToString(scoreDefs[rkey].format, CultureInfo.InvariantCulture);
}
else return result;
}
public bool TryGetScoreSrc(int key, out PropSrc value) {
return scoreSrcs.TryGetValue(key, out value);
}
public bool TryGetScoreStringSrc(int key, out PropSrc value) {
return scoreStringSrcs.TryGetValue(key, out value);
} }
public string GetFullFormattedScoreString() { public string GetFullFormattedScoreString() {
bool flag = false; bool flag = false;
string result = ""; string result = "";
foreach (var s in GetFormattedScoreStrings()) { foreach (var s in scores.Keys) {
result += string.Format(flag ? "\n{0}: {1}" : "{0}: {1}", s.Key, s.Value); result += string.Format(flag ? "\n{0}: {1}" : "{0}: {1}", IdentifierManager.SharedInstance.Retrieve(s), GetScoreString(scoreStringKeys[s]));
flag = true; flag = true;
} }
return result; return result;
} }
class ScoreStringSrc : PropSrc {
readonly Func<string> _cb;
readonly ArrayPool<byte> _pool;
byte[] _buf;
public ScoreStringSrc(ArrayPool<byte> pool, Func<string> cb) {
_pool = pool;
_cb = cb;
}
public override void Invalidate() {
base.Invalidate();
if (_buf != null) {
_pool.Return(_buf);
_buf = null;
}
}
protected override unsafe void InternalGet(out int type, out byte[] value) {
var src = _cb();
int strlen = src.Length;
type = PdtInternalType.String;
value = _pool.Rent(sizeof(int) + strlen * sizeof(char));
fixed (byte* _ptr = value) {
char* ptr = (char*)(_ptr + sizeof(int));
*(int*)_ptr = strlen;
int i = 0;
foreach (var c in src) ptr[i++] = c;
}
}
}
} }
public class InputDefinition { public class InputDefinition {
public int dim; public int dim;
public bool notnull; public bool notnull;
public Dictionary<string, PdtExpression> pass; public Dictionary<Identifier, PdtExpression> pass;
} }
public class JudgeDefinition { public class JudgeDefinition {
public PdtExpression clip; public float[] clip;
public PdtExpression input;
public PdtExpression hit; public PdtExpression hit;
public string[] pass; public Identifier[] pass;
public string miss; public Identifier[] miss;
public Dictionary<string, PdtExpression> scores; public Dictionary<ScoreOperation, PdtExpression> scores;
public int stack;
public int prop = 1;
} }
public class ScoreOperation { public class ScoreOperation {
public string name; public Identifier name;
public PdtOperator op; public Identifier op;
public override string ToString() {
if (op == default(Identifier)) return name.ToString();
else return string.Format("{0} {1}", name, op);
}
} }
public class ScoreDefinition { public class ScoreDefinition {
public PdtExpression value; public PdtExpression value;

View File

@@ -6,25 +6,33 @@ namespace Cryville.Crtr {
public class Menu : MonoBehaviour { public class Menu : MonoBehaviour {
#pragma warning disable IDE0044 #pragma warning disable IDE0044
[SerializeField] [SerializeField]
private ResourceBrowserMaster m_browserMaster; ResourceBrowserMaster m_browserMaster;
[SerializeField] [SerializeField]
private Animator m_targetAnimator; Animator m_targetAnimator;
[SerializeField] [SerializeField]
private ProgressBar m_progressBar; ProgressBar m_progressBar;
[SerializeField]
SettingsPanel m_settingsPanel;
#pragma warning restore IDE0044 #pragma warning restore IDE0044
int frameIndex = 2;
bool initialized = false; bool initialized = false;
int totalTasks = 0; int totalTasks = 0;
#pragma warning disable IDE0051 #pragma warning disable IDE0051
void Awake() { void Awake() {
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;
} }
void Update() { void Update() {
if (!initialized) { if (!initialized) {
int taskCount = Game.NetworkTaskWorker.TaskCount; int taskCount = Game.NetworkTaskWorker.TaskCount;
if (totalTasks < taskCount) totalTasks = taskCount; if (totalTasks < taskCount) totalTasks = taskCount;
m_progressBar.value = 1 - (float)taskCount / totalTasks; if (frameIndex > 0) {
frameIndex--;
return;
}
m_progressBar.value = totalTasks == 0 ? 1 : (1 - (float)taskCount / totalTasks);
if (taskCount == 0) { if (taskCount == 0) {
initialized = true; initialized = true;
m_targetAnimator.SetTrigger("T_Main"); m_targetAnimator.SetTrigger("T_Main");

View File

@@ -22,23 +22,16 @@ namespace Cryville.Crtr {
get; get;
private set; private set;
} }
public bool Transparent {
get;
private set;
}
public bool Initialized { public bool Initialized {
get; get;
private set; private set;
} }
public Material NewMaterial { public Material NewMaterial {
get { get {
return Material.Instantiate(GenericResources.Materials[ return Material.Instantiate(GenericResources.Materials["-SpriteMat"]);
Transparent ? "-TransparentMat" : "-CutoutMat"
]);
} }
} }
public void Init(Transform parent, bool transparent = false) { public void Init(Transform parent) {
Transparent = transparent;
MeshObject = new GameObject("__mesh__"); MeshObject = new GameObject("__mesh__");
MeshTransform = MeshObject.transform; MeshTransform = MeshObject.transform;
MeshTransform.SetParent(parent, false); MeshTransform.SetParent(parent, false);
@@ -48,9 +41,7 @@ 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 = GenericResources.Materials[ Renderer.material = GenericResources.Materials["-SpriteMat"];
transparent ? "-TransparentMat" : "-CutoutMat"
]; // TODO
Initialized = true; Initialized = true;
} }
public void Destroy() { public void Destroy() {

View File

@@ -139,41 +139,6 @@ namespace Cryville.Crtr {
} }
} }
public struct MotionName : IEquatable<MotionName> {
public string MainName { get; private set; }
public string SubName { get; private set; }
public string FullName { get; private set; }
readonly int hash;
public MotionName(string mainName, string subName) {
MainName = mainName;
SubName = subName;
FullName = subName == null ? mainName : string.Format("{0}!{1}", mainName, subName);
hash = FullName.GetHashCode();
}
public MotionName(string fullName) {
var names = fullName.Split('!');
if (names.Length > 2) throw new ArgumentException("Invalid name");
FullName = fullName;
hash = FullName.GetHashCode();
MainName = names[0];
SubName = names.Length == 1 ? "" : names[1];
}
public override bool Equals(object obj) {
if (!(obj is MotionName)) return false;
return Equals((MotionName)obj);
}
public bool Equals(MotionName other) {
return hash == other.hash;
}
public override int GetHashCode() {
return hash;
}
public override string ToString() {
return FullName;
}
}
public struct MotionRegistry { public struct MotionRegistry {
readonly Type m_Type; readonly Type m_Type;
public Type Type { public Type Type {
@@ -319,21 +284,15 @@ namespace Cryville.Crtr {
} }
// Adopted from System.Collections.Generic.ArraySortHelper<T>.InternalBinarySearch(T[] array, int index, int length, T value, IComparer<T> comparer) // Adopted from System.Collections.Generic.ArraySortHelper<T>.InternalBinarySearch(T[] array, int index, int length, T value, IComparer<T> comparer)
internal int BinarySearch(float value) { int BinarySearch(float value) {
int num = 0; int num = 0;
int num2 = RelativeNodes.Count - 1; int num2 = RelativeNodes.Count - 1;
while (num <= num2) { while (num <= num2) {
int num3 = num + (num2 - num >> 1); int num3 = num + (num2 - num >> 1);
int num4 = RelativeNodes[num3].Time.Value.CompareTo(value); int num4 = RelativeNodes[num3].Time.Value.CompareTo(value);
if (num4 == 0) { if (num4 == 0) return num3;
return num3; if (num4 < 0) num = num3 + 1;
} else num2 = num3 - 1;
if (num4 < 0) {
num = num3 + 1;
}
else {
num2 = num3 - 1;
}
} }
return ~num; return ~num;
} }
@@ -408,11 +367,11 @@ namespace Cryville.Crtr {
static readonly Type[] stringTypeArray = new Type[] { typeof(string) }; static readonly Type[] stringTypeArray = new Type[] { typeof(string) };
static readonly Type[] floatArrayTypeArray = new Type[] { typeof(float[]) }; static readonly Type[] floatArrayTypeArray = new Type[] { typeof(float[]) };
public static Vector Construct(Type type, string s) { public static Vector Construct(Type type, string s) {
if (!typeof(Vector).IsAssignableFrom(type)) throw new ArgumentException(); // TODO if (!typeof(Vector).IsAssignableFrom(type)) throw new ArgumentException("Type is not vector");
return (Vector)type.GetConstructor(stringTypeArray).Invoke(new object[] { s }); return (Vector)type.GetConstructor(stringTypeArray).Invoke(new object[] { s });
} }
public static Vector Construct(Type type, float[] values) { public static Vector Construct(Type type, float[] values) {
if (!typeof(Vector).IsAssignableFrom(type)) throw new ArgumentException(); // TODO if (!typeof(Vector).IsAssignableFrom(type)) throw new ArgumentException("Type is not vector");
return (Vector)type.GetConstructor(floatArrayTypeArray).Invoke(new object[] { values }); return (Vector)type.GetConstructor(floatArrayTypeArray).Invoke(new object[] { values });
} }
} }

View File

@@ -1,3 +1,4 @@
using Cryville.Common;
using Cryville.Common.Math; using Cryville.Common.Math;
using Cryville.Crtr.Components; using Cryville.Crtr.Components;
using Cryville.Crtr.Event; using Cryville.Crtr.Event;
@@ -9,10 +10,11 @@ namespace Cryville.Crtr {
class NoteHandler : ContainerHandler { class NoteHandler : ContainerHandler {
readonly GroupHandler gh; readonly GroupHandler gh;
public readonly Chart.Note Event; public readonly Chart.Note Event;
readonly Judge judge; readonly PdtRuleset ruleset;
public NoteHandler(GroupHandler gh, Chart.Note ev, Judge j) : base() { public NoteHandler(GroupHandler gh, Chart.Note ev, PdtRuleset rs, Judge j) : base() {
this.gh = gh; this.gh = gh;
Event = ev; Event = ev;
ruleset = rs;
judge = j; judge = j;
} }
@@ -59,18 +61,6 @@ namespace Cryville.Crtr {
} }
} }
readonly Dictionary<Chart.Motion, Vec1> phMotions = new Dictionary<Chart.Motion, Vec1>();
bool invalidated = false;
readonly List<StampedEvent.Judge> patchedJudgeEvents = new List<StampedEvent.Judge>();
public override void StartUpdate(ContainerState s) {
base.StartUpdate(s);
/*if (s.CloneType == 16 && Event.judge != null) {
// var etor = new Evaluator();
//CompiledRuleset.PatchJudge(Event, ChartPlayer.cruleset.primary_judges[Event.judge], s.Time, etor, patchedJudgeEvents, !Event.@long);
}*/
}
public override void Update(ContainerState s, StampedEvent ev) { public override void Update(ContainerState s, StampedEvent ev) {
base.Update(s, ev); base.Update(s, ev);
if (s.CloneType == 1) { if (s.CloneType == 1) {
@@ -90,73 +80,16 @@ namespace Cryville.Crtr {
else if (s.CloneType == 16) { else if (s.CloneType == 16) {
if (ev == null) { } if (ev == null) { }
else if (ev.Unstamped == null) { } else if (ev.Unstamped == null) { }
else if (ev.Unstamped is Chart.Motion) { else if (ev.Unstamped is Chart.Judge) {
var tev = (Chart.Motion)ev.Unstamped; var tev = (Chart.Judge)ev.Unstamped;
if (tev.Name.MainName != "judge") return; Identifier name = default(Identifier);
phMotions.Add(tev, (Vec1)s.GetRawValue<Vec1>(tev.Name).Clone()); ChartPlayer.etor.ContextEvent = tev;
ChartPlayer.etor.ContextState = s;
ChartPlayer.etor.Evaluate(new PropOp.Identifier(v => name = new Identifier(v)), ruleset.judges[tev.Id].input);
judge.Prepare(ev.Time, ev.Time + ev.Duration, name, ruleset.judges[tev.Id], cs);
ChartPlayer.etor.ContextState = null;
ChartPlayer.etor.ContextEvent = null;
} }
else if (ev.Unstamped is InstantEvent) {
var oev = ((InstantEvent)ev.Unstamped).Original;
if (oev is Chart.Motion) {
var tev = (Chart.Motion)oev;
if (tev.Name.MainName != "judge") return;
var v0 = phMotions[tev];
var v1 = s.GetRawValue<Vec1>(tev.Name);
// var etor = new Evaluator();
for (var vi = Mathf.Ceil(v0.Value); vi < v1.Value; vi++) {
var v = new Vec1(vi);
var t = MotionLerper.Delerp(v, ev.Time, v1, ev.Origin.Time, v0, tev.transition, tev.rate);
/*CompiledRuleset.PatchJudge(
Event, ChartPlayer.cruleset.primary_judges[tev.Name.SubName],
t, etor, patchedJudgeEvents
);*/
}
phMotions.Remove(tev);
}
}
}
}
public override void ExUpdate(ContainerState s, StampedEvent ev) {
base.ExUpdate(s, ev);
if (ev is StampedEvent.Judge) {
var tev = (StampedEvent.Judge)ev;
if (tev.TargetJudge != null && s.CloneType == 0 && !invalidated) {
//judge.Issue(tev, this);
}
else if (tev.TargetJudge == null && s.CloneType == 17) {
//judge.RecordPos(tev.StartEvent, GetFramePoint(s.Parent, s.Track));
}
else
return;
patchedJudgeEvents.Remove(tev);
// Logger.Log("main", 0, "Judge", "ir {0}", patchedJudgeEvents.Count);
}
}
public override void MotionUpdate(byte ct, Chart.Motion ev) {
base.MotionUpdate(ct, ev);
if (ct == 0) {
if (ev.Name.MainName == "judge") {
if (invalidated) return;
if (ev.Name.SubName == null)
throw new InvalidOperationException();
// judge.IssueImmediate(this, ev.Name.SubName, GetFramePoint(cs.Parent, cs.Track));
}
}
else if (ct == 16) {
/*var etor = new EvalImpl();
if (ev.MotionName == "judge") {
if (ev.MotionSubName == null)
throw new InvalidOperationException();
var l = new List<StampedEvent>();
float t = ps.Time;
CompiledRuleset.PatchJudge(
Event, ChartPlayer.cruleset.primary_judges[ev.MotionSubName],
t, etor, ref l
);
cs.Bus.IssueEventPatch(l);
}*/
} }
} }
@@ -170,13 +103,6 @@ namespace Cryville.Crtr {
a_tail.rotation = Quaternion.Euler(ts.Direction); a_tail.rotation = Quaternion.Euler(ts.Direction);
#endif #endif
} }
else if (s.CloneType == 16) {
/*if (Event.endjudge != null) {
//var etor = new Evaluator();
//CompiledRuleset.PatchJudge(Event, ChartPlayer.cruleset.primary_judges[Event.endjudge], ps.Time, etor, patchedJudgeEvents, true);
}
cs.Bus.IssuePatch(patchedJudgeEvents.Cast<StampedEvent>());*/
}
OpenAnchor("tail"); OpenAnchor("tail");
base.EndUpdate(s); base.EndUpdate(s);
CloseAnchor("tail"); CloseAnchor("tail");
@@ -235,10 +161,5 @@ namespace Cryville.Crtr {
} }
} }
} }
public List<StampedEvent.Judge> Invalidate() {
invalidated = true;
return patchedJudgeEvents;
}
} }
} }

View File

@@ -1,150 +1,162 @@
using Cryville.Common.Pdt; using Cryville.Common;
using Cryville.Common.Pdt;
using Cryville.Crtr.Event;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
namespace Cryville.Crtr { namespace Cryville.Crtr {
public class PdtEvaluator : PdtEvaluatorBase { public class PdtEvaluator : PdtEvaluatorBase {
static readonly Dictionary<OperatorSignature, PdtOperator> _shortops = new Dictionary<OperatorSignature, PdtOperator>(); static readonly Dictionary<PdtOperatorSignature, PdtOperator> _shortops = new Dictionary<PdtOperatorSignature, PdtOperator>();
static readonly Dictionary<string, PdtOperator> _longops = new Dictionary<string, PdtOperator>(); readonly Dictionary<int, PdtOperator> _ctxops = new Dictionary<int, PdtOperator>();
readonly Dictionary<string, PdtOperator> _ctxops = new Dictionary<string, PdtOperator>();
struct OperatorSignature : IEquatable<OperatorSignature> {
public string Name { get; private set; }
public int ParamCount { get; private set; }
readonly int _hash;
public OperatorSignature(string name, int paramCount) {
Name = name;
ParamCount = paramCount;
_hash = name.GetHashCode() ^ paramCount;
}
public override bool Equals(object obj) {
if (!(obj is OperatorSignature)) return false;
return Equals((OperatorSignature)obj);
}
public bool Equals(OperatorSignature other) {
return Name == other.Name && ParamCount == other.ParamCount;
}
public override int GetHashCode() {
return _hash;
}
}
readonly byte[] _numbuf = new byte[4]; readonly byte[] _numbuf = new byte[4];
protected override void GetVariable(string name, out int type, out byte[] value) { static readonly int _var_w = IdentifierManager.SharedInstance.Request("w");
switch (name) { static readonly int _var_h = IdentifierManager.SharedInstance.Request("h");
case "w": LoadNum(ChartPlayer.hitRect.width); type = PdtInternalType.Number; value = _numbuf; return; static readonly int _var_true = IdentifierManager.SharedInstance.Request("true");
case "h": LoadNum(ChartPlayer.hitRect.height); type = PdtInternalType.Number; value = _numbuf; return; static readonly int _var_false = IdentifierManager.SharedInstance.Request("false");
case "true": LoadNum(1); type = PdtInternalType.Number; value = _numbuf; return; protected override void GetVariable(int name, out int type, out byte[] value) {
case "false": LoadNum(0); type = PdtInternalType.Number; value = _numbuf; return; if (name == _var_w) { LoadNum(ChartPlayer.hitRect.width); type = PdtInternalType.Number; value = _numbuf; }
default: else if (name == _var_h) { LoadNum(ChartPlayer.hitRect.height); type = PdtInternalType.Number; value = _numbuf; }
PropSrc prop; else if (name == _var_true) { LoadNum(1); type = PdtInternalType.Number; value = _numbuf; }
string str; else if (name == _var_false) { LoadNum(0); type = PdtInternalType.Number; value = _numbuf; }
if (ContextEvent != null && ContextEvent.PropSrcs.TryGetValue(name, out prop)) { else {
prop.Get(out type, out value); var id = new Identifier(name);
} PropSrc prop;
else if (ContextJudge != null && ContextJudge.GetFormattedScoreStrings().TryGetValue(name, out str)) { if (ContextEvent != null && ContextEvent.PropSrcs.TryGetValue(name, out prop)) {
type = PdtInternalType.String; prop.Get(out type, out value);
value = GetBytes(str); }
RevokePotentialConstant(); else if (ContextState != null && ChartPlayer.motionRegistry.ContainsKey(id)) {
var vec = ContextState.GetRawValue(id);
new VectorSrc(() => vec).Get(out type, out value);
}
else if (ContextJudge != null && ContextJudge.TryGetScoreSrc(name, out prop)) {
prop.Get(out type, out value);
RevokePotentialConstant();
}
else if (ContextJudge != null && ContextJudge.TryGetScoreStringSrc(name, out prop)) {
prop.Get(out type, out value);
RevokePotentialConstant();
}
else {
PropSrc.Arbitrary result = ContextCascadeLookup(name);
if (result != null) {
result.Get(out type, out value);
} }
else { else {
PropSrc.Arbitrary result;
foreach (var cas in ContextCascade) {
if (cas.TryGetValue(name, out result)) {
result.Get(out type, out value);
return;
}
}
type = PdtInternalType.Undefined; type = PdtInternalType.Undefined;
value = GetBytes(name); LoadNum(name);
value = _numbuf;
} }
return; }
} }
} }
unsafe void LoadNum(int value) {
fixed (byte* ptr = _numbuf) *(int*)ptr = value;
}
unsafe void LoadNum(float value) { unsafe void LoadNum(float value) {
fixed (byte* ptr = _numbuf) *(float*)ptr = value; fixed (byte* ptr = _numbuf) *(float*)ptr = value;
} }
unsafe byte[] GetBytes(string value) { static readonly int _op_sep = IdentifierManager.SharedInstance.Request(",");
int strlen = value.Length; static readonly int _func_int_map = IdentifierManager.SharedInstance.Request("int_map");
byte[] result = new byte[strlen * sizeof(char) + sizeof(int)]; protected override PdtOperator GetOperator(PdtOperatorSignature sig) {
fixed (byte* _ptr = result) {
char* ptr = (char*)(_ptr + sizeof(int));
*(int*)_ptr = strlen;
int i = 0;
foreach (var c in value) ptr[i++] = c;
}
return result;
}
protected override PdtOperator GetOperator(string name, int pc) {
PdtOperator result; PdtOperator result;
if (name.Length == 1 && _shortops.TryGetValue(new OperatorSignature(name, pc), out result)) { if (_shortops.TryGetValue(sig, out result)) {
return result; return result;
} }
else if (name == ",") { else if (sig.Name == _op_sep) {
result = new op_arr(pc); result = new op_arr(sig.ParamCount);
_shortops.Add(new OperatorSignature(",", pc), result); _shortops.Add(new PdtOperatorSignature(_op_sep, sig.ParamCount), result);
return result; return result;
} }
else if (_longops.TryGetValue(name, out result)) { else if (sig.Name == _func_int_map) {
result = new func_int_map(sig.ParamCount);
_shortops.Add(new PdtOperatorSignature(_func_int_map, sig.ParamCount), result);
return result; return result;
} }
else if (_ctxops.TryGetValue(name, out result)) { else if (_ctxops.TryGetValue(sig.Name, out result)) {
return result; return result;
} }
else throw new KeyNotFoundException(string.Format("Undefined operator {0}({1})", name, pc)); else throw new KeyNotFoundException(string.Format("Undefined operator {0}", sig));
} }
protected override bool Collapse(string name, PdtVariableMemory param) { static readonly int _colop_and = IdentifierManager.SharedInstance.Request("&");
switch (name) { static readonly int _colop_or = IdentifierManager.SharedInstance.Request("|");
case "&": return param.AsNumber() == 0; protected override bool Collapse(int name, PdtVariableMemory param) {
case "|": return param.AsNumber() != 0; if (name == _colop_and) return param.Type == PdtInternalType.Number && param.AsNumber() <= 0;
default: throw new KeyNotFoundException(string.Format("Undefined collapse operator {0}", name)); else if (name == _colop_or) return param.Type != PdtInternalType.Number || param.AsNumber() > 0;
} else throw new KeyNotFoundException(string.Format("Undefined collapse operator {0}", name));
} }
public ChartEvent ContextEvent { private get; set; } public ChartEvent ContextEvent { private get; set; }
public ContainerState ContextState { private get; set; }
public Transform ContextTransform { private get; set; } public Transform ContextTransform { private get; set; }
public Judge ContextJudge { private get; set; } public Judge ContextJudge { private get; set; }
public PropSrc ContextSelfValue { private get; set; } public PropSrc ContextSelfValue { private get; set; }
readonly List<Dictionary<string, PropSrc.Arbitrary>> ContextCascade = new List<Dictionary<string, PropSrc.Arbitrary>>(); readonly Dictionary<int, PropSrc.Arbitrary>[] ContextCascade = new Dictionary<int, PropSrc.Arbitrary>[256];
int _cascadeHeight;
public void ContextCascadeInsert() { public void ContextCascadeInsert() {
ContextCascade.Add(new Dictionary<string, PropSrc.Arbitrary>()); ContextCascade[_cascadeHeight++].Clear();
} }
public void ContextCascadeUpdate(string key, PropSrc.Arbitrary value) { public void ContextCascadeUpdate(int key, PropSrc.Arbitrary value) {
ContextCascade[ContextCascade.Count - 1][key] = value; ContextCascade[_cascadeHeight - 1][key] = value;
}
public PropSrc.Arbitrary ContextCascadeLookup(int name) {
PropSrc.Arbitrary result;
for (int i = _cascadeHeight - 1; i >= 0; i--) {
Dictionary<int, PropSrc.Arbitrary> cas = ContextCascade[i];
if (cas.TryGetValue(name, out result)) {
return result;
}
}
return null;
} }
public void ContextCascadeDiscard() { public void ContextCascadeDiscard() {
ContextCascade.RemoveAt(ContextCascade.Count - 1); --_cascadeHeight;
} }
public PdtEvaluator() { public PdtEvaluator() {
_ctxops.Add("screen_edge", new func_screen_edge(() => ContextTransform)); for (int i = 0; i < ContextCascade.Length; i++) ContextCascade[i] = new Dictionary<int, PropSrc.Arbitrary>();
_ctxops.Add("int", new func_int(() => ContextSelfValue));
_ctxops.Add("clamp", new func_clamp(() => ContextSelfValue)); _ctxops.Add(IdentifierManager.SharedInstance.Request("screen_edge"), new func_screen_edge(() => ContextTransform));
_ctxops.Add("min", new func_min(() => ContextSelfValue)); _ctxops.Add(IdentifierManager.SharedInstance.Request("int"), new func_int(() => ContextSelfValue));
_ctxops.Add("max", new func_max(() => ContextSelfValue)); _ctxops.Add(IdentifierManager.SharedInstance.Request("clamp"), new func_clamp(() => ContextSelfValue));
_ctxops.Add(IdentifierManager.SharedInstance.Request("min"), new func_min(() => ContextSelfValue));
_ctxops.Add(IdentifierManager.SharedInstance.Request("max"), new func_max(() => ContextSelfValue));
_ctxops.Add(IdentifierManager.SharedInstance.Request("abs"), new func_abs(() => ContextSelfValue));
Func<int, PropSrc> cccb = k => ContextCascadeLookup(k);
_ctxops.Add(IdentifierManager.SharedInstance.Request("attack_timing"), new func_attack_timing(cccb));
_ctxops.Add(IdentifierManager.SharedInstance.Request("enter_timing"), new func_enter_timing(cccb));
_ctxops.Add(IdentifierManager.SharedInstance.Request("release_timing"), new func_release_timing(cccb));
_ctxops.Add(IdentifierManager.SharedInstance.Request("leave_timing"), new func_leave_timing(cccb));
_ctxops.Add(IdentifierManager.SharedInstance.Request("contact_timing"), new func_contact_timing(cccb));
} }
static PdtEvaluator() { static PdtEvaluator() {
_shortops.Add(new OperatorSignature("*", 2), new op_mul_2()); _shortops.Add(new PdtOperatorSignature("@", 2), new op_at_2());
_shortops.Add(new OperatorSignature("/", 2), new op_div_2());
_shortops.Add(new OperatorSignature("%", 2), new op_mod_2());
_shortops.Add(new OperatorSignature("+", 1), new op_add_1()); _shortops.Add(new PdtOperatorSignature("*", 2), new op_mul_2());
_shortops.Add(new OperatorSignature("+", 2), new op_add_2()); _shortops.Add(new PdtOperatorSignature("/", 2), new op_div_2());
_shortops.Add(new OperatorSignature("-", 1), new op_sub_1()); _shortops.Add(new PdtOperatorSignature("%", 2), new op_mod_2());
_shortops.Add(new OperatorSignature("-", 2), new op_sub_2());
_shortops.Add(new OperatorSignature("=", 2), new op_eq_2()); _shortops.Add(new PdtOperatorSignature("+", 1), new op_add_1());
_shortops.Add(new OperatorSignature("<", 2), new op_lt_2()); _shortops.Add(new PdtOperatorSignature("+", 2), new op_add_2());
_shortops.Add(new OperatorSignature(">", 2), new op_gt_2()); _shortops.Add(new PdtOperatorSignature("-", 1), new op_sub_1());
_shortops.Add(new PdtOperatorSignature("-", 2), new op_sub_2());
_shortops.Add(new OperatorSignature("!", 1), new op_not_1()); _shortops.Add(new PdtOperatorSignature("=", 2), new op_eq_2());
_shortops.Add(new PdtOperatorSignature("<", 2), new op_lt_2());
_shortops.Add(new PdtOperatorSignature(">", 2), new op_gt_2());
_longops.Add("frame_seq", new func_frame_seq()); _shortops.Add(new PdtOperatorSignature("!", 1), new op_not_1());
_shortops.Add(new PdtOperatorSignature("frame_seq", 3), new func_frame_seq());
_shortops.Add(new PdtOperatorSignature("in_area", 1), new func_in_area());
} }
#region Operators #region Operators
#pragma warning disable IDE1006 #pragma warning disable IDE1006
#region Basic Operators
class op_add_1 : PdtOperator { class op_add_1 : PdtOperator {
public op_add_1() : base(1) { } public op_add_1() : base(1) { }
protected override void Execute() { protected override void Execute() {
@@ -218,7 +230,7 @@ namespace Cryville.Crtr {
class op_not_1 : PdtOperator { class op_not_1 : PdtOperator {
public op_not_1() : base(1) { } public op_not_1() : base(1) { }
protected override void Execute() { protected override void Execute() {
float result = GetOperand(0).AsNumber() == 0 ? 1 : 0; float result = GetOperand(0).AsNumber() <= 0 ? 1 : 0;
GetReturnFrame(PdtInternalType.Number, sizeof(float)).SetNumber(result); GetReturnFrame(PdtInternalType.Number, sizeof(float)).SetNumber(result);
} }
} }
@@ -229,19 +241,39 @@ namespace Cryville.Crtr {
int type = o0.Type; int type = o0.Type;
int len = o0.Length; int len = o0.Length;
bool blit = !IsBlittable(type); bool blit = !IsBlittable(type);
for (var i = 1; i < ParamCount; i++) { for (var i = 1; i < LoadedOperandCount; i++) {
var o = GetOperand(i); var o = GetOperand(i);
if (o.Type != type) throw new InvalidOperationException("Cannot create variant type array"); if (o.Type != type) throw new InvalidOperationException("Cannot create variant type array");
else if (!IsBlittable(o.Type)) blit = true; else if (!IsBlittable(o.Type)) blit = true;
len += o.Length; len += o.Length;
} }
if (blit) GetReturnFrame(PdtInternalType.Array, len + 2 * sizeof(int)).SetArraySuffix(type, ParamCount); if (blit) GetReturnFrame(PdtInternalType.Array, len + 2 * sizeof(int)).SetArraySuffix(type, LoadedOperandCount);
else GetReturnFrame(PdtInternalType.Vector, len + sizeof(int)).SetArraySuffix(type); else GetReturnFrame(PdtInternalType.Vector, len + sizeof(int)).SetArraySuffix(type);
} }
bool IsBlittable(int type) { bool IsBlittable(int type) {
return type == PdtInternalType.Number; return type == PdtInternalType.Number;
} }
} }
class op_at_2 : PdtOperator {
public op_at_2() : base(2) { }
protected override void Execute() {
int _;
var op0 = GetOperand(0);
var op1 = (int)Math.Round(GetOperand(1).AsNumber());
if (op0.Type == PdtInternalType.Vector) {
op0.GetArraySuffix(out _, out _);
if (op1 >= (op0.Length - sizeof(int)) / sizeof(float)) throw new IndexOutOfRangeException();
GetReturnFrame(PdtInternalType.Number, sizeof(float)).SetNumber(op0.AsNumber(op1 * sizeof(float)));
}
else if (op0.Type == PdtInternalType.Number) {
if (op1 != 0) throw new IndexOutOfRangeException();
GetReturnFrame(PdtInternalType.Number, sizeof(float)).SetNumber(op0.AsNumber());
}
else throw new InvalidOperationException("Not a vector or number");
}
}
#endregion
#region Basic Functions
class func_frame_seq : PdtOperator { class func_frame_seq : PdtOperator {
public func_frame_seq() : base(3) { } public func_frame_seq() : base(3) { }
protected override unsafe void Execute() { protected override unsafe void Execute() {
@@ -272,6 +304,39 @@ namespace Cryville.Crtr {
} }
} }
} }
class func_in_area : PdtOperator {
public func_in_area() : base(1) { }
protected override unsafe void Execute() {
var arg = GetOperand(0);
if (arg.Type == PdtInternalType.Error) {
throw new InvalidOperationException("Error");
}
else if (arg.Type == PdtInternalType.Number && arg.AsNumber() <= 0) {
GetReturnFrame(PdtInternalType.Null, 0);
}
else {
var ret = GetReturnFrame(arg.Type, arg.Length);
arg.CopyTo(ret);
}
}
}
class func_int_map : PdtOperator {
public func_int_map(int pc) : base(pc) {
if (pc < 4) throw new ArgumentOutOfRangeException("Too few parameters for int_map");
}
protected override unsafe void Execute() {
var value = GetOperand(0).AsNumber();
var offset = GetOperand(1).AsNumber();
var step = GetOperand(2).AsNumber();
var index = (int)((value - offset) / step);
if (index < 0 || index >= LoadedOperandCount - 3) index = 0;
var hit = GetOperand(index + 3);
var ret = GetReturnFrame(hit.Type, hit.Length);
hit.CopyTo(ret);
}
}
#endregion
#region Contextual Functions
class func_screen_edge : PdtOperator { class func_screen_edge : PdtOperator {
readonly Func<Transform> _ctxcb; readonly Func<Transform> _ctxcb;
public func_screen_edge(Func<Transform> ctxcb) : base(1) { public func_screen_edge(Func<Transform> ctxcb) : base(1) {
@@ -361,10 +426,93 @@ namespace Cryville.Crtr {
ret.SetNumber(Mathf.Max(a, b)); ret.SetNumber(Mathf.Max(a, b));
} }
} }
class func_abs : PdtOperator {
readonly Func<PropSrc> _ctxcb;
public func_abs(Func<PropSrc> ctxcb) : base(1) {
_ctxcb = ctxcb;
}
protected override unsafe void Execute() {
var ret = GetReturnFrame(PdtInternalType.Number, sizeof(float));
float arg;
switch (LoadedOperandCount) {
case 0: arg = oputil.AsNumber(_ctxcb()); break;
case 1: arg = GetOperand(0).AsNumber(); break;
default: throw new ArgumentException("Argument count not 0 or 1");
}
ret.SetNumber(Mathf.Abs(arg));
}
}
#endregion
#region Judge Functions
static readonly int _var_fn = IdentifierManager.SharedInstance.Request("fn");
static readonly int _var_tn = IdentifierManager.SharedInstance.Request("tn");
static readonly int _var_ft = IdentifierManager.SharedInstance.Request("ft");
static readonly int _var_tt = IdentifierManager.SharedInstance.Request("tt");
static readonly int _var_fv = IdentifierManager.SharedInstance.Request("fv");
static readonly int _var_tv = IdentifierManager.SharedInstance.Request("tv");
abstract class JudgeFunction : PdtOperator {
readonly Func<int, PropSrc> _ctxcb;
protected JudgeFunction(int pc, Func<int, PropSrc> ctxcb) : base(pc) {
_ctxcb = ctxcb;
}
protected sealed override void Execute() {
var ret = GetReturnFrame(PdtInternalType.Number, sizeof(float));
var fn = oputil.AsNumber(_ctxcb(_var_fn));
var tn = oputil.AsNumber(_ctxcb(_var_tn));
var ft = oputil.AsNumber(_ctxcb(_var_ft));
var tt = oputil.AsNumber(_ctxcb(_var_tt));
var fv = oputil.AsVector(_ctxcb(_var_fv));
var tv = oputil.AsVector(_ctxcb(_var_tv));
ret.SetNumber(ExecuteImpl(fn, tn, ft, tt, fv, tv) ? 1 : 0);
}
protected abstract bool ExecuteImpl(float fn, float tn, float ft, float tt, Vector3? fv, Vector3? tv);
}
class func_attack_timing : JudgeFunction {
public func_attack_timing(Func<int, PropSrc> ctxcb) : base(2, ctxcb) { }
protected override bool ExecuteImpl(float fn, float tn, float ft, float tt, Vector3? fv, Vector3? tv) {
if (fv != null) return false;
var t0 = GetOperand(0).AsNumber() + fn;
var t1 = GetOperand(1).AsNumber() + tn;
return tt > t0 && tt <= t1;
}
}
class func_enter_timing : JudgeFunction {
public func_enter_timing(Func<int, PropSrc> ctxcb) : base(1, ctxcb) { }
protected override bool ExecuteImpl(float fn, float tn, float ft, float tt, Vector3? fv, Vector3? tv) {
if (fv == null || tv == null) return false;
var t0 = GetOperand(0).AsNumber() + fn;
return ft < t0 && tt >= t0;
}
}
class func_release_timing : JudgeFunction {
public func_release_timing(Func<int, PropSrc> ctxcb) : base(2, ctxcb) { }
protected override bool ExecuteImpl(float fn, float tn, float ft, float tt, Vector3? fv, Vector3? tv) {
if (tv != null) return false;
var t0 = GetOperand(0).AsNumber() + fn;
var t1 = GetOperand(1).AsNumber() + tn;
return ft > t0 && ft <= t1;
}
}
class func_leave_timing : JudgeFunction {
public func_leave_timing(Func<int, PropSrc> ctxcb) : base(1, ctxcb) { }
protected override bool ExecuteImpl(float fn, float tn, float ft, float tt, Vector3? fv, Vector3? tv) {
if (fv == null || tv == null) return false;
var t1 = GetOperand(0).AsNumber() + tn;
return ft < t1 && tt >= t1;
}
}
class func_contact_timing : JudgeFunction {
public func_contact_timing(Func<int, PropSrc> ctxcb) : base(2, ctxcb) { }
protected override bool ExecuteImpl(float fn, float tn, float ft, float tt, Vector3? fv, Vector3? tv) {
var t0 = GetOperand(0).AsNumber() + fn;
var t1 = GetOperand(1).AsNumber() + tn;
return (fv == null || ft < t1) && (tv == null || tt >= t0);
}
}
#endregion
unsafe static class oputil { unsafe static class oputil {
public static float AsNumber(PropSrc src) { public static float AsNumber(PropSrc src) {
if (src == null) if (src == null) throw new ArgumentNullException("src");
throw new ArgumentNullException("src");
int type; byte[] value; int type; byte[] value;
src.Get(out type, out value); src.Get(out type, out value);
if (type != PdtInternalType.Number) if (type != PdtInternalType.Number)
@@ -373,6 +521,25 @@ namespace Cryville.Crtr {
return *(float*)ptr; return *(float*)ptr;
} }
} }
public static Vector3? AsVector(PropSrc src) {
if (src == null) throw new ArgumentNullException("src");
int type; byte[] value;
src.Get(out type, out value);
if (type == PdtInternalType.Vector) {
fixed (byte* ptr = value) {
return *(Vector3*)ptr;
}
}
else if (type == PdtInternalType.Number) {
fixed (byte* ptr = value) {
return new Vector3(*(float*)ptr, 0, 0);
}
}
else if (type == PdtInternalType.Null) {
return null;
}
else throw new ArgumentException("Not a number");
}
} }
#pragma warning restore IDE1006 #pragma warning restore IDE1006
#endregion #endregion

View File

@@ -0,0 +1,37 @@
using System;
using UnityEngine;
using UnityEngine.UI;
namespace Cryville.Crtr {
public class Popup : MonoBehaviour {
public string Message = "";
CanvasGroup group;
float timer = 0;
const float DURATION = 5.0f;
const float DURIN = 0.4f;
const float DUROUT = 0.4f;
void Start() {
group = GetComponent<CanvasGroup>();
group.alpha = 0;
GetComponentInChildren<Text>().text = Message;
transform.SetParent(GameObject.Find("PopupList").transform);
}
void Update() {
if (timer <= DURIN) group.alpha = timer / DURIN;
else if (timer >= DURATION) GameObject.Destroy(gameObject);
else if (timer >= DURATION - DUROUT) group.alpha = (DURATION - timer) / DUROUT;
timer += Time.deltaTime;
}
public static void CreateException(Exception ex) {
Create(ex.Message);
}
public static void Create(string msg) {
Instantiate(Resources.Load<GameObject>("Common/Popup")).GetComponent<Popup>().Message = msg;
}
}
}

View File

@@ -1,17 +1,28 @@
using Cryville.Common.Pdt; using Cryville.Common;
using Cryville.Common.Pdt;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Reflection; using System.Reflection;
using RBeatTime = Cryville.Crtr.BeatTime; using RBeatTime = Cryville.Crtr.BeatTime;
using RTargetString = Cryville.Common.Buffers.TargetString;
namespace Cryville.Crtr { namespace Cryville.Crtr {
public abstract class PropOp : PdtOperator { public abstract class PropOp : PdtOperator {
internal PropOp() : base(1) { } internal PropOp() : base(1) { }
public class Arbitrary : PropOp {
public int Name { get; set; }
protected override void Execute() {
var op = GetOperand(0);
var value = new byte[op.Length];
op.CopyTo(value, 0);
ChartPlayer.etor.ContextCascadeUpdate(Name, new PropSrc.Arbitrary(op.Type, value));
}
}
public class Boolean : PropOp { public class Boolean : PropOp {
readonly Action<bool> _cb; readonly Action<bool> _cb;
public Boolean(Action<bool> cb) { _cb = cb; } public Boolean(Action<bool> cb) { _cb = cb; }
protected override void Execute() { protected override void Execute() {
_cb(GetOperand(0).AsNumber() != 0); _cb(GetOperand(0).AsNumber() > 0);
} }
} }
public class Integer : PropOp { public class Integer : PropOp {
@@ -35,15 +46,38 @@ namespace Cryville.Crtr {
_cb(GetOperand(0).AsString()); _cb(GetOperand(0).AsString());
} }
} }
public class TargetString : PropOp {
readonly Func<RTargetString> _cb;
public TargetString(Func<RTargetString> cb) { _cb = cb; }
protected override unsafe void Execute() {
var target = _cb();
var op = GetOperand(0);
if (op.Type != PdtInternalType.String) throw new ArgumentException("Not a string");
var ptr = (byte*)op.TrustedAsOfLength(op.Length);
var len = *(int*)ptr;
target.Length = len;
var cptr = (char*)(ptr + sizeof(int));
for (int i = 0; i < len; i++)
target[i] = cptr[i];
target.Validate();
}
}
public class Identifier : PropOp {
readonly Action<int> _cb;
public Identifier(Action<int> cb) { _cb = cb; }
protected override void Execute() {
_cb(GetOperand(0).AsIdentifier());
}
}
public class Enum<T> : PropOp { public class Enum<T> : PropOp {
readonly static Dictionary<string, int> _cache = new Dictionary<string, int>(); readonly static Dictionary<int, int> _cache = new Dictionary<int, int>();
readonly Action<T> _cb; readonly Action<T> _cb;
public Enum(Action<T> cb) { public Enum(Action<T> cb) {
if (!typeof(T).IsEnum) if (!typeof(T).IsEnum)
throw new ArgumentException("Type is not enum"); throw new ArgumentException("Type is not enum");
var names = typeof(T).GetFields(BindingFlags.Public | BindingFlags.Static); var names = typeof(T).GetFields(BindingFlags.Public | BindingFlags.Static);
for (int i = 0; i < names.Length; i++) for (int i = 0; i < names.Length; i++)
_cache[names[i].Name] = Convert.ToInt32(names[i].GetValue(null)); _cache[IdentifierManager.SharedInstance.Request(names[i].Name)] = Convert.ToInt32(names[i].GetValue(null));
_cb = cb; _cb = cb;
} }
protected override void Execute() { protected override void Execute() {

View File

@@ -6,6 +6,7 @@ namespace Cryville.Crtr {
public abstract class PropSrc { public abstract class PropSrc {
int _type; int _type;
byte[] _buf = null; byte[] _buf = null;
public virtual void Invalidate() { _buf = null; }
public void Get(out int type, out byte[] value) { public void Get(out int type, out byte[] value) {
if (_buf == null) InternalGet(out _type, out _buf); if (_buf == null) InternalGet(out _type, out _buf);
type = _type; type = _type;
@@ -13,14 +14,14 @@ namespace Cryville.Crtr {
} }
protected abstract void InternalGet(out int type, out byte[] value); protected abstract void InternalGet(out int type, out byte[] value);
public class Arbitrary : PropSrc { public class Arbitrary : PropSrc {
readonly new int _type; public int Type { get; private set; }
readonly byte[] _value; readonly byte[] _value;
public Arbitrary(int type, byte[] value) { public Arbitrary(int type, byte[] value) {
_type = type; Type = type;
_value = value; _value = value;
} }
protected override void InternalGet(out int type, out byte[] value) { protected override void InternalGet(out int type, out byte[] value) {
type = _type; type = Type;
value = _value; value = _value;
} }
} }
@@ -56,6 +57,14 @@ namespace Cryville.Crtr {
} }
} }
} }
public class Identifier : PropSrc {
readonly Func<int> _cb;
public Identifier(Func<int> cb) { _cb = cb; }
protected override void InternalGet(out int type, out byte[] value) {
type = PdtInternalType.Undefined;
value = BitConverter.GetBytes(_cb());
}
}
public class BeatTime : PropSrc { public class BeatTime : PropSrc {
readonly Func<RBeatTime> _cb; readonly Func<RBeatTime> _cb;
public BeatTime(Func<RBeatTime> cb) { _cb = cb; } public BeatTime(Func<RBeatTime> cb) { _cb = cb; }

View File

@@ -1,28 +1,29 @@
using Cryville.Common; using Cryville.Common;
using Cryville.Common.Pdt; using Cryville.Common.Pdt;
using Cryville.Crtr.Browsing;
using Newtonsoft.Json; using Newtonsoft.Json;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Text; using System.Text;
using System.Text.RegularExpressions;
using SIdentifier = Cryville.Common.Identifier;
namespace Cryville.Crtr { namespace Cryville.Crtr {
public class Ruleset { public class Ruleset : MetaInfo {
public const long CURRENT_FORMAT = 2;
[JsonRequired] [JsonRequired]
public long format; public long format;
[JsonRequired]
public string @base; public string @base;
[JsonRequired]
public string pdt;
[JsonIgnore] [JsonIgnore]
public PdtRuleset Root { get; private set; } public PdtRuleset Root { get; private set; }
public void LoadPdt(DirectoryInfo dir) { public void LoadPdt(DirectoryInfo dir) {
using (StreamReader pdtreader = new StreamReader(dir.FullName + "/" + pdt + ".pdt", Encoding.UTF8)) { using (StreamReader pdtreader = new StreamReader(dir.FullName + "/" + data + ".pdt", Encoding.UTF8)) {
var src = pdtreader.ReadToEnd(); var src = pdtreader.ReadToEnd();
Root = new RulesetInterpreter(src, null).Interpret(); Root = new RulesetInterpreter(src, null).Interpret();
} }
@@ -31,9 +32,9 @@ namespace Cryville.Crtr {
[Binder(typeof(PdtRulesetBinder))] [Binder(typeof(PdtRulesetBinder))]
public class PdtRuleset { public class PdtRuleset {
public Dictionary<string, InputDefinition> inputs; public Dictionary<Identifier, InputDefinition> inputs;
public Dictionary<string, JudgeDefinition> judges; public Dictionary<Identifier, JudgeDefinition> judges;
public Dictionary<string, ScoreDefinition> scores; public Dictionary<Identifier, ScoreDefinition> scores;
public Constraint constraints; public Constraint constraints;
public void Optimize(PdtEvaluatorBase etor) { public void Optimize(PdtEvaluatorBase etor) {
foreach (var i in inputs.Values) { foreach (var i in inputs.Values) {
@@ -42,10 +43,13 @@ namespace Cryville.Crtr {
} }
} }
foreach (var j in judges.Values) { foreach (var j in judges.Values) {
if (j.clip != null) etor.Optimize(j.clip);
if (j.hit != null) etor.Optimize(j.hit); if (j.hit != null) etor.Optimize(j.hit);
if (j.scores != null) foreach (var e in j.scores.Values) { if (j.scores != null) {
etor.Optimize(e); foreach (var s in j.scores) {
if (s.Key.op != default(Identifier))
etor.PatchCompound(s.Key.name.Key, s.Key.op.Key, s.Value);
etor.Optimize(s.Value);
}
} }
} }
foreach (var s in scores.Values) { foreach (var s in scores.Values) {
@@ -58,16 +62,7 @@ namespace Cryville.Crtr {
} }
} }
public class Constraint { public class Constraint {
class ArbitraryOp : PropOp { static readonly PropOp.Arbitrary _arbop = new PropOp.Arbitrary();
public string name;
protected override void Execute() {
var op = GetOperand(0);
var value = new byte[op.Length];
op.CopyTo(value, 0);
ChartPlayer.etor.ContextCascadeUpdate(name, new PropSrc.Arbitrary(op.Type, value));
}
}
static readonly ArbitraryOp _arbop = new ArbitraryOp();
[ElementList] [ElementList]
public Dictionary<RulesetSelectors, Constraint> Elements = new Dictionary<RulesetSelectors, Constraint>(); public Dictionary<RulesetSelectors, Constraint> Elements = new Dictionary<RulesetSelectors, Constraint>();
[PropertyList] [PropertyList]
@@ -96,7 +91,7 @@ namespace Cryville.Crtr {
etor.ContextSelfValue = null; etor.ContextSelfValue = null;
break; break;
case PropertyType.Variable: case PropertyType.Variable:
_arbop.name = name; _arbop.Name = name;
etor.Evaluate(_arbop, prop.Value); etor.Evaluate(_arbop, prop.Value);
break; break;
default: throw new NotSupportedException("Unknown property key type"); default: throw new NotSupportedException("Unknown property key type");
@@ -114,16 +109,16 @@ namespace Cryville.Crtr {
} }
public class PropertyKey { public class PropertyKey {
public PropertyType Type { get; private set; } public PropertyType Type { get; private set; }
public string Name { get; private set; } public int Name { get; private set; }
public PropertyKey(PropertyType type, string name) { public PropertyKey(PropertyType type, string name) {
Type = type; Type = type;
Name = name; Name = IdentifierManager.SharedInstance.Request(name);
} }
public override string ToString() { public override string ToString() {
switch (Type) { switch (Type) {
case PropertyType.Property: return Name; case PropertyType.Property: return (string)IdentifierManager.SharedInstance.Retrieve(Name);
case PropertyType.Variable: return "@var " + Name; case PropertyType.Variable: return string.Format("@var {0}", IdentifierManager.SharedInstance.Retrieve(Name));
default: return string.Format("<{0}> {1}", Type, Name); default: return string.Format("<{0}> {1}", Type, IdentifierManager.SharedInstance.Retrieve(Name));
} }
} }
} }
@@ -151,39 +146,73 @@ namespace Cryville.Crtr {
return result; return result;
} }
else if (type.Equals(typeof(string))) { else if (type.Equals(typeof(string))) {
string result = null; string result = default(string);
ChartPlayer.etor.Evaluate(new PropOp.String(r => result = r), exp);
return result;
}
else if (type.Equals(typeof(float[]))) {
float[] result = null;
ChartPlayer.etor.Evaluate(new pop_numarr(r => result = r), exp);
return result;
}
else if (type.Equals(typeof(Identifier))) {
Identifier result = default(Identifier);
ChartPlayer.etor.Evaluate(new pop_identstr(r => result = r), exp); ChartPlayer.etor.Evaluate(new pop_identstr(r => result = r), exp);
return result; return result;
} }
else if (type.Equals(typeof(string[]))) { else if (type.Equals(typeof(Identifier[]))) {
string[] result = null; Identifier[] result = null;
ChartPlayer.etor.Evaluate(new pop_identstrarr(r => result = r), exp); ChartPlayer.etor.Evaluate(new pop_identstrarr(r => result = r), exp);
return result; return result;
} }
} }
else if (value is string) {
var exp = (string)value;
if (type.Equals(typeof(Identifier))) {
return (Identifier)exp;
}
else if (type == typeof(ScoreOperation)) {
var m = Regex.Match(exp, @"^(\S+)\s*?(\S+)?$");
var name = new Identifier(m.Groups[1].Value);
if (!m.Groups[2].Success) return new ScoreOperation { name = name };
var op = new Identifier(m.Groups[2].Value);
return new ScoreOperation { name = name, op = op };
}
}
return base.ChangeType(value, type, culture); return base.ChangeType(value, type, culture);
} }
#pragma warning disable IDE1006 #pragma warning disable IDE1006
class pop_numarr : PdtOperator {
readonly Action<float[]> _cb;
public pop_numarr(Action<float[]> cb) : base(16) { _cb = cb; }
protected override void Execute() {
var result = new float[LoadedOperandCount];
for (int i = 0; i < LoadedOperandCount; i++) {
result[i] = GetOperand(i).AsNumber();
}
_cb(result);
}
}
class pop_identstr : PropOp { class pop_identstr : PropOp {
readonly Action<string> _cb; readonly Action<SIdentifier> _cb;
public pop_identstr(Action<string> cb) { _cb = cb; } public pop_identstr(Action<SIdentifier> cb) { _cb = cb; }
protected override void Execute() { protected override void Execute() {
var op = GetOperand(0); var op = GetOperand(0);
if (op.Type == PdtInternalType.Undefined) _cb(op.AsIdentifier()); if (op.Type == PdtInternalType.Undefined) _cb(new SIdentifier(op.AsIdentifier()));
else if (op.Type == PdtInternalType.String) _cb(op.AsString()); else if (op.Type == PdtInternalType.String) _cb(new SIdentifier(op.AsString()));
else throw new InvalidCastException("Not an identifier or string"); else throw new InvalidCastException("Not an identifier or string");
} }
} }
class pop_identstrarr : PdtOperator { class pop_identstrarr : PdtOperator {
readonly Action<string[]> _cb; readonly Action<SIdentifier[]> _cb;
public pop_identstrarr(Action<string[]> cb) : base(16) { _cb = cb; } public pop_identstrarr(Action<SIdentifier[]> cb) : base(16) { _cb = cb; }
protected override void Execute() { protected override void Execute() {
var result = new string[LoadedOperandCount]; var result = new SIdentifier[LoadedOperandCount];
for (int i = 0; i < LoadedOperandCount; i++) { for (int i = 0; i < LoadedOperandCount; i++) {
var op = GetOperand(i); var op = GetOperand(i);
if (op.Type != PdtInternalType.Undefined) if (op.Type != PdtInternalType.Undefined)
throw new InvalidCastException("Not an identifier"); throw new InvalidCastException("Not an identifier");
result[i] = op.AsIdentifier(); result[i] = new SIdentifier(op.AsIdentifier());
} }
_cb(result); _cb(result);
} }

View File

@@ -84,6 +84,18 @@ namespace Cryville.Crtr {
} }
} }
[Browsable(false)]
[Category("data")]
[Description("The ruleset config file to load.")]
public string LoadRulesetConfig {
get {
return PlayerPrefs.GetString("LoadRulesetConfig", "");
}
set {
PlayerPrefs.SetString("LoadRulesetConfig", value);
}
}
[Browsable(false)] [Browsable(false)]
[Category("data")] [Category("data")]
[Description("The skin file to load.")] [Description("The skin file to load.")]
@@ -100,7 +112,7 @@ namespace Cryville.Crtr {
[LogarithmicScale][Step(0.5f)][Precision(1e-1)] [LogarithmicScale][Step(0.5f)][Precision(1e-1)]
public float RenderDistance { public float RenderDistance {
get { get {
return PlayerPrefs.GetFloat("RenderDistance", 6); return PlayerPrefs.GetFloat("RenderDistance", 4);
} }
set { set {
PlayerPrefs.SetFloat("RenderDistance", value); PlayerPrefs.SetFloat("RenderDistance", value);
@@ -119,17 +131,6 @@ namespace Cryville.Crtr {
} }
} }
[Category("gameplay")]
[LogarithmicScale][Step(0.5f)][Precision(1e-1)]
public float ScrollVelocity {
get {
return PlayerPrefs.GetFloat("ScrollVelocity", 1);
}
set {
PlayerPrefs.SetFloat("ScrollVelocity", value);
}
}
[Category("gameplay")] [Category("gameplay")]
[Step(0.04f)][Precision(1e-3)] [Step(0.04f)][Precision(1e-3)]
public float SoundOffset { public float SoundOffset {

View File

@@ -7,30 +7,41 @@ using UnityEngine;
namespace Cryville.Crtr { namespace Cryville.Crtr {
public class SettingsPanel : MonoBehaviour { public class SettingsPanel : MonoBehaviour {
[SerializeField] [SerializeField]
private GameObject m_categoryPrefab; GameObject m_categoryPrefab;
private Transform _container; [SerializeField]
Transform m_container;
#pragma warning disable IDE0051 bool _invalidated = true;
void Awake() { object m_target;
_container = transform.Find("Content/__content__"); public object Target {
} get {
public void Start() { return m_target;
LoadProperties(); }
foreach (Transform c in _container) GameObject.Destroy(c.gameObject); set {
foreach (var c in _categories) { if (m_target != value) {
var obj = GameObject.Instantiate<GameObject>(m_categoryPrefab); m_target = value;
obj.transform.SetParent(_container, false); _invalidated = true;
obj.GetComponent<PropertyCategoryPanel>().Load(c.Key, c.Value, Settings.Default); }
} }
} }
#pragma warning restore IDE0051
Dictionary<string, List<PropertyInfo>> _categories = null; public void Update() {
if (!_invalidated) return;
LoadProperties();
foreach (Transform c in m_container) GameObject.Destroy(c.gameObject);
foreach (var c in _categories) {
var obj = GameObject.Instantiate<GameObject>(m_categoryPrefab, m_container, false);
obj.GetComponent<PropertyCategoryPanel>().Load(c.Key, c.Value, Target);
}
}
Dictionary<string, List<PropertyInfo>> _categories = new Dictionary<string, List<PropertyInfo>>();
public void LoadProperties() { public void LoadProperties() {
if (_categories != null) return; _categories.Clear();
_categories = new Dictionary<string, List<PropertyInfo>>(); _invalidated = false;
foreach (var p in typeof(Settings).GetProperties()) { if (Target == null) return;
foreach (var p in Target.GetType().GetProperties()) {
bool browsable = true; bool browsable = true;
string category = "miscellaneous"; string category = "miscellaneous";
foreach (var attr in p.GetCustomAttributes(true)) { foreach (var attr in p.GetCustomAttributes(true)) {

View File

@@ -1,5 +1,6 @@
using Cryville.Common; using Cryville.Common;
using Cryville.Common.Pdt; using Cryville.Common.Pdt;
using Cryville.Crtr.Browsing;
using Cryville.Crtr.Components; using Cryville.Crtr.Components;
using Newtonsoft.Json; using Newtonsoft.Json;
using System; using System;
@@ -10,7 +11,9 @@ using System.Reflection;
using System.Text; using System.Text;
namespace Cryville.Crtr { namespace Cryville.Crtr {
public class Skin { public class Skin : MetaInfo {
public const long CURRENT_FORMAT = 2;
[JsonRequired] [JsonRequired]
public long format; public long format;
@@ -19,14 +22,13 @@ namespace Cryville.Crtr {
[JsonRequired] [JsonRequired]
public string ruleset; public string ruleset;
[JsonRequired] public List<string> frames = new List<string>();
public string pdt;
[JsonIgnore] [JsonIgnore]
public PdtSkin Root { get; private set; } public PdtSkin Root { get; private set; }
public void LoadPdt(DirectoryInfo dir) { public void LoadPdt(DirectoryInfo dir) {
using (StreamReader pdtreader = new StreamReader(dir.FullName + "/" + pdt + ".pdt", Encoding.UTF8)) { using (StreamReader pdtreader = new StreamReader(dir.FullName + "/" + data + ".pdt", Encoding.UTF8)) {
var src = pdtreader.ReadToEnd(); var src = pdtreader.ReadToEnd();
Root = new SkinInterpreter(src, null).Interpret(); Root = new SkinInterpreter(src, null).Interpret();
} }

View File

@@ -9,78 +9,100 @@ using UnityEngine.Profiling;
namespace Cryville.Crtr { namespace Cryville.Crtr {
public class SkinContainer { public class SkinContainer {
readonly PdtSkin skin; readonly PdtSkin skin;
readonly Dictionary<SkinElement, Transform> matchedStatic readonly List<DynamicProperty> dynprops = new List<DynamicProperty>();
= new Dictionary<SkinElement, Transform>(); struct DynamicProperty {
readonly Dictionary<SkinElement, Transform> matchedDynamic public Transform Anchor { get; set; }
= new Dictionary<SkinElement, Transform>(); public SkinPropertyKey Key { get; set; }
public PdtExpression Value { get; set; }
}
readonly List<DynamicElement> dynelems = new List<DynamicElement>();
struct DynamicElement {
public Transform Anchor { get; set; }
public SkinSelectors Selectors { get; set; }
public SkinElement Element { get; set; }
}
public SkinContainer(PdtSkin _skin) { public SkinContainer(PdtSkin _skin) {
skin = _skin; skin = _skin;
} }
public void MatchStatic(ContainerState context) { public void MatchStatic(ContainerState context) {
matchedStatic.Clear(); dynprops.Clear(); dynelems.Clear();
ChartPlayer.etor.ContextState = context;
ChartPlayer.etor.ContextEvent = context.Container;
MatchStatic(skin, context, context.Handler.gogroup); MatchStatic(skin, context, context.Handler.gogroup);
ChartPlayer.etor.ContextEvent = null;
foreach (var m in matchedStatic) { ChartPlayer.etor.ContextState = null;
var el = m.Key;
var obj = m.Value;
foreach (var p in el.properties) {
if (p.Key.Name == null)
obj.gameObject.AddComponent(p.Key.Component);
else {
ChartPlayer.etor.ContextTransform = obj;
ChartPlayer.etor.ContextEvent = context.Container;
ChartPlayer.etor.Evaluate(GetPropOp(obj, p.Key), p.Value);
}
}
}
} }
void MatchStatic(SkinElement rel, ContainerState context, Transform anchor = null) { void MatchStatic(SkinElement rel, ContainerState context, Transform anchor = null) {
matchedStatic.Add(rel, anchor); ChartPlayer.etor.ContextTransform = anchor;
foreach (var p in rel.properties) {
if (p.Key.Name == null)
anchor.gameObject.AddComponent(p.Key.Component);
else {
ChartPlayer.etor.Evaluate(GetPropOp(anchor, p.Key).Operator, p.Value);
if (!p.Value.IsConstant) dynprops.Add(
new DynamicProperty { Anchor = anchor, Key = p.Key, Value = p.Value }
);
}
}
ChartPlayer.etor.ContextTransform = null;
foreach (var r in rel.elements) { foreach (var r in rel.elements) {
var new_anchor = r.Key.MatchStatic(context, anchor); try {
if (new_anchor != null) { var new_anchor = r.Key.MatchStatic(context, anchor);
MatchStatic(r.Value, context, new_anchor); if (new_anchor != null) {
MatchStatic(r.Value, context, new_anchor);
}
}
catch (SelectorNotStaticException) {
dynelems.Add(
new DynamicElement { Anchor = anchor, Selectors = r.Key, Element = r.Value }
);
} }
} }
} }
public void MatchDynamic(ContainerState context) { public void MatchDynamic(ContainerState context) {
if (dynprops.Count == 0 && dynelems.Count == 0) return;
Profiler.BeginSample("SkinContainer.MatchDynamic"); Profiler.BeginSample("SkinContainer.MatchDynamic");
matchedDynamic.Clear(); ChartPlayer.etor.ContextState = context;
MatchDynamic(skin, context, context.Handler.gogroup); ChartPlayer.etor.ContextEvent = context.Container;
for (int i = 0; i < dynprops.Count; i++) {
foreach (var m in matchedDynamic) { DynamicProperty p = dynprops[i];
var el = m.Key; var prop = GetPropOp(p.Anchor, p.Key);
var obj = m.Value; if (context.CloneType > prop.UpdateCloneType) continue;
foreach (var p in el.properties) { ChartPlayer.etor.Evaluate(prop.Operator, p.Value);
if (p.Key.Name == null) continue;
if (p.Value.IsConstant) continue;
ChartPlayer.etor.ContextTransform = obj;
ChartPlayer.etor.ContextEvent = context.Container;
ChartPlayer.etor.Evaluate(GetPropOp(obj, p.Key), p.Value);
}
} }
for (int i = 0; i < dynelems.Count; i++) {
DynamicElement e = dynelems[i];
var anchor = e.Selectors.MatchDynamic(context, e.Anchor);
if (anchor != null) MatchDynamic(e.Element, context, anchor);
}
ChartPlayer.etor.ContextEvent = null;
ChartPlayer.etor.ContextState = null;
Profiler.EndSample(); Profiler.EndSample();
} }
void MatchDynamic(SkinElement rel, ContainerState context, Transform anchor = null) { void MatchDynamic(SkinElement rel, ContainerState context, Transform anchor = null) {
matchedDynamic.Add(rel, anchor); ChartPlayer.etor.ContextTransform = anchor;
foreach (var p in rel.properties) {
if (p.Key.Name == null)
throw new InvalidOperationException("Component creation in dynamic context is not allowed");
var prop = GetPropOp(anchor, p.Key);
if (context.CloneType > prop.UpdateCloneType) continue;
ChartPlayer.etor.Evaluate(prop.Operator, p.Value);
}
ChartPlayer.etor.ContextTransform = null;
foreach (var r in rel.elements) { foreach (var r in rel.elements) {
Transform new_anchor;
if (!matchedStatic.ContainsKey(r.Value)) continue;
if (!r.Key.IsUpdatable(context)) continue; if (!r.Key.IsUpdatable(context)) continue;
new_anchor = r.Key.MatchDynamic( var new_anchor = r.Key.MatchDynamic(context, anchor);
context, r.Value, matchedStatic[r.Value], anchor
);
if (new_anchor != null) { if (new_anchor != null) {
MatchDynamic(r.Value, context, new_anchor); MatchDynamic(r.Value, context, new_anchor);
} }
} }
} }
PdtOperator GetPropOp(Transform obj, SkinPropertyKey key) { SkinProperty GetPropOp(Transform obj, SkinPropertyKey key) {
var ctype = key.Component; var ctype = key.Component;
var comp = (SkinComponent)obj.GetComponent(ctype); var comp = (SkinComponent)obj.GetComponent(ctype);
if (comp == null) throw new InvalidOperationException("Component instance not found"); if (comp == null) throw new InvalidOperationException("Component instance not found");
PdtOperator result; SkinProperty result;
if (!comp.PropOps.TryGetValue(key.Name, out result)) if (!comp.Properties.TryGetValue(key.Name, out result))
throw new ArgumentException(string.Format("Property {0} not found on component", key.Name)); throw new ArgumentException(string.Format("Property {0} not found on component", key.Name));
return result; return result;
} }

View File

@@ -4,6 +4,7 @@ using Cryville.Crtr.Event;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Runtime.Serialization;
using UnityEngine; using UnityEngine;
namespace Cryville.Crtr { namespace Cryville.Crtr {
@@ -34,7 +35,15 @@ namespace Cryville.Crtr {
selectors[i].Optimize(etor); selectors[i].Optimize(etor);
} }
} }
public Transform MatchStatic(ContainerState h, Transform anchor = null) { public bool IsStatic {
get {
foreach (var s in selectors) {
if (!s.IsStatic) return false;
}
return true;
}
}
public Transform MatchStatic(ContainerState h, Transform anchor) {
foreach (var s in selectors) { foreach (var s in selectors) {
anchor = s.Match(h, anchor); anchor = s.Match(h, anchor);
if (anchor == null) return null; if (anchor == null) return null;
@@ -46,10 +55,9 @@ namespace Cryville.Crtr {
if (!s.IsUpdatable(h)) return false; if (!s.IsUpdatable(h)) return false;
return true; return true;
} }
public Transform MatchDynamic(ContainerState h, SkinElement e, Transform old_target, Transform anchor = null) { public Transform MatchDynamic(ContainerState h, Transform anchor) {
if (!e.IsDynamic) return null;
foreach (var s in selectors) { foreach (var s in selectors) {
anchor = s.Match(h, anchor, old_target); anchor = s.Match(h, anchor, true);
if (anchor == null) return null; if (anchor == null) return null;
} }
return anchor; return anchor;
@@ -62,7 +70,7 @@ namespace Cryville.Crtr {
get; get;
} }
public virtual void Optimize(PdtEvaluatorBase etor) { } public virtual void Optimize(PdtEvaluatorBase etor) { }
public abstract Transform Match(ContainerState h, Transform a, Transform ot = null); public abstract Transform Match(ContainerState h, Transform a, bool dyn = false);
public virtual bool IsUpdatable(ContainerState h) { public virtual bool IsUpdatable(ContainerState h) {
return true; return true;
} }
@@ -71,12 +79,9 @@ namespace Cryville.Crtr {
public override bool IsStatic { public override bool IsStatic {
get { return true; } get { return true; }
} }
public override Transform Match(ContainerState h, Transform a, Transform ot = null) { public override Transform Match(ContainerState h, Transform a, bool dyn = false) {
if (ot != null) if (dyn) throw new InvalidOperationException("Object creation in dynamic context is not allowed");
return ot; var obj = new GameObject("__obj__");
var obj = new GameObject {
name = "__obj__"
};
obj.transform.SetParent(a, false); obj.transform.SetParent(a, false);
obj.AddComponent<TransformInterface>(); obj.AddComponent<TransformInterface>();
return obj.transform; return obj.transform;
@@ -91,7 +96,7 @@ namespace Cryville.Crtr {
get { return true; } get { return true; }
} }
public override Transform Match(ContainerState h, Transform a, Transform ot = null) { public override Transform Match(ContainerState h, Transform a, bool dyn = false) {
return h.Handler.Anchors[Name].Transform; return h.Handler.Anchors[Name].Transform;
} }
public override bool IsUpdatable(ContainerState h) { public override bool IsUpdatable(ContainerState h) {
@@ -110,13 +115,20 @@ namespace Cryville.Crtr {
etor.Optimize(_exp); etor.Optimize(_exp);
} }
public override bool IsStatic { public override bool IsStatic {
get { throw new NotImplementedException(); } get { return _exp.IsConstant; }
} }
public override Transform Match(ContainerState h, Transform a, Transform ot = null) { public override Transform Match(ContainerState h, Transform a, bool dyn = false) {
ChartPlayer.etor.ContextTransform = a; ChartPlayer.etor.ContextTransform = a;
ChartPlayer.etor.ContextEvent = h.Container; try {
ChartPlayer.etor.Evaluate(_op, _exp); ChartPlayer.etor.Evaluate(_op, _exp);
return _flag ? a : null; return _flag ? a : null;
}
catch (Exception) {
throw new SelectorNotStaticException();
}
finally {
ChartPlayer.etor.ContextTransform = null;
}
} }
} }
public class State : SkinSelector { public class State : SkinSelector {
@@ -124,7 +136,7 @@ namespace Cryville.Crtr {
public override bool IsStatic { public override bool IsStatic {
get { return false; } get { return false; }
} }
public override Transform Match(ContainerState h, Transform a, Transform ot = null) { public override Transform Match(ContainerState h, Transform a, bool dyn = false) {
return null; // TODO return null; // TODO
} }
} }
@@ -134,9 +146,15 @@ namespace Cryville.Crtr {
public override bool IsStatic { public override bool IsStatic {
get { return true; } get { return true; }
} }
public override Transform Match(ContainerState h, Transform a, Transform ot = null) { public override Transform Match(ContainerState h, Transform a, bool dyn = false) {
return h.Handler.TypeName == _type ? a : null; return h.Handler.TypeName == _type ? a : null;
} }
} }
} }
public class SelectorNotStaticException : Exception {
public SelectorNotStaticException() : base("The selector is not static") { }
public SelectorNotStaticException(string message) : base(message) { }
public SelectorNotStaticException(string message, Exception innerException) : base(message, innerException) { }
protected SelectorNotStaticException(SerializationInfo info, StreamingContext context) : base(info, context) { }
}
} }

View File

@@ -0,0 +1,109 @@
using System;
using UnityEngine;
namespace Cryville.Crtr {
public class SpriteFrame {
#pragma warning disable IDE1006
Rect _frame;
public Rect frame {
get { return _frame; }
set { _frame = value; }
}
public Rect textureRect {
get { return _frame; }
set { _frame = value; }
}
bool _rotated = false;
public bool rotated {
get { return _rotated; }
set { _rotated = value; }
}
public bool textureRotated {
get { return _rotated; }
set { _rotated = value; }
}
#pragma warning restore IDE1006
public Vector2 offset;
public Rect sourceColorRect;
public Vector2 sourceSize;
private Rect _uv;
private Vector2[] cuv;
public Rect UV {
get {
return _uv;
}
private set {
_uv = value;
float x0 = Mathf.Min(_uv.xMin, _uv.xMax);
float x1 = Mathf.Max(_uv.xMin, _uv.xMax);
float y0 = Mathf.Min(_uv.yMin, _uv.yMax);
float y1 = Mathf.Max(_uv.yMin, _uv.yMax);
if (_rotated) cuv = new Vector2[]{
new Vector2(x0, y1),
new Vector2(x1, y0),
new Vector2(x0, y0),
new Vector2(x1, y1),
};
else cuv = new Vector2[]{
new Vector2(x0, y0),
new Vector2(x1, y1),
new Vector2(x1, y0),
new Vector2(x0, y1),
};
}
}
public Vector2 GetUV(Vector2 uv) {
return GetUV(uv.x, uv.y);
}
public Vector2 GetUV(float u, float v) {
Vector2 uv00 = cuv[0], uv11 = cuv[1],
uv10 = cuv[2], uv01 = cuv[3];
return (1 - u - v) * uv00
+ u * uv10
+ v * uv01
+ u * v * (uv00 + uv11 - uv10 - uv01);
}
public Texture2D Texture {
get;
private set;
}
public Vector2 Size {
get {
return new Vector2(Texture.width, Texture.height);
}
}
public void Init() {
if (Texture == null)
throw new InvalidOperationException("Missing texture");
_frame = new Rect(Vector2.zero, Size);
var w = _frame.width;
var h = _frame.height;
float x = _frame.x / w;
float y = 1 - _frame.y / h;
float tw = (_rotated ? _frame.height : _frame.width) / w;
float th = (_rotated ? _frame.width : _frame.height) / h;
if (_rotated) UV = new Rect(x, y, tw, -th);
else UV = new Rect(x, y, tw, -th);
}
public void Init(int w, int h, Texture2D _base) {
if (Texture != null)
throw new InvalidOperationException("Missing texture");
Texture = _base;
float x = _frame.x / w;
float y = 1 - _frame.y / h;
float tw = (_rotated ? _frame.height : _frame.width) / w;
float th = (_rotated ? _frame.width : _frame.height) / h;
if (_rotated) UV = new Rect(x, y, tw, -th);
else UV = new Rect(x, y, tw, -th);
}
public SpriteFrame() { }
public SpriteFrame(Texture2D tex) {
Texture = tex;
}
}
}

View File

@@ -32,17 +32,11 @@ namespace Cryville.Crtr {
} }
public void Forward(Action<T> callback = null) { public void Forward(Action<T> callback = null) {
ForwardToTime(float.PositiveInfinity, ev => { ForwardToTime(float.PositiveInfinity, callback);
if (callback != null)
callback(ev);
});
} }
public void ForwardByTime(float time, Action<T> callback = null) { public void ForwardByTime(float time, Action<T> callback = null) {
ForwardToTime(Time + time, ev => { ForwardToTime(Time + time, callback);
if (callback != null)
callback(ev);
});
} }
public void ForwardOnceByTime(float time, Action<T> callback = null) { public void ForwardOnceByTime(float time, Action<T> callback = null) {

View File

@@ -97,7 +97,7 @@ namespace Cryville.Crtr {
pwp = Vector3.zero; pwp = Vector3.zero;
ptime = s.Time; ptime = s.Time;
length = 0; length = 0;
//Logger.LogFormat("main", 0, "Debug", "SV: {0}", cs.GetRawValue<Vec1m>("svm").Value); // Logger.LogFormat("main", 0, "Debug", "SV: {0}", cs.GetRawValue<Vec1m>("svm").Value);
} }
// TODO Fix anchor rotation // TODO Fix anchor rotation

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