98 Commits

Author SHA1 Message Date
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
77 changed files with 1847 additions and 829 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,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

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

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

@@ -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

@@ -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,13 @@ 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) {
return Regex.Replace(name, @"[\/\\\<\>\:\x22\|\?\*\p{Cc}\.\s]", "_");
}
} }
} }

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

@@ -11,18 +11,20 @@ namespace Cryville.Common.Unity.Input {
typeof(UnityMouseHandler), typeof(UnityMouseHandler),
typeof(UnityTouchHandler), typeof(UnityTouchHandler),
}; };
readonly List<InputHandler> _handlers = new List<InputHandler>(); // TODO set private
public 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 +34,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 +51,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 +82,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;
} }
} }
@@ -50,7 +50,7 @@ namespace Cryville.Common.Unity.Input {
} }
public abstract string GetKeyName(int type); public abstract string GetKeyName(int type);
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 +64,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 +92,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

@@ -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

@@ -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,24 +59,27 @@ 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 + "/meta.json");
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.chart.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 {
IsDirectory = false, IsDirectory = false,
Icon = cover, Icon = cover,
@@ -86,20 +90,22 @@ namespace Cryville.Crtr.Browsing {
public ChartDetail GetItemDetail(int id) { public ChartDetail GetItemDetail(int id) {
var item = items[id]; var item = items[id];
var meta = new ChartMeta();
var metaFile = new FileInfo(item.FullName + "/meta.json");
if (metaFile.Exists) {
using (var reader = new StreamReader(metaFile.FullName)) {
meta = JsonConvert.DeserializeObject<ChartMeta>(reader.ReadToEnd());
}
}
AsyncDelivery<Texture2D> cover = null; AsyncDelivery<Texture2D> cover = null;
var coverFile = item.GetFiles("cover.*"); if (meta.cover != null && meta.cover != "") {
var coverFile = item.GetFiles(meta.cover);
if (coverFile.Length > 0) { if (coverFile.Length > 0) {
cover = new AsyncDelivery<Texture2D>(); cover = new AsyncDelivery<Texture2D>();
var task = new LoadTextureTask(Game.FileProtocolPrefix + coverFile[0].FullName, cover.Deliver); var task = new LoadTextureTask(Game.FileProtocolPrefix + coverFile[0].FullName, cover.Deliver);
cover.CancelSource = task.Cancel; cover.CancelSource = task.Cancel;
Game.NetworkTaskWorker.SubmitNetworkTask(task); Game.NetworkTaskWorker.SubmitNetworkTask(task);
} }
ChartMeta meta = new ChartMeta();
var metaFile = new FileInfo(item.FullName + "/meta.json");
if (metaFile.Exists) {
using (var reader = new StreamReader(metaFile.FullName)) {
meta = JsonConvert.DeserializeObject<ChartMeta>(reader.ReadToEnd());
}
} }
return new ChartDetail { return new ChartDetail {
Cover = cover, Cover = cover,
@@ -115,9 +121,19 @@ namespace Cryville.Crtr.Browsing {
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) {
Popup.Create(ex.Message);
return false;
}
foreach (var res in resources) { foreach (var res in resources) {
if (res is ChartResource) { if (!res.Valid) {
Logger.Log("main", 3, "Resource", "Attempt to import invalid resource {0}", res);
}
else if (res is ChartResource) {
var tres = (ChartResource)res; var tres = (ChartResource)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();
@@ -132,8 +148,9 @@ namespace Cryville.Crtr.Browsing {
var tres = (CoverResource)res; var tres = (CoverResource)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();
var dest = new FileInfo(_rootPath + "/charts/" + res.Name + "/cover" + tres.Source.Extension); var dest = new FileInfo(_rootPath + "/charts/" + res.Name + "/" + tres.Source.Name);
if (!dest.Exists) tres.Source.CopyTo(dest.FullName); if (!dest.Exists) tres.Source.CopyTo(dest.FullName);
} }
else if (res is SongResource) { else if (res is SongResource) {
var tres = (SongResource)res; var tres = (SongResource)res;

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

@@ -29,7 +29,6 @@ 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;
var item = ResourceManager.GetItemMeta(id); var item = ResourceManager.GetItemMeta(id);
bi.Load(id, item); bi.Load(id, item);
return true; return true;
@@ -60,11 +59,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

@@ -64,8 +64,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 +74,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 +84,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);
} }
} }
@@ -107,6 +107,7 @@ namespace Cryville.Crtr.Browsing {
} }
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,7 @@
using System.Collections.Generic; using Cryville.Common;
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,9 +9,13 @@ 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 ChartResource : Resource {
public ChartResource(string name, Chart main, ChartMeta meta) : base(name) { public ChartResource(string name, Chart main, ChartMeta meta) : base(name) {
@@ -17,17 +23,20 @@ namespace Cryville.Crtr.Browsing {
} }
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 class CoverResource : Resource {
public CoverResource(string name, FileInfo src) : base(name) { public CoverResource(string name, FileInfo src) : base(name) {
Source = src; Source = src;
} }
public FileInfo Source { get; private set; } public FileInfo Source { get; private set; }
public override bool Valid { get { return Source.Exists; } }
} }
public class SongResource : Resource { public class SongResource : Resource {
public SongResource(string name, FileInfo src) : base(name) { public SongResource(string name, FileInfo src) : base(name) {
Source = src; Source = src;
} }
public FileInfo Source { get; private set; } public FileInfo Source { get; private set; }
public override bool Valid { get { return Source.Exists; } }
} }
} }

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; }
} }
} }
@@ -275,8 +276,8 @@ 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(); // TODO
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;
})); }));
@@ -378,7 +379,7 @@ namespace Cryville.Crtr {
public Note() { public Note() {
SubmitPropSrc("track", new PropSrc.Float(() => { SubmitPropSrc("track", new PropSrc.Float(() => {
var i = motions.FirstOrDefault(m => m.RelativeNode == null && m.Name.MainName == "track"); var i = motions.FirstOrDefault(m => m.RelativeNode == null && m.Name == "track");
if (i == null) return ((Vec1)ChartPlayer.motionRegistry["track"].InitValue).Value; if (i == null) return ((Vec1)ChartPlayer.motionRegistry["track"].InitValue).Value;
else return ((Vec1)i.AbsoluteValue).Value; else return ((Vec1)i.AbsoluteValue).Value;
})); }));
@@ -391,19 +392,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 +421,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

@@ -1,8 +1,8 @@
//#define NO_THREAD
#define BUILD #define BUILD
using Cryville.Common; using Cryville.Common;
using Cryville.Common.Plist; 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;
@@ -52,6 +52,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 +63,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,18 +85,43 @@ namespace Cryville.Crtr {
texHandler = new DownloadHandlerTexture(); texHandler = new DownloadHandlerTexture();
#if BUILD #if BUILD
try {
Play(); 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();
if (logEnabled) LogUpdate();
else Game.MainLogger.Enumerate((level, module, msg) => { });
}
void GameUpdate() {
try { try {
if (Screen.width != screenSize.x || Screen.height != screenSize.y) if (Screen.width != screenSize.x || Screen.height != screenSize.y)
throw new InvalidOperationException("Window resized while playing"); throw new InvalidOperationException("Window resized while playing");
@@ -112,16 +129,9 @@ namespace Cryville.Crtr {
? 1f / Application.targetFrameRate ? 1f / Application.targetFrameRate
: Time.deltaTime; : Time.deltaTime;
firstFrame = false; firstFrame = false;
inputProxy.ForceTick();
cbus.ForwardByTime(dt); cbus.ForwardByTime(dt);
bbus.ForwardByTime(dt); bbus.ForwardByTime(dt);
UnityEngine.Profiling.Profiler.BeginSample("ChartPlayer.FeedJudge");
judge.StartFrame();
Game.InputManager.EnumerateEvents(ev => {
// Logger.Log("main", 0, "Input", ev.ToString());
judge.Feed(ev);
});
judge.EndFrame();
UnityEngine.Profiling.Profiler.EndSample();
UnityEngine.Profiling.Profiler.BeginSample("ChartPlayer.Forward"); UnityEngine.Profiling.Profiler.BeginSample("ChartPlayer.Forward");
UnityEngine.Profiling.Profiler.BeginSample("EventBus.Copy"); UnityEngine.Profiling.Profiler.BeginSample("EventBus.Copy");
bbus.CopyTo(2, tbus); bbus.CopyTo(2, tbus);
@@ -144,37 +154,31 @@ namespace Cryville.Crtr {
} }
catch (Exception ex) { catch (Exception ex) {
Game.LogException("Game", "An error occured while playing", ex); Game.LogException("Game", "An error occured while playing", ex);
Popup.CreateException(ex);
Stop(); Stop();
} }
} }
#if !NO_THREAD void LoadUpdate() {
else if (loadThread != null) {
if (texLoader != null) { if (texLoader != null) {
string url = texLoader.url; string url = texLoader.url;
string name = StringUtils.TrimExt(url.Substring(url.LastIndexOfAny(new char[] {'/', '\\'}) + 1)); string name = StringUtils.TrimExt(url.Substring(url.LastIndexOfAny(new char[] {'/', '\\'}) + 1));
#if UNITY_5_4_OR_NEWER #if UNITY_5_4_OR_NEWER
if (texHandler.isDone) { if (texHandler.isDone) {
var tex = texHandler.texture; var tex = texHandler.texture;
tex.wrapMode = TextureWrapMode.Clamp;
texs.Add(name, tex); texs.Add(name, tex);
Logger.Log("main", 0, "Load/MainThread", "Loaded texture {0} ({1} bytes)", name, texLoader.downloadedBytes);
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 #else
if (texLoader.isDone) { if (texLoader.isDone) {
var tex = texLoader.texture; var tex = texLoader.texture;
tex.wrapMode = TextureWrapMode.Clamp;
texs.Add(name, tex); texs.Add(name, tex);
Logger.Log("main", 0, "Load/MainThread", "Loaded texture {0} ({1} bytes)", name, texLoader.bytesDownloaded);
texLoader.Dispose(); texLoader.Dispose();
texLoader = null; texLoader = null;
} }
else if (texLoader.progress != 0) {
Logger.Log("main", 0, "Load/MainThread", "Loading texture {0} {1:P0}", name, texLoader.progress);
}
#endif #endif
} }
if (texLoader == null) if (texLoader == null)
@@ -193,9 +197,10 @@ namespace Cryville.Crtr {
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
@@ -206,8 +211,8 @@ namespace Cryville.Crtr {
} }
} }
} }
#endif string timetext = string.Empty;
if (logEnabled) { void LogUpdate() {
string _logs = logs.text; string _logs = logs.text;
Game.MainLogger.Enumerate((level, module, msg) => { Game.MainLogger.Enumerate((level, module, msg) => {
string color; string color;
@@ -242,12 +247,18 @@ namespace Cryville.Crtr {
UnityEngine.Profiling.Profiler.GetTotalReservedMemory() UnityEngine.Profiling.Profiler.GetTotalReservedMemory()
#endif #endif
); );
sttext += timetext;
if (judge != null) sttext += "\n== Scores ==\n" + judge.GetFullFormattedScoreString(); if (judge != null) sttext += "\n== Scores ==\n" + judge.GetFullFormattedScoreString();
status.text = sttext; status.text = sttext;
} }
else { void OnCameraPostRender(Camera cam) {
Game.MainLogger.Enumerate((level, module, msg) => { }); 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 +309,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,12 +332,33 @@ 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
FileInfo rulesetConfigFile = new FileInfo(
Game.GameDataPath + "/config/rulesets/" + Settings.Default.LoadRulesetConfig
); );
if (!rulesetConfigFile.Exists) throw new FileNotFoundException("Ruleset config not found\nPlease open the config to generate");
using (StreamReader cfgreader = new StreamReader(rulesetConfigFile.FullName, Encoding.UTF8)) {
_rscfg = JsonConvert.DeserializeObject<RulesetConfig>(cfgreader.ReadToEnd(), new JsonSerializerSettings() {
MissingMemberHandling = MissingMemberHandling.Error
});
}
sv = _rscfg.generic.ScrollVelocity;
FileInfo skinFile = new FileInfo(
string.Format("{0}/skins/{1}/{2}/.umgs", Game.GameDataPath, rulesetFile.Directory.Name, _rscfg.generic.Skin)
);
if (!skinFile.Exists) throw new FileNotFoundException("Skin not found\nPlease specify an available skin in the config");
loadThread = new Thread(new ParameterizedThreadStart(Load));
loadThread.Start(new LoadInfo() {
chartFile = chartFile,
rulesetFile = rulesetFile,
skinFile = skinFile,
});
Logger.Log("main", 0, "Load/MainThread", "Loading textures..."); Logger.Log("main", 0, "Load/MainThread", "Loading textures...");
texloadtimer = new diag::Stopwatch(); texloadtimer = new diag::Stopwatch();
@@ -335,33 +366,8 @@ namespace Cryville.Crtr {
texs = new Dictionary<string, Texture2D>(); texs = new Dictionary<string, Texture2D>();
var flist = skinFile.Directory.GetFiles("*.png"); var flist = skinFile.Directory.GetFiles("*.png");
foreach (FileInfo f in flist) { foreach (FileInfo f in flist) {
#if NO_THREAD
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); texLoadQueue.Enqueue(f.FullName);
#endif
} }
#if NO_THREAD
texloadtimer.Stop();
Logger.LogFormat("main", 0, "Load/MainThread", "Textures loaded successfully ({0}ms)", texloadtimer.Elapsed.TotalMilliseconds);
Load(new LoadInfo(){
chartFile = chartFile,
rulesetFile = rulesetFile,
skinFile = skinFile,
});
Prehandle();
#else
loadThread = new Thread(new ParameterizedThreadStart(Load));
loadThread.Start(new LoadInfo() {
chartFile = chartFile,
rulesetFile = rulesetFile,
skinFile = skinFile,
});
#endif
} }
void Prehandle() { void Prehandle() {
@@ -381,7 +387,7 @@ namespace Cryville.Crtr {
} }
Logger.Log("main", 0, "Load/Prehandle", "Initializing states"); Logger.Log("main", 0, "Load/Prehandle", "Initializing states");
cbus.BroadcastInit(); cbus.BroadcastInit();
Game.InputManager.Activate(); 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 +395,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 +410,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 +449,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 +466,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,10 +493,16 @@ 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); cbus.AttachSystems(pskin, judge);
Logger.Log("main", 0, "Load/WorkerThread", "Attaching handlers"); Logger.Log("main", 0, "Load/WorkerThread", "Attaching handlers");
@@ -499,7 +514,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);
@@ -508,11 +523,15 @@ namespace Cryville.Crtr {
} }
} }
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)"); Logger.Log("main", 0, "Load/WorkerThread", "Prehandling (iteration 2)");
cbus.Clone(17).Forward(); using (var pbus = cbus.Clone(17)) {
pbus.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);

View File

@@ -96,6 +96,7 @@ namespace Cryville.Crtr.Components {
float sum_x; float sum_x;
void UpdateMeshes() { void UpdateMeshes() {
// TODO optimize GC
if (meshes.Count == 0) return; if (meshes.Count == 0) return;
sum_x = 0; sum_x = 0;
int vc = m_value.Length * 4; int vc = m_value.Length * 4;

View File

@@ -1,9 +1,77 @@
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
);
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 != 1) 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 ReturnToMenu() { public void ReturnToMenu() {
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));
}
GameObject.Find("Master").GetComponent<Master>().ShowMenu(); GameObject.Find("Master").GetComponent<Master>().ShowMenu();
#if UNITY_5_5_OR_NEWER #if UNITY_5_5_OR_NEWER
SceneManager.UnloadSceneAsync("Config"); SceneManager.UnloadSceneAsync("Config");

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
);
DirectoryInfo dir = file.Directory;
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); _entries.Add(i.Key, e);
e.SetKey(this, i.Key); e.SetKey(this, i.Key);
OnProxyChanged(this, proxy[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

@@ -66,9 +66,9 @@ 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, Vector> CachedValues;
protected Dictionary<MotionName, bool> CachedValueStates = new Dictionary<MotionName, bool>(); protected Dictionary<Identifier, bool> CachedValueStates;
/// <summary> /// <summary>
/// Gets a motion value. /// Gets a motion value.
@@ -76,12 +76,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,7 +89,7 @@ namespace Cryville.Crtr.Event {
return value; return value;
} }
void InvalidateMotion(MotionName name) { void InvalidateMotion(Identifier name) {
CachedValueStates[name] = false; CachedValueStates[name] = false;
foreach (var c in Children) foreach (var c in Children)
c.Value.InvalidateMotion(name); c.Value.InvalidateMotion(name);
@@ -103,8 +103,11 @@ namespace Cryville.Crtr.Event {
Parent = parent; Parent = parent;
} }
Values = new Dictionary<Identifier, RealtimeMotionValue>(ChartPlayer.motionRegistry.Count);
CachedValues = new Dictionary<Identifier, Vector>(ChartPlayer.motionRegistry.Count);
CachedValueStates = new Dictionary<Identifier, bool>(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,19 +120,19 @@ 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, Vector>(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); var cvss = new Dictionary<Identifier, bool>(ChartPlayer.motionRegistry.Count);
foreach (var cv in CachedValueStates) { foreach (var cv in CachedValueStates) {
cvss.Add(cv.Key, cv.Value); cvss.Add(cv.Key, cv.Value);
} }
@@ -193,7 +196,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();
@@ -211,28 +214,40 @@ namespace Cryville.Crtr.Event {
this.judge = judge; this.judge = judge;
} }
public T GetRawValue<T>(MotionName key) where T : Vector { public Vector GetRawValue(Identifier key) {
Vector tr; Vector tr;
if (!CachedValues.TryGetValue(key, out tr)) { if (!CachedValues.TryGetValue(key, out tr)) {
tr = (Vector)ReflectionHelper.InvokeEmptyConstructor(typeof(T)); tr = (Vector)ReflectionHelper.InvokeEmptyConstructor(ChartPlayer.motionRegistry[key].Type);
CachedValues.Add(key, tr); CachedValues.Add(key, tr);
CachedValueStates[key] = false; CachedValueStates[key] = false;
} }
T r = (T)tr; Vector r = tr;
#if !DISABLE_CACHE #if !DISABLE_CACHE
if (CachedValueStates[key]) return r; if (CachedValueStates[key]) 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; CachedValueStates[key] = 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) { else Callback(null, callback);
Callback(ev, callback);
flag = true;
}
if (!flag) Callback(null, callback);
return;
}
Callback(null, callback);
} }
void Callback(StampedEvent ev, Action<StampedEvent> callback) { void Callback(StampedEvent ev, Action<StampedEvent> callback) {

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, string> _rented = new Dictionary<RealtimeMotionValue, string>();
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

@@ -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,30 @@ 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() { song = new ChartMeta.MetaInfo() {
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>(),
@@ -68,7 +76,7 @@ namespace Cryville.Crtr.Extensions.Malody {
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 += baseBpm == null ? 0 : (cbeat - pbeat) / baseBpm.Value * 60f;
pbeat = cbeat; pbeat = cbeat;
if (ev is MalodyChart.Time) { if (ev is MalodyChart.Time) {
@@ -94,17 +102,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 +121,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,
@@ -140,9 +149,11 @@ namespace Cryville.Crtr.Extensions.Malody {
}; };
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.chart.name);
result.Add(new ChartResource(chartName, chart, meta)); if (src.meta.background != null) {
if (src.meta.background != null)
result.Add(new CoverResource(chartName, new FileInfo(file.DirectoryName + "/" + src.meta.background))); result.Add(new CoverResource(chartName, new FileInfo(file.DirectoryName + "/" + src.meta.background)));
meta.cover = src.meta.background;
}
result.Add(new ChartResource(chartName, chart, meta));
return result; return result;
} }
@@ -151,7 +162,7 @@ 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];
} }
} }

