58 Commits

Author SHA1 Message Date
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
40 changed files with 1207 additions and 525 deletions

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

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

View File

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

View File

@@ -3,26 +3,33 @@
/// The identifiers of the internal types of PDT. /// The identifiers of the internal types of PDT.
/// </summary> /// </summary>
public static class PdtInternalType { public static class PdtInternalType {
internal readonly static int Error = "error".GetHashCode(); /// <summary>
/// Error type.
/// </summary>
public readonly static int Error = 0x00525245;
/// <summary> /// <summary>
/// Array of a same variable-length type, with a suffix indicating the element count and the element type. /// Array of a same variable-length type, with a suffix indicating the element count and the element type.
/// </summary> /// </summary>
public readonly static int Array = "array".GetHashCode(); public readonly static int Array = 0x00525241;
/// <summary>
/// Null type.
/// </summary>
public readonly static int Null = 0x4c4c554e;
/// <summary> /// <summary>
/// IEEE 754 32-bit floating-point number. /// IEEE 754 32-bit floating-point number.
/// </summary> /// </summary>
public readonly static int Number = "number".GetHashCode(); public readonly static int Number = 0x004d554e;
/// <summary> /// <summary>
/// A sequence of UTF-16 code units, with a prefix indicating the number of the code units. /// A sequence of UTF-16 code units, with a prefix indicating the number of the code units.
/// </summary> /// </summary>
public readonly static int String = "string".GetHashCode(); public readonly static int String = 0x00525453;
/// <summary> /// <summary>
/// A sequence of UTF-16 code units, with a prefix indicating the number of the code units, representing the name of an undefined variable. /// A sequence of UTF-16 code units, with a prefix indicating the number of the code units, representing the name of an undefined variable.
/// </summary> /// </summary>
public readonly static int Undefined = "undefined".GetHashCode(); public readonly static int Undefined = 0x00444e55;
/// <summary> /// <summary>
/// Vector of a same constant-length type, with a suffix indicating the element type. /// Vector of a same constant-length type, with a suffix indicating the element type.
/// </summary> /// </summary>
public readonly static int Vector = "vector".GetHashCode(); public readonly static int Vector = 0x00434556;
} }
} }

View File

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

View File

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

View File

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

@@ -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,18 @@ 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<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; 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));
@@ -46,7 +46,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 +77,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

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

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

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

@@ -3,6 +3,7 @@
using Cryville.Common; using Cryville.Common;
using Cryville.Common.Plist; using Cryville.Common.Plist;
using Cryville.Common.Unity.Input;
using Cryville.Crtr.Event; using Cryville.Crtr.Event;
using Newtonsoft.Json; using Newtonsoft.Json;
using System; using System;
@@ -62,10 +63,12 @@ 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;
InputProxy inputProxy;
~ChartPlayer() { ~ChartPlayer() {
Dispose(); Dispose();
} }
@@ -102,6 +105,7 @@ namespace Cryville.Crtr {
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 (Input.GetKeyDown(KeyCode.Return)) TogglePlay();
if (started) { if (started) {
@@ -112,16 +116,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);
@@ -242,6 +239,12 @@ namespace Cryville.Crtr {
UnityEngine.Profiling.Profiler.GetTotalReservedMemory() UnityEngine.Profiling.Profiler.GetTotalReservedMemory()
#endif #endif
); );
if (started) sttext += string.Format(
"\nSTime: {0:R}\nATime: {1:R}\nITime: {2:R}",
cbus.Time,
Game.AudioClient.Position - atime0,
inputProxy.GetTimestampAverage()
);
if (judge != null) sttext += "\n== Scores ==\n" + judge.GetFullFormattedScoreString(); if (judge != null) sttext += "\n== Scores ==\n" + judge.GetFullFormattedScoreString();
status.text = sttext; status.text = sttext;
} }
@@ -328,23 +331,6 @@ namespace Cryville.Crtr {
FileInfo skinFile = new FileInfo( FileInfo skinFile = new FileInfo(
Game.GameDataPath + "/skins/" + Settings.Default.LoadSkin Game.GameDataPath + "/skins/" + Settings.Default.LoadSkin
); );
Logger.Log("main", 0, "Load/MainThread", "Loading textures...");
texloadtimer = new diag::Stopwatch();
texloadtimer.Start();
texs = new Dictionary<string, Texture2D>();
var flist = skinFile.Directory.GetFiles("*.png");
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);
#endif
}
#if NO_THREAD #if NO_THREAD
texloadtimer.Stop(); texloadtimer.Stop();
Logger.LogFormat("main", 0, "Load/MainThread", "Textures loaded successfully ({0}ms)", texloadtimer.Elapsed.TotalMilliseconds); Logger.LogFormat("main", 0, "Load/MainThread", "Textures loaded successfully ({0}ms)", texloadtimer.Elapsed.TotalMilliseconds);
@@ -362,6 +348,23 @@ namespace Cryville.Crtr {
skinFile = skinFile, skinFile = skinFile,
}); });
#endif #endif
Logger.Log("main", 0, "Load/MainThread", "Loading textures...");
texloadtimer = new diag::Stopwatch();
texloadtimer.Start();
texs = new Dictionary<string, Texture2D>();
var flist = skinFile.Directory.GetFiles("*.png");
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);
#endif
}
} }
void Prehandle() { void Prehandle() {
@@ -381,7 +384,23 @@ 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 = new InputProxy(pruleset, judge);
foreach (var i in Game.InputManager._handlers) {
/*if (i is UnityKeyHandler<UnityKeyboardReceiver>) {
inputProxy.Set(new InputProxyEntry { Source = new InputSource { Handler = i, Type = (int)KeyCode.Z }, Target = "track0" });
inputProxy.Set(new InputProxyEntry { Source = new InputSource { Handler = i, Type = (int)KeyCode.X }, Target = "track1" });
inputProxy.Set(new InputProxyEntry { Source = new InputSource { Handler = i, Type = (int)KeyCode.Comma }, Target = "track2" });
inputProxy.Set(new InputProxyEntry { Source = new InputSource { Handler = i, Type = (int)KeyCode.Period }, Target = "track3" });
break;
}*/
if (i is UnityMouseHandler) {
inputProxy.Set(new InputProxyEntry { Source = new InputSource { Handler = i, Type = 0 }, Target = "screen_x" });
break;
}
}
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,8 +408,9 @@ 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) {
@@ -408,7 +428,7 @@ namespace Cryville.Crtr {
if (bbus != null) bbus.Dispose(); if (bbus != null) bbus.Dispose();
if (tbus != null) tbus.Dispose(); if (tbus != null) tbus.Dispose();
if (nbus != null) nbus.Dispose(); if (nbus != null) nbus.Dispose();
// Game.InputManager.Deactivate(); inputProxy.Deactivate();
foreach (var t in texs) Texture.Destroy(t.Value); foreach (var t in texs) Texture.Destroy(t.Value);
Logger.Log("main", 1, "Game", "Stopped"); Logger.Log("main", 1, "Game", "Stopped");
} }
@@ -484,11 +504,11 @@ 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);
cbus.AttachSystems(pskin, judge); cbus.AttachSystems(pskin, judge);
Logger.Log("main", 0, "Load/WorkerThread", "Attaching handlers"); Logger.Log("main", 0, "Load/WorkerThread", "Attaching handlers");
var ch = new ChartHandler(chart, dir); var ch = new ChartHandler(chart, dir);
@@ -499,7 +519,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);

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

@@ -64,7 +64,7 @@ namespace Cryville.Crtr.Config {
}); });
if (ruleset.format != 1) throw new FormatException("Invalid ruleset file version"); if (ruleset.format != 1) throw new FormatException("Invalid ruleset file version");
ruleset.LoadPdt(dir); ruleset.LoadPdt(dir);
_proxy = new InputProxy(ruleset.Root); _proxy = new InputProxy(ruleset.Root, null);
foreach (var i in ruleset.Root.inputs) { foreach (var i in ruleset.Root.inputs) {
var e = GameObject.Instantiate(m_prefabInputConfigEntry).GetComponent<InputConfigEntry>(); var e = GameObject.Instantiate(m_prefabInputConfigEntry).GetComponent<InputConfigEntry>();
e.transform.SetParent(m_entryList.transform); e.transform.SetParent(m_entryList.transform);

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

@@ -94,10 +94,11 @@ 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,
}); });
} }

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 System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine;
using Logger = Cryville.Common.Logger;
namespace Cryville.Crtr { namespace Cryville.Crtr {
public class InputProxy { public class InputProxy {
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,36 @@ 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 Set(InputProxyEntry proxy) { public void Set(InputProxyEntry proxy) {
var name = proxy.Target; var name = proxy.Target;
if (_hash1.ContainsKey(name)) Remove(proxy); if (_tproxies.ContainsKey(name)) Remove(proxy);
if (_use[proxy.Target] > 0) if (_use[proxy.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); proxy.Source.Value.Handler.OnInput -= OnInput; // Prevent duplicated hooks, no exception will be thrown
_hash2.Add(proxy.Source.Value, proxy); proxy.Source.Value.Handler.OnInput += OnInput;
_tproxies.Add(proxy.Target, proxy);
_sproxies.Add(proxy.Source.Value, proxy);
IncrementUseRecursive(name); IncrementUseRecursive(name);
IncrementReversedUseRecursive(name); IncrementReversedUseRecursive(name);
} }
} }
void Remove(InputProxyEntry proxy) { void Remove(InputProxyEntry proxy) {
var name = proxy.Target; var name = proxy.Target;
_hash2.Remove(_hash1[name].Source.Value); proxy.Source.Value.Handler.OnInput -= OnInput;
_hash1.Remove(name); _sproxies.Remove(_tproxies[name].Source.Value);
_tproxies.Remove(name);
DecrementUseRecursive(name); DecrementUseRecursive(name);
DecrementReversedUseRecursive(name); DecrementReversedUseRecursive(name);
} }
public bool IsUsed(InputSource src) { public bool IsUsed(InputSource src) {
return _hash2.ContainsKey(src); return _sproxies.ContainsKey(src);
} }
void IncrementUseRecursive(string name) { void IncrementUseRecursive(string name) {
BroadcastProxyChanged(name); BroadcastProxyChanged(name);
@@ -80,8 +97,105 @@ 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, 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(); }
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));
}
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);
_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) {
var def = _ruleset.inputs[target];
if (def.pass != null) {
foreach (var p in def.pass) {
_etor.ContextCascadeInsert();
_arbop.Name = _var_value;
_etor.Evaluate(_arbop, p.Value);
OnInput(id, p.Key, ft, tt);
_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 +215,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,185 @@
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;
}
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);
index = BinarySearch(actlist, ev.StartClip, def.prop);
if (index < 0) index = ~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);
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);
}
}
}
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 +188,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

@@ -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,104 @@ 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));
} }
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 +244,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 +255,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 +318,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 +440,77 @@ 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;
}
}
#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 +519,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

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

@@ -13,14 +13,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 +56,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

@@ -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")]