View File

@@ -85,12 +85,10 @@ namespace Cryville.Crtr {
AudioSequencer.Playing = true; AudioSequencer.Playing = true;
AudioClient.Start(); AudioClient.Start();
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 +96,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

@@ -1,17 +1,25 @@
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) { }
}
_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 +31,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 +127,127 @@ 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 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 byte[] _nullvalue = 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, new PropSrc.Arbitrary(PdtInternalType.Null, _nullvalue));
OnInput(id, proxy.Target, ft, tt, true);
}
else {
fixed (byte* ptr = _vecbuf) {
*(Vector3*)ptr = vec.Vector;
}
_etor.ContextCascadeUpdate(_var_value, new PropSrc.Arbitrary(PdtInternalType.Vector, _vecbuf));
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 = new PropSrc.Arbitrary(PdtInternalType.Null, _nullvalue);
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 +267,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,38 +1,203 @@
using Cryville.Common;
using Cryville.Common.Pdt; using Cryville.Common.Pdt;
using Cryville.Common.Unity.Input; using Cryville.Crtr.Event;
using System.Collections.Generic; using System.Collections.Generic;
namespace Cryville.Crtr { namespace Cryville.Crtr {
public class Judge { public class Judge {
readonly PdtEvaluator _etor;
readonly PdtRuleset _rs; readonly PdtRuleset _rs;
readonly Dictionary<Identifier, float> ct
= new Dictionary<Identifier, float>();
readonly Dictionary<Identifier, List<JudgeEvent>> evs
= 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; }
}
static readonly IComparer<JudgeEvent> _stcmp = new JudgeEventStartTimeComparer();
class JudgeEventStartTimeComparer : IComparer<JudgeEvent> {
public int Compare(JudgeEvent x, JudgeEvent y) {
return x.StartClip.CompareTo(y.StartClip);
}
}
public Judge(PdtRuleset rs) { public Judge(PdtRuleset rs) {
_etor = ChartPlayer.etor;
_rs = rs; _rs = rs;
foreach (var s in rs.scores) foreach (var s in rs.scores) {
scores.Add(s.Key, s.Value.init); var key = s.Key;
scoreSrcs.Add(key.Key, new PropSrc.Float(() => scores[key.Key]));
scoreOps.Add(key.Key, new PropOp.Float(v => scores[key.Key] = v));
scoreFmtKeys.Add(key.Key, IdentifierManager.SharedInstance.Request("_score_" + (string)key.Name));
scoreDefs.Add(key.Key, s.Value);
scores.Add(key.Key, s.Value.init);
} }
public void StartFrame() {
} }
public void Feed(InputEvent ev) { 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>());
} }
public void EndFrame() { 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);
} }
public readonly Dictionary<string, float> scores = new Dictionary<string, float>(); static bool _flag;
readonly Dictionary<string, string> ScoreCache = new Dictionary<string, string>(); static readonly PropOp.Boolean _flagop = new PropOp.Boolean(v => _flag = v);
public Dictionary<string, string> GetFormattedScoreStrings() { 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);
scoreSrcs[key.name.Key].Invalidate();
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);
scoreSrcs[s.Key.Key].Invalidate();
}
}
}
ScoreCache.Clear();
}
readonly Dictionary<int, int> scoreFmtKeys = 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>();
public readonly Dictionary<int, float> scores = new Dictionary<int, float>();
readonly Dictionary<int, string> ScoreCache = new Dictionary<int, string>();
readonly object _lock = new object();
public Dictionary<int, string> GetFormattedScoreStrings() {
lock (_lock) {
if (ScoreCache.Count == 0) { if (ScoreCache.Count == 0) {
foreach (var s in scores) foreach (var s in scores)
ScoreCache.Add(s.Key, s.Value.ToString(_rs.scores[s.Key].format)); ScoreCache.Add(scoreFmtKeys[s.Key], s.Value.ToString(scoreDefs[s.Key].format));
} }
return ScoreCache; return ScoreCache;
} }
}
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 GetFormattedScoreStrings()) {
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.Key), s.Value);
flag = true; flag = true;
} }
return result; return result;
@@ -41,18 +206,25 @@ namespace Cryville.Crtr {
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,11 +6,13 @@ 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
bool initialized = false; bool initialized = false;
@@ -19,6 +21,7 @@ namespace Cryville.Crtr {
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) {

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

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,12 @@ 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 PdtRuleset ruleset;
readonly Judge judge; readonly Judge judge;
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;
} }
@@ -90,29 +93,39 @@ 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.Judge) {
var tev = (Chart.Judge)ev.Unstamped;
Identifier name = default(Identifier);
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 Chart.Motion) { else if (ev.Unstamped is Chart.Motion) {
var tev = (Chart.Motion)ev.Unstamped; /*var tev = (Chart.Motion)ev.Unstamped;
if (tev.Name.MainName != "judge") return; if (tev.Name != "judge") return;
phMotions.Add(tev, (Vec1)s.GetRawValue<Vec1>(tev.Name).Clone()); phMotions.Add(tev, (Vec1)s.GetRawValue<Vec1>(tev.Name).Clone());*/
} }
else if (ev.Unstamped is InstantEvent) { else if (ev.Unstamped is InstantEvent) {
var oev = ((InstantEvent)ev.Unstamped).Original; /*var oev = ((InstantEvent)ev.Unstamped).Original;
if (oev is Chart.Motion) { if (oev is Chart.Motion) {
var tev = (Chart.Motion)oev; var tev = (Chart.Motion)oev;
if (tev.Name.MainName != "judge") return; if (tev.Name != "judge") return;
var v0 = phMotions[tev]; var v0 = phMotions[tev];
var v1 = s.GetRawValue<Vec1>(tev.Name); var v1 = s.GetRawValue<Vec1>(tev.Name);
// var etor = new Evaluator(); // var etor = new Evaluator();
for (var vi = Mathf.Ceil(v0.Value); vi < v1.Value; vi++) { for (var vi = Mathf.Ceil(v0.Value); vi < v1.Value; vi++) {
var v = new Vec1(vi); var v = new Vec1(vi);
var t = MotionLerper.Delerp(v, ev.Time, v1, ev.Origin.Time, v0, tev.transition, tev.rate); var t = MotionLerper.Delerp(v, ev.Time, v1, ev.Origin.Time, v0, tev.transition, tev.rate);
/*CompiledRuleset.PatchJudge( CompiledRuleset.PatchJudge(
Event, ChartPlayer.cruleset.primary_judges[tev.Name.SubName], Event, ChartPlayer.cruleset.primary_judges[tev.Name.SubName],
t, etor, patchedJudgeEvents t, etor, patchedJudgeEvents
);*/ );
} }
phMotions.Remove(tev); phMotions.Remove(tev);
} }*/
} }
} }
} }
@@ -137,12 +150,12 @@ namespace Cryville.Crtr {
public override void MotionUpdate(byte ct, Chart.Motion ev) { public override void MotionUpdate(byte ct, Chart.Motion ev) {
base.MotionUpdate(ct, ev); base.MotionUpdate(ct, ev);
if (ct == 0) { if (ct == 0) {
if (ev.Name.MainName == "judge") { /*if (ev.Name == "judge") {
if (invalidated) return; if (invalidated) return;
if (ev.Name.SubName == null) if (ev.Name == null)
throw new InvalidOperationException(); throw new InvalidOperationException();
// judge.IssueImmediate(this, ev.Name.SubName, GetFramePoint(cs.Parent, cs.Track)); judge.IssueImmediate(this, ev.Name.SubName, GetFramePoint(cs.Parent, cs.Track));
} }*/
} }
else if (ct == 16) { else if (ct == 16) {
/*var etor = new EvalImpl(); /*var etor = new EvalImpl();

View File

@@ -1,66 +1,64 @@
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; }
else if (name == _var_true) { LoadNum(1); type = PdtInternalType.Number; value = _numbuf; }
else if (name == _var_false) { LoadNum(0); type = PdtInternalType.Number; value = _numbuf; }
else {
var id = new Identifier(name);
PropSrc prop; PropSrc prop;
string str; string str;
float num;
if (ContextEvent != null && ContextEvent.PropSrcs.TryGetValue(name, out prop)) { if (ContextEvent != null && ContextEvent.PropSrcs.TryGetValue(name, out prop)) {
prop.Get(out type, out value); prop.Get(out type, out value);
} }
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.scores.TryGetValue(name, out num)) {
type = PdtInternalType.Number;
LoadNum(num);
value = _numbuf;
RevokePotentialConstant();
}
else if (ContextJudge != null && ContextJudge.GetFormattedScoreStrings().TryGetValue(name, out str)) { else if (ContextJudge != null && ContextJudge.GetFormattedScoreStrings().TryGetValue(name, out str)) {
type = PdtInternalType.String; type = PdtInternalType.String;
value = GetBytes(str); value = GetBytes(str);
RevokePotentialConstant(); RevokePotentialConstant();
} }
else { else {
PropSrc.Arbitrary result; PropSrc.Arbitrary result = ContextCascadeLookup(name);
foreach (var cas in ContextCascade) { if (result != null) {
if (cas.TryGetValue(name, out result)) {
result.Get(out type, out value); result.Get(out type, out value);
return;
}
} }
else {
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;
} }
@@ -75,76 +73,106 @@ namespace Cryville.Crtr {
} }
return result; return result;
} }
protected override PdtOperator GetOperator(string name, int pc) { static readonly int _op_sep = IdentifierManager.SharedInstance.Request(",");
static readonly int _func_int_map = IdentifierManager.SharedInstance.Request("int_map");
protected override PdtOperator GetOperator(PdtOperatorSignature sig) {
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 +246,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 +257,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 +320,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 +442,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 +537,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,4 +1,5 @@
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;
@@ -7,11 +8,20 @@ using RBeatTime = Cryville.Crtr.BeatTime;
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 +45,22 @@ namespace Cryville.Crtr {
_cb(GetOperand(0).AsString()); _cb(GetOperand(0).AsString());
} }
} }
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 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

@@ -6,6 +6,8 @@ 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 {
@@ -31,9 +33,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 +44,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 +63,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 +92,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 +110,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 +147,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 {
return m_target;
} }
public void Start() { set {
if (m_target != value) {
m_target = value;
_invalidated = true;
}
}
}
public void Update() {
if (!_invalidated) return;
LoadProperties(); LoadProperties();
foreach (Transform c in _container) GameObject.Destroy(c.gameObject); foreach (Transform c in m_container) GameObject.Destroy(c.gameObject);
foreach (var c in _categories) { foreach (var c in _categories) {
var obj = GameObject.Instantiate<GameObject>(m_categoryPrefab); var obj = GameObject.Instantiate<GameObject>(m_categoryPrefab, m_container, false);
obj.transform.SetParent(_container, false); obj.GetComponent<PropertyCategoryPanel>().Load(c.Key, c.Value, Target);
obj.GetComponent<PropertyCategoryPanel>().Load(c.Key, c.Value, Settings.Default);
} }
} }
#pragma warning restore IDE0051
Dictionary<string, List<PropertyInfo>> _categories = null; 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

@@ -30,6 +30,8 @@ namespace Cryville.Crtr {
ChartPlayer.etor.ContextTransform = obj; ChartPlayer.etor.ContextTransform = obj;
ChartPlayer.etor.ContextEvent = context.Container; ChartPlayer.etor.ContextEvent = context.Container;
ChartPlayer.etor.Evaluate(GetPropOp(obj, p.Key), p.Value); ChartPlayer.etor.Evaluate(GetPropOp(obj, p.Key), p.Value);
ChartPlayer.etor.ContextEvent = null;
ChartPlayer.etor.ContextTransform = null;
} }
} }
} }
@@ -57,6 +59,8 @@ namespace Cryville.Crtr {
ChartPlayer.etor.ContextTransform = obj; ChartPlayer.etor.ContextTransform = obj;
ChartPlayer.etor.ContextEvent = context.Container; ChartPlayer.etor.ContextEvent = context.Container;
ChartPlayer.etor.Evaluate(GetPropOp(obj, p.Key), p.Value); ChartPlayer.etor.Evaluate(GetPropOp(obj, p.Key), p.Value);
ChartPlayer.etor.ContextEvent = null;
ChartPlayer.etor.ContextTransform = null;
} }
} }
Profiler.EndSample(); Profiler.EndSample();

View File

@@ -116,6 +116,8 @@ namespace Cryville.Crtr {
ChartPlayer.etor.ContextTransform = a; ChartPlayer.etor.ContextTransform = a;
ChartPlayer.etor.ContextEvent = h.Container; ChartPlayer.etor.ContextEvent = h.Container;
ChartPlayer.etor.Evaluate(_op, _exp); ChartPlayer.etor.Evaluate(_op, _exp);
ChartPlayer.etor.ContextEvent = null;
ChartPlayer.etor.ContextTransform = null;
return _flag ? a : null; return _flag ? a : null;
} }
} }

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

@@ -37,3 +37,6 @@ using System.Diagnostics.CodeAnalysis;
// Index operator not supported // Index operator not supported
[assembly: SuppressMessage("Style", "IDE0056")] [assembly: SuppressMessage("Style", "IDE0056")]
// Local function not supported
[assembly: SuppressMessage("Style", "IDE0039")]

Binary file not shown.

View File

@@ -0,0 +1,24 @@
#if UNITY_EDITOR
using System;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
public class MsvcStdextWorkaround : IPreprocessBuildWithReport {
const string kWorkaroundFlag = "/D_SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS";
public int callbackOrder => 0;
public void OnPreprocessBuild(BuildReport report) {
var clEnv = Environment.GetEnvironmentVariable("_CL_");
if (string.IsNullOrEmpty(clEnv)) {
Environment.SetEnvironmentVariable("_CL_", kWorkaroundFlag);
}
else if (!clEnv.Contains(kWorkaroundFlag)) {
clEnv += " " + kWorkaroundFlag;
Environment.SetEnvironmentVariable("_CL_", clEnv);
}
}
}
#endif // UNITY_EDITOR

View File

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

Binary file not shown.

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: d3142009b74dda042a75e9b808dde66d
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1 @@
../../Local/default_resources.zip