98 Commits

Author SHA1 Message Date
a4fdb97424 Fix IL2CPP incompatibility. 2022-11-16 17:45:52 +08:00
735a85b914 Add error notice for mcz files. 2022-11-16 17:44:56 +08:00
be0c71702b Ignore Local directory. 2022-11-16 17:44:18 +08:00
535959a6ed Use symbolic link for default resources. 2022-11-16 17:43:19 +08:00
ae37b27dc0 Remove default resources temporarily. 2022-11-16 17:42:49 +08:00
80cc5fdbda Pull down scroll velocity option. Add property categories for ruleset config. 2022-11-16 17:30:33 +08:00
87e406e903 Cleanup. 2022-11-16 12:08:11 +08:00
f04d0ec299 Loads ruleset config before worker. Implement skin option of ruleset config. 2022-11-16 11:45:28 +08:00
a19057f869 Uses original cover file name on import. 2022-11-16 11:42:51 +08:00
d0d981b790 Add string property value panel. 2022-11-16 11:40:58 +08:00
c95ae92ba8 Fix input proxy not deactivated on stop. 2022-11-16 00:28:10 +08:00
31e9f1352b Redefine stack and propagation of judge. 2022-11-16 00:27:38 +08:00
9974b25377 Adjust config scene layout. 2022-11-16 00:25:25 +08:00
852c93c6d0 Add generic ruleset config. 2022-11-16 00:25:08 +08:00
15e66d29c4 Code cleanup. 2022-11-15 20:14:36 +08:00
3d5ea4f056 Fix null vector passing. 2022-11-15 20:14:27 +08:00
1772c90c2f Fix texture wrap mode. 2022-11-15 20:12:24 +08:00
53ada70dda Remove unexpected using. 2022-11-15 18:08:13 +08:00
a8ab73ac65 Fix chart player dispose. 2022-11-15 17:29:10 +08:00
35ac57bfba Code cleanup. 2022-11-15 17:28:42 +08:00
945f9ca7d1 Implement input config scene loading and saving. 2022-11-15 17:27:51 +08:00
d2b2834a60 Implement input config loading and saving. 2022-11-15 17:26:00 +08:00
f82e0ce9ef Add ruleset config. 2022-11-15 17:22:13 +08:00
5444ea7186 Add popup for exception on worker thread. 2022-11-15 17:20:00 +08:00
3a54d2023f Pull down popup from common. 2022-11-15 17:17:30 +08:00
cb3e3e5f28 Remove obsolete NO_THREAD symbol. 2022-11-15 15:25:53 +08:00
174f616e5c Add error notice popup for resource import. 2022-11-15 13:31:39 +08:00
0f8bb5f1f6 Fix and add popup. 2022-11-15 13:30:40 +08:00
2d35e3177b Update ruleset name for Malody extension. 2022-11-15 12:12:59 +08:00
7b1f639412 Code cleanup. 2022-11-15 12:12:29 +08:00
fcc9935325 Fix input config. 2022-11-15 12:10:54 +08:00
8b29cd2893 Generalize settings panel. 2022-11-15 12:10:34 +08:00
f44d9546e1 Implement config category switch. 2022-11-15 12:09:29 +08:00
1d1d2646c4 Passes chart detail on open and config. 2022-11-15 12:08:48 +08:00
6444de41a2 Fix property value panel layout update. 2022-11-15 12:06:00 +08:00
ea856f3339 Code cleanup. 2022-11-15 11:05:10 +08:00
74b1a5485b Fix resource import interrupted when item not valid. 2022-11-15 09:15:53 +08:00
975b48e61e Add leave_timing and contact_timing function. 2022-11-14 23:28:32 +08:00
9e0bf024d7 Fix judge propagation. 2022-11-14 23:28:14 +08:00
d2ff168e25 Add invalidation for property source. Fix cache lock for scores. 2022-11-14 16:38:15 +08:00
05664a2994 Code cleanup. 2022-11-14 16:05:44 +08:00
ba6166068b Implement score update. 2022-11-14 16:05:21 +08:00
d5d6465806 Implement compound operator patching. 2022-11-14 16:03:35 +08:00
1f57c299a2 Add some judge functions. Code cleanup. 2022-11-14 13:59:26 +08:00
49431e888c Implement judge feed, pass, cleanup, and miss. Add update score stub. 2022-11-14 13:57:02 +08:00
c31c16792c Add judge priority. 2022-11-14 13:55:10 +08:00
7ce73186ae Make Unity timestamps realtime critical. (2) 2022-11-14 13:49:29 +08:00
318a6705be Fix collapse operators and boolean property operator. 2022-11-14 11:28:10 +08:00
7fca09ff49 Code cleanup. 2022-11-13 13:42:08 +08:00
eff8dd2c35 Remove temporary debug logs. 2022-11-12 17:50:31 +08:00
252853f4d4 Add time debug info. Fix sleep duration for audio sync. 2022-11-12 17:02:21 +08:00
a47faf0049 Implement force tick and sync time for input proxy. 2022-11-12 17:01:10 +08:00
604398cae2 Add judge feed and cleanup stub. 2022-11-12 16:56:27 +08:00
457d491d89 Update internal judge event data structure. 2022-11-12 16:53:57 +08:00
0c8e24b079 Make Unity timestamps realtime critical. 2022-11-12 16:49:01 +08:00
fcc159ab6c Code cleanup. 2022-11-12 01:02:30 +08:00
f7454eb514 Add active counting for input sources for force tick. 2022-11-12 01:02:00 +08:00
35040e4ebd Update input feeding logic. 2022-11-12 01:00:31 +08:00
d10e6ea18b Implement judge event preparation. 2022-11-12 00:57:41 +08:00
8af09a7167 Prevents duplicated event hooks. 2022-11-12 00:52:44 +08:00
bca71982e5 Code cleanup. 2022-11-11 17:46:10 +08:00
0b17520bfd Modify logic for "not" operator. 2022-11-11 17:36:52 +08:00
990a42f71b Evaluates clipping of judge events on load. 2022-11-11 10:36:00 +08:00
383fca1a8e Modify logic for "at" operator. 2022-11-11 10:02:43 +08:00
cf00bd8db0 Implement input name evaluation. Implement context state. 2022-11-11 10:02:01 +08:00
84e4e3514d Reorganize event priority. 2022-11-11 09:57:08 +08:00
5ac0a558e0 Delay input name evaluation in judge definition. 2022-11-11 00:44:44 +08:00
20f4de3832 Implement int_map function. Remove "long operator" concept. 2022-11-11 00:36:16 +08:00
296d5bb615 Reads score operation as structure. 2022-11-11 00:34:30 +08:00
c33186086c Tokenize ruleset keys. Remove MotionName. 2022-11-09 14:01:27 +08:00
55efc7a428 Code cleanup. 2022-11-09 13:53:53 +08:00
1f621082c6 Fix item not reloaded on resource import. 2022-11-09 13:51:00 +08:00
f311eb5e8d Implement InputProxy. 2022-11-07 12:21:50 +08:00
0d7018c964 Fix import error due to invalid file name. (Amend) 2022-11-07 12:19:31 +08:00
a401585f07 Optimize context cascade in PDT evaluator. 2022-11-07 12:15:22 +08:00
7e025f9268 Fix import error due to invalid file name. 2022-11-07 12:13:07 +08:00
65d86ed72d Modify logic for "and" and "or" operator and in_area function. Add null marshaling for input proxy. 2022-11-06 14:52:05 +08:00
71a33c0b43 Code cleanup. 2022-11-06 14:25:02 +08:00
f33560daba Add in_area function. (Amend) 2022-11-06 14:20:28 +08:00
b4fa5849ae Add error type and null type. 2022-11-06 14:19:00 +08:00
cfcc371226 Add in_area function. 2022-11-06 13:48:23 +08:00
c635d89c6a Fix delegate invocation by input proxy. 2022-11-06 13:47:48 +08:00
fc04071b53 Fix number marshaling for PDT variable memory. 2022-11-06 13:46:23 +08:00
2c74296532 Add abs function. Fix "at" operator. 2022-11-06 13:21:15 +08:00
b92a21951d Transforms input from screen point to world point. 2022-11-06 13:20:26 +08:00
d58e255b3f Update operator exception handling. 2022-11-06 12:12:51 +08:00
01a4214265 Fix exception handling on failure to get operator. 2022-11-06 12:11:55 +08:00
15e8a2a2a8 Fix typo in PdtVariableMemory. 2022-11-06 12:10:32 +08:00
57fd2c0c0d Add lock for input proxy. 2022-11-06 00:55:56 +08:00
8f98cb63cb Implement input proxy. Change input callback delegate to event. Prevents repeated (de)activation. 2022-11-06 00:50:09 +08:00
7f02b75b29 Move arbitrary property operator to PropOp. 2022-11-06 00:30:36 +08:00
9d4f938675 Move InputEvent to InputManager.cs. 2022-11-06 00:20:01 +08:00
c3dc6b9a03 Modify PDT type identifiers to avoid hash collision. 2022-11-05 20:00:15 +08:00
a422f06221 Add "at" operator. 2022-11-05 17:41:54 +08:00
8e3bd87667 Reverse context cascade searching order. 2022-11-05 17:06:35 +08:00
324c887539 Retrieve identifier names for debugging. 2022-11-01 17:36:18 +08:00
2c9be2ef1e Introduce IdentifierManager to improve PDT evaluator performance. 2022-11-01 13:47:04 +08:00
3bfc7eb643 Logic cleanup. 2022-11-01 11:28:48 +08:00
77 changed files with 1847 additions and 829 deletions

1
.gitignore vendored
View File

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

Binary file not shown.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -34,6 +34,16 @@ namespace Cryville.Common.Pdt {
}
}
/// <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.
/// </summary>
/// <param name="exp">The expression to optimize.</param>
@@ -47,7 +57,7 @@ namespace Cryville.Common.Pdt {
var i = _rip.Value;
if (i is PdtInstruction.Operate) {
int fc0 = _framecount;
int fc1 = ((PdtInstruction.Operate)i).ParamCount;
int fc1 = ((PdtInstruction.Operate)i).Signature.ParamCount;
try { i.Execute(this); } catch (Exception) { }
if (fc0 - _framecount == fc1) {
unsafe {
@@ -137,7 +147,7 @@ namespace Cryville.Common.Pdt {
_goffset += value.Length;
}
}
internal unsafe void PushVariable(ref string name) {
internal unsafe void PushVariable(int name) {
fixed (StackFrame* frame = &_stack[_framecount++]) {
byte[] 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="type">The type 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);
internal void Operate(ref string name, int pc) {
protected abstract void GetVariable(int name, out int type, out byte[] value);
internal void Operate(PdtOperatorSignature sig) {
PdtOperator op;
try { op = GetOperator(name, pc); }
catch (Exception) { _framecount -= pc; return; }
Operate(op, pc);
try { op = GetOperator(sig); }
catch (Exception) {
for (int i = 0; i < sig.ParamCount; i++)
DiscardStack();
throw;
}
Operate(op, sig.ParamCount);
}
/// <summary>
/// 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>
/// <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>
protected abstract PdtOperator GetOperator(string name, int pc);
protected abstract PdtOperator GetOperator(PdtOperatorSignature sig);
unsafe void Operate(PdtOperator op, int pc, bool noset = false) {
fixed (byte* pmem = _mem) {
op.Begin(this);
@@ -179,7 +193,7 @@ namespace Cryville.Common.Pdt {
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) {
var frame = _stack[--_framecount];
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="param">The top frame in the stack as the parameter.</param>
/// <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) {
fixed (StackFrame* frame = &_stack[_framecount++]) {
frame->Type = type;

View File

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

View File

@@ -3,26 +3,33 @@
/// The identifiers of the internal types of PDT.
/// </summary>
public static class PdtInternalType {
internal readonly static int Error = "error".GetHashCode();
/// <summary>
/// Error type.
/// </summary>
public readonly static int Error = 0x00525245;
/// <summary>
/// Array of a same variable-length type, with a suffix indicating the element count and the element type.
/// </summary>
public readonly static int Array = "array".GetHashCode();
public readonly static int Array = 0x00525241;
/// <summary>
/// Null type.
/// </summary>
public readonly static int Null = 0x4c4c554e;
/// <summary>
/// IEEE 754 32-bit floating-point number.
/// </summary>
public readonly static int Number = "number".GetHashCode();
public readonly static int Number = 0x004d554e;
/// <summary>
/// A sequence of UTF-16 code units, with a prefix indicating the number of the code units.
/// </summary>
public readonly static int String = "string".GetHashCode();
public readonly static int String = 0x00525453;
/// <summary>
/// A sequence of UTF-16 code units, with a prefix indicating the number of the code units, representing the name of an undefined variable.
/// </summary>
public readonly static int Undefined = "undefined".GetHashCode();
public readonly static int Undefined = 0x00444e55;
/// <summary>
/// Vector of a same constant-length type, with a suffix indicating the element type.
/// </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) {
_prmem = prmem;
_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 (_rfreq) _etor.DiscardStack();
throw new InvalidOperationException("Evaluation failed");
@@ -74,4 +77,48 @@ namespace Cryville.Common.Pdt {
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;
}
/// <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.
/// </summary>
/// <param name="dest">The destination buffer.</param>
@@ -42,28 +49,33 @@ namespace Cryville.Common.Pdt {
/// <summary>
/// Gets the memory of the span as a number.
/// </summary>
/// <param name="offset">The offset on the span to start reading from.</param>
/// <returns>A number.</returns>
/// <exception cref="InvalidCastException">The span does not represent a number.</exception>
public float AsNumber() {
if (Type != PdtInternalType.Number)
/// <exception cref="InvalidCastException">The span at the offset does not represent a number.</exception>
public float AsNumber(int offset = 0) {
if (Type != PdtInternalType.Number && Type != PdtInternalType.Vector)
throw new InvalidCastException("Not a number");
float value;
byte* ptr = (byte*)&value;
for (int i = 0; i < sizeof(float); i++)
ptr[i] = _ptr[i];
ptr[i] = _ptr[i + offset];
return value;
}
/// <summary>
/// Sets the memory of the span to a number.
/// </summary>
/// <param name="value">The number.</param>
/// <exception cref="InvalidCastException">The span does not represent a number.</exception>
public void SetNumber(float value) {
if (Type != PdtInternalType.Number)
/// <param name="offset">The offset from the start of the span.</param>
/// <exception cref="InvalidCastException">The span at the offset does not represent a number.</exception>
/// <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");
if (Length < sizeof(float) + offset)
throw new InvalidOperationException("Frame length not sufficient");
byte* ptr = (byte*)&value;
for (int i = 0; i < sizeof(float); i++)
_ptr[i] = ptr[i];
_ptr[i + offset] = ptr[i];
}
/// <summary>
/// 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>
/// <returns>The name of an undefined identifier.</returns>
/// <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)
throw new InvalidCastException("Not an identifier");
var len = *(int*)(_ptr + offset);
return new string((char*)(_ptr + offset + sizeof(int)), 0, len);
return *(int*)(_ptr + offset);
}
internal void* TrustedAsOfLength(int len) {
if (Length < len)
@@ -119,7 +130,7 @@ namespace Cryville.Common.Pdt {
/// <param name="pc">The item count of the array.</param>
/// <exception cref="InvalidCastException">The span does not represent an array.</exception>
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");
arrtype = *(int*)(_ptr + Length - sizeof(int));
if (Type == PdtInternalType.Array) pc = *(int*)(_ptr + Length - 2 * sizeof(int));

View File

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

View File

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

View File

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

View File

@@ -4,7 +4,7 @@ using UnityEngine;
namespace Cryville.Common.Unity.Input {
public delegate void InputEventDelegate(InputIdentifier id, InputVector vec);
public abstract class InputHandler : IDisposable {
public InputEventDelegate Callback { private get; set; }
public event InputEventDelegate OnInput;
~InputHandler() {
Dispose(false);
@@ -14,15 +14,27 @@ namespace Cryville.Common.Unity.Input {
GC.SuppressFinalize(this);
}
public abstract void Activate();
public abstract void Deactivate();
public bool Activated { get; private set; }
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 bool IsNullable(int type);
public abstract byte GetDimension(int type);
public abstract string GetTypeName(int type);
public abstract double GetCurrentTimestamp();
protected void OnInput(int type, int id, InputVector vec) {
if (Callback != null) Callback(new InputIdentifier { Source = new InputSource { Handler = this, Type = type }, Id = id }, vec);
protected void Feed(int type, int id, InputVector 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 double Time { get; set; }
public bool IsNull { get; set; }

View File

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

View File

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

View File

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

View File

@@ -9,19 +9,19 @@ namespace Cryville.Common.Unity.Input {
public UnityKeyHandler() { }
public override void Activate() {
protected override void ActivateImpl() {
receiver = new GameObject("__keyrecv__");
recvcomp = receiver.AddComponent<T>();
recvcomp.SetCallback(OnInput);
recvcomp.SetCallback(Feed);
}
public override void Deactivate() {
protected override void DeactivateImpl() {
if (receiver) GameObject.Destroy(receiver);
}
public override void Dispose(bool disposing) {
if (disposing) {
Deactivate();
DeactivateImpl();
}
}
@@ -38,7 +38,7 @@ namespace Cryville.Common.Unity.Input {
}
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);
void Update() {
double time = Time.timeAsDouble;
double time = Time.realtimeSinceStartupAsDouble;
foreach (var k in Keys) {
Callback(k, 0, new InputVector(time, Vector3.zero));
}
@@ -64,7 +64,7 @@ namespace Cryville.Common.Unity.Input {
void OnGUI() {
var e = Event.current;
if (e.keyCode == KeyCode.None) return;
double time = Time.timeAsDouble;
double time = Time.realtimeSinceStartupAsDouble;
var key = (int)e.keyCode;
switch (e.type) {
case EventType.KeyDown:
@@ -92,7 +92,7 @@ namespace Cryville.Common.Unity.Input {
}
void OnGUI() {
var e = Event.current;
double time = Time.timeAsDouble;
double time = Time.realtimeSinceStartupAsDouble;
var key = e.button;
switch (e.type) {
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.AddComponent<UnityMouseReceiver>().SetHandler(this);
}
public override void Deactivate() {
protected override void DeactivateImpl() {
if (receiver) GameObject.Destroy(receiver);
}
public override void Dispose(bool disposing) {
if (disposing) {
Deactivate();
DeactivateImpl();
}
}
@@ -45,7 +45,7 @@ namespace Cryville.Common.Unity.Input {
}
public override double GetCurrentTimestamp() {
return Time.timeAsDouble;
return Time.realtimeSinceStartupAsDouble;
}
public class UnityMouseReceiver : MonoBehaviour {
@@ -54,10 +54,9 @@ namespace Cryville.Common.Unity.Input {
handler = h;
}
void Update() {
double time = Time.timeAsDouble;
Vector2 pos = unity::Input.mousePosition;
pos.y = Screen.height - pos.y;
handler.OnInput(0, 0, new InputVector(time, pos));
double time = Time.realtimeSinceStartupAsDouble;
Vector3 pos = UnityCameraUtils.ScreenToWorldPoint(unity::Input.mousePosition);
handler.Feed(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.AddComponent<UnityPointerReceiver>().SetHandler(this);
}
public override void Deactivate() {
protected override void DeactivateImpl() {
if (receiver) GameObject.Destroy(receiver);
}
public override void Dispose(bool disposing) {
if (disposing) {
Deactivate();
DeactivateImpl();
}
}
@@ -45,7 +45,7 @@ namespace Cryville.Common.Unity.Input {
}
public override double GetCurrentTimestamp() {
return Time.timeAsDouble;
return Time.realtimeSinceStartupAsDouble;
}
public class UnityPointerReceiver : MonoBehaviour {
@@ -54,18 +54,17 @@ namespace Cryville.Common.Unity.Input {
handler = h;
}
void Update() {
double time = Time.timeAsDouble;
double time = Time.realtimeSinceStartupAsDouble;
for (int i = 0; i < unity::Input.touchCount; i++) {
var t = unity::Input.GetTouch(i);
Vector2 pos = t.position;
pos.y = Screen.height - pos.y;
Vector2 pos = UnityCameraUtils.ScreenToWorldPoint(t.position);
var vec = new InputVector(time, pos);
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) {
handler.OnInput(0, t.fingerId, vec);
handler.OnInput(0, t.fingerId, new InputVector(time));
handler.Feed(0, t.fingerId, vec);
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_PENTAPFEEDBACK = 0x00000008;
public const int TABLET_DISABLE_PENBARRELFEEDBACK = 0x00000010;
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);
NativeMethods.SetProp(hMainWindow, PRESS_AND_HOLD_ATOM,
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) {
NativeMethods.RemoveProp(hMainWindow, PRESS_AND_HOLD_ATOM);
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";
@@ -158,7 +142,7 @@ namespace Cryville.Common.Unity.Input {
}
public override void Dispose(bool disposing) {
Deactivate();
DeactivateImpl();
if (usePointerMessage)
NativeMethods.EnableMouseInPointer(false);
Instance = null;
@@ -230,7 +214,7 @@ namespace Cryville.Common.Unity.Input {
NativeMethods.POINT p = rawpinfo.ptPixelLocation;
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;
@@ -244,7 +228,7 @@ namespace Cryville.Common.Unity.Input {
default: type = 0; break;
}
if (rawpinfo.pointerFlags.HasFlag(NativeMethods.POINTER_FLAGS.POINTER_FLAG_CANCELED)) {
OnInput(type, id, new InputVector(time));
Feed(type, id, new InputVector(time));
return;
}
@@ -253,11 +237,11 @@ namespace Cryville.Common.Unity.Input {
switch ((WindowMessages)msg) {
case WindowMessages.WM_POINTERDOWN:
case WindowMessages.WM_POINTERUPDATE:
OnInput(type, id, vec);
Feed(type, id, vec);
break;
case WindowMessages.WM_POINTERUP:
OnInput(type, id, vec);
OnInput(type, id, new InputVector(time));
Feed(type, id, vec);
Feed(type, id, new InputVector(time));
break;
}
}
@@ -316,7 +300,7 @@ namespace Cryville.Common.Unity.Input {
Y = touch.y / 100
};
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;
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) ||
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)) {
OnInput(255, id, vec);
OnInput(255, id, new InputVector(time));
Feed(255, id, vec);
Feed(255, id, new InputVector(time));
}
}

View File

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

View File

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

View File

@@ -200,8 +200,7 @@ namespace Cryville.Common.Unity.UI {
void GenerateLine(int index, int line) {
for (int j = 0; j < LineItemCount; j++) {
var child = GameObject.Instantiate(m_itemTemplate);
child.transform.SetParent(transform, false);
var child = GameObject.Instantiate(m_itemTemplate, transform, false);
lines[index][j] = child;
}
LoadLine(index, line);

View File

@@ -60,10 +60,10 @@ namespace Cryville.Crtr.Browsing {
}
}
public void OnPlay() {
Master.Open(_id);
Master.Open(_id, _data);
}
public void OnConfig() {
Master.OpenConfig(_id);
Master.OpenConfig(_id, _data);
}
}
}

View File

@@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEngine;
using Logger = Cryville.Common.Logger;
namespace Cryville.Crtr.Browsing {
internal class LegacyResourceManager : IResourceManager<ChartDetail> {
@@ -58,24 +59,27 @@ namespace Cryville.Crtr.Browsing {
public ResourceItemMeta GetItemMeta(int id) {
var item = items[id];
AsyncDelivery<Texture2D> cover = null;
var coverFile = item.GetFiles("cover.*");
if (coverFile.Length > 0) {
cover = new AsyncDelivery<Texture2D>();
var task = new LoadTextureTask(Game.FileProtocolPrefix + coverFile[0].FullName, cover.Deliver);
cover.CancelSource = task.Cancel;
Game.NetworkTaskWorker.SubmitNetworkTask(task);
}
var meta = new ChartMeta();
string name = item.Name;
string desc = "(Unknown)";
var metaFile = new FileInfo(item.FullName + "/meta.json");
if (metaFile.Exists) {
using (var reader = new StreamReader(metaFile.FullName)) {
var meta = JsonConvert.DeserializeObject<ChartMeta>(reader.ReadToEnd());
meta = JsonConvert.DeserializeObject<ChartMeta>(reader.ReadToEnd());
name = meta.song.name;
desc = meta.chart.name;
}
}
AsyncDelivery<Texture2D> cover = null;
if (meta.cover != null && meta.cover != "") {
var coverFile = item.GetFiles(meta.cover);
if (coverFile.Length > 0) {
cover = new AsyncDelivery<Texture2D>();
var task = new LoadTextureTask(Game.FileProtocolPrefix + coverFile[0].FullName, cover.Deliver);
cover.CancelSource = task.Cancel;
Game.NetworkTaskWorker.SubmitNetworkTask(task);
}
}
return new ResourceItemMeta {
IsDirectory = false,
Icon = cover,
@@ -86,21 +90,23 @@ namespace Cryville.Crtr.Browsing {
public ChartDetail GetItemDetail(int id) {
var item = items[id];
AsyncDelivery<Texture2D> cover = null;
var coverFile = item.GetFiles("cover.*");
if (coverFile.Length > 0) {
cover = new AsyncDelivery<Texture2D>();
var task = new LoadTextureTask(Game.FileProtocolPrefix + coverFile[0].FullName, cover.Deliver);
cover.CancelSource = task.Cancel;
Game.NetworkTaskWorker.SubmitNetworkTask(task);
}
ChartMeta meta = new ChartMeta();
var meta = new ChartMeta();
var metaFile = new FileInfo(item.FullName + "/meta.json");
if (metaFile.Exists) {
using (var reader = new StreamReader(metaFile.FullName)) {
meta = JsonConvert.DeserializeObject<ChartMeta>(reader.ReadToEnd());
}
}
AsyncDelivery<Texture2D> cover = null;
if (meta.cover != null && meta.cover != "") {
var coverFile = item.GetFiles(meta.cover);
if (coverFile.Length > 0) {
cover = new AsyncDelivery<Texture2D>();
var task = new LoadTextureTask(Game.FileProtocolPrefix + coverFile[0].FullName, cover.Deliver);
cover.CancelSource = task.Cancel;
Game.NetworkTaskWorker.SubmitNetworkTask(task);
}
}
return new ChartDetail {
Cover = cover,
Meta = meta,
@@ -115,9 +121,19 @@ namespace Cryville.Crtr.Browsing {
var file = new FileInfo(path);
if (!converters.ContainsKey(file.Extension)) return false;
foreach (var converter in converters[file.Extension]) {
var resources = converter.ConvertFrom(file);
IEnumerable<Resource> resources = null;
try {
resources = converter.ConvertFrom(file);
}
catch (Exception ex) {
Popup.Create(ex.Message);
return false;
}
foreach (var res in resources) {
if (res is ChartResource) {
if (!res.Valid) {
Logger.Log("main", 3, "Resource", "Attempt to import invalid resource {0}", res);
}
else if (res is ChartResource) {
var tres = (ChartResource)res;
var dir = new DirectoryInfo(_rootPath + "/charts/" + res.Name);
if (!dir.Exists) dir.Create();
@@ -132,8 +148,9 @@ namespace Cryville.Crtr.Browsing {
var tres = (CoverResource)res;
var dir = new DirectoryInfo(_rootPath + "/charts/" + res.Name);
if (!dir.Exists) dir.Create();
var dest = new FileInfo(_rootPath + "/charts/" + res.Name + "/cover" + tres.Source.Extension);
var dest = new FileInfo(_rootPath + "/charts/" + res.Name + "/" + tres.Source.Name);
if (!dest.Exists) tres.Source.CopyTo(dest.FullName);
}
else if (res is SongResource) {
var tres = (SongResource)res;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -29,7 +29,6 @@ namespace Cryville.Crtr.Browsing {
private bool LoadItem(int id, GameObject obj) {
var bi = obj.GetComponent<BrowserItem>();
if (bi.Id == id) return true;
var item = ResourceManager.GetItemMeta(id);
bi.Load(id, item);
return true;
@@ -60,11 +59,11 @@ namespace Cryville.Crtr.Browsing {
private void OnAddDialogClosed() {
if (_dialog.FileName == null) return;
if (ResourceManager.ImportItemFrom(_dialog.FileName)) {
Debug.Log("Import succeeded"); // TODO
Popup.Create("Import succeeded");
OnPathClicked(ResourceManager.CurrentDirectory.Length - 1);
}
else {
Debug.Log("Import failed"); // TODO
Popup.Create("Import failed");
}
}
}

View File

@@ -64,8 +64,8 @@ namespace Cryville.Crtr.Browsing {
_units[_slideDest + 1].SlideToRight();
}
public void Open(int id) {
SetDataSettings(id);
public void Open(int id, ChartDetail detail) {
SetDataSettings(id, detail);
#if UNITY_5_3_OR_NEWER
SceneManager.LoadScene("Play", LoadSceneMode.Additive);
#else
@@ -74,8 +74,8 @@ namespace Cryville.Crtr.Browsing {
GameObject.Find("/Master").GetComponent<Master>().HideMenu();
}
public void OpenConfig(int id) {
SetDataSettings(id);
public void OpenConfig(int id, ChartDetail detail) {
SetDataSettings(id, detail);
#if UNITY_5_3_OR_NEWER
SceneManager.LoadScene("Config", LoadSceneMode.Additive);
#else
@@ -84,9 +84,9 @@ namespace Cryville.Crtr.Browsing {
GameObject.Find("/Master").GetComponent<Master>().HideMenu();
}
void SetDataSettings(int id) {
Settings.Default.LoadRuleset = "key/.umgr";
Settings.Default.LoadSkin = "key/0/.umgs";
void SetDataSettings(int id, ChartDetail detail) {
Settings.Default.LoadRuleset = detail.Meta.ruleset + "/.umgr";
Settings.Default.LoadRulesetConfig = detail.Meta.ruleset + ".json";
Settings.Default.LoadChart = MainBrowser.ResourceManager.GetItemPath(id);
}
}
@@ -107,6 +107,7 @@ namespace Cryville.Crtr.Browsing {
}
public string ruleset { get; set; }
public int note_count { get; set; }
public string cover { get; set; }
}
#pragma warning restore IDE1006
}

View File

@@ -1,5 +1,7 @@
using System.Collections.Generic;
using Cryville.Common;
using System.Collections.Generic;
using System.IO;
namespace Cryville.Crtr.Browsing {
public abstract class ResourceConverter {
public abstract string[] GetSupportedFormats();
@@ -7,9 +9,13 @@ namespace Cryville.Crtr.Browsing {
}
public abstract class Resource {
protected Resource(string name) {
Name = name;
Name = StringUtils.EscapeFileName(name);
}
public string Name { get; private set; }
public abstract bool Valid { get; }
public override string ToString() {
return string.Format("{0} ({1})", Name, ReflectionHelper.GetSimpleName(GetType()));
}
}
public class ChartResource : Resource {
public ChartResource(string name, Chart main, ChartMeta meta) : base(name) {
@@ -17,17 +23,20 @@ namespace Cryville.Crtr.Browsing {
}
public Chart Main { get; private set; }
public ChartMeta Meta { get; private set; }
public override bool Valid { get { return true; } }
}
public class CoverResource : Resource {
public CoverResource(string name, FileInfo src) : base(name) {
Source = src;
}
public FileInfo Source { get; private set; }
public override bool Valid { get { return Source.Exists; } }
}
public class SongResource : Resource {
public SongResource(string name, FileInfo src) : base(name) {
Source = src;
}
public FileInfo Source { get; private set; }
public override bool Valid { get { return Source.Exists; } }
}
}

View File

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

View File

@@ -1,8 +1,8 @@
//#define NO_THREAD
#define BUILD
using Cryville.Common;
using Cryville.Common.Plist;
using Cryville.Crtr.Config;
using Cryville.Crtr.Event;
using Newtonsoft.Json;
using System;
@@ -52,6 +52,7 @@ namespace Cryville.Crtr {
public static Rect hitRect;
public static Plane[] frustumPlanes;
RulesetConfig _rscfg;
static bool disableGC = true;
static float clippingDist = 1f;
static float renderDist = 6f;
@@ -62,20 +63,11 @@ namespace Cryville.Crtr {
static float startOffset = 0;
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;
~ChartPlayer() {
Dispose();
}
public void Dispose() {
#if !NO_THREAD
if (loadThread != null) loadThread.Abort();
#endif
if (texLoader != null) texLoader.Dispose();
}
InputProxy inputProxy;
#region MonoBehaviour
void Start() {
@@ -93,140 +85,153 @@ namespace Cryville.Crtr {
texHandler = new DownloadHandlerTexture();
#if BUILD
Play();
try {
Play();
}
catch (Exception ex) {
Game.LogException("Load/WorkerThread", "An error occured while loading the data", ex);
Popup.CreateException(ex);
ReturnToMenu();
}
#endif
// Camera.main.RenderToCubemap();
}
void OnDestroy() {
if (cbus != null) cbus.Dispose();
if (bbus != null) bbus.Dispose();
if (tbus != null) tbus.Dispose();
if (nbus != null) nbus.Dispose();
if (loadThread != null) loadThread.Abort();
if (texLoader != null) texLoader.Dispose();
if (inputProxy != null) inputProxy.Dispose();
if (texs != null) foreach (var t in texs) Texture.Destroy(t.Value);
Camera.onPostRender -= OnCameraPostRender;
GC.Collect();
}
bool texloaddone;
diag::Stopwatch texloadtimer = new diag::Stopwatch();
bool firstFrame;
double atime0;
void Update() {
// if (Input.GetKeyDown(KeyCode.Return)) TogglePlay();
if (started) {
try {
if (Screen.width != screenSize.x || Screen.height != screenSize.y)
throw new InvalidOperationException("Window resized while playing");
float dt = firstFrame
if (started) GameUpdate();
else if (loadThread != null) LoadUpdate();
if (logEnabled) LogUpdate();
else Game.MainLogger.Enumerate((level, module, msg) => { });
}
void GameUpdate() {
try {
if (Screen.width != screenSize.x || Screen.height != screenSize.y)
throw new InvalidOperationException("Window resized while playing");
float dt = firstFrame
? 1f / Application.targetFrameRate
: Time.deltaTime;
firstFrame = false;
cbus.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("EventBus.Copy");
bbus.CopyTo(2, tbus);
bbus.CopyTo(3, nbus);
UnityEngine.Profiling.Profiler.EndSample();
float step = autoRenderStep ? ( firstFrame
firstFrame = false;
inputProxy.ForceTick();
cbus.ForwardByTime(dt);
bbus.ForwardByTime(dt);
UnityEngine.Profiling.Profiler.BeginSample("ChartPlayer.Forward");
UnityEngine.Profiling.Profiler.BeginSample("EventBus.Copy");
bbus.CopyTo(2, tbus);
bbus.CopyTo(3, nbus);
UnityEngine.Profiling.Profiler.EndSample();
float step = autoRenderStep ? ( firstFrame
? 1f / Application.targetFrameRate
: Time.smoothDeltaTime
) : renderStep;
actualRenderStep = step;
actualRenderStep = step;
nbus.ForwardStepByTime(clippingDist, step);
nbus.BroadcastEndUpdate();
nbus.Anchor();
nbus.ForwardStepByTime(clippingDist, step);
nbus.BroadcastEndUpdate();
nbus.Anchor();
tbus.ForwardStepByTime(clippingDist, step);
tbus.ForwardStepByTime(renderDist, step);
tbus.BroadcastEndUpdate();
UnityEngine.Profiling.Profiler.EndSample();
}
catch (Exception ex) {
Game.LogException("Game", "An error occured while playing", ex);
Stop();
}
tbus.ForwardStepByTime(clippingDist, step);
tbus.ForwardStepByTime(renderDist, step);
tbus.BroadcastEndUpdate();
UnityEngine.Profiling.Profiler.EndSample();
}
#if !NO_THREAD
else if (loadThread != null) {
if (texLoader != null) {
string url = texLoader.url;
string name = StringUtils.TrimExt(url.Substring(url.LastIndexOfAny(new char[] {'/', '\\'}) + 1));
catch (Exception ex) {
Game.LogException("Game", "An error occured while playing", ex);
Popup.CreateException(ex);
Stop();
}
}
void LoadUpdate() {
if (texLoader != null) {
string url = texLoader.url;
string name = StringUtils.TrimExt(url.Substring(url.LastIndexOfAny(new char[] {'/', '\\'}) + 1));
#if UNITY_5_4_OR_NEWER
if (texHandler.isDone) {
var tex = texHandler.texture;
texs.Add(name, tex);
Logger.Log("main", 0, "Load/MainThread", "Loaded texture {0} ({1} bytes)", name, texLoader.downloadedBytes);
texLoader.Dispose();
texHandler.Dispose();
texLoader = null;
}
else if (texLoader.downloadProgress != 0) {
Logger.Log("main", 0, "Load/MainThread", "Loading texture {0} {1:P0}", name, texLoader.downloadProgress);
}
#else
if (texLoader.isDone) {
var tex = texLoader.texture;
texs.Add(name, tex);
Logger.Log("main", 0, "Load/MainThread", "Loaded texture {0} ({1} bytes)", name, texLoader.bytesDownloaded);
texLoader.Dispose();
texLoader = null;
}
else if (texLoader.progress != 0) {
Logger.Log("main", 0, "Load/MainThread", "Loading texture {0} {1:P0}", name, texLoader.progress);
}
#endif
if (texHandler.isDone) {
var tex = texHandler.texture;
tex.wrapMode = TextureWrapMode.Clamp;
texs.Add(name, tex);
texLoader.Dispose();
texHandler.Dispose();
texLoader = null;
}
if (texLoader == null)
if (texLoadQueue.Count > 0) {
#else
if (texLoader.isDone) {
var tex = texLoader.texture;
tex.wrapMode = TextureWrapMode.Clamp;
texs.Add(name, tex);
texLoader.Dispose();
texLoader = null;
}
#endif
}
if (texLoader == null)
if (texLoadQueue.Count > 0) {
#if UNITY_5_4_OR_NEWER
texHandler = new DownloadHandlerTexture();
texLoader = new UnityWebRequest(Game.FileProtocolPrefix + texLoadQueue.Dequeue(), "GET", texHandler, null);
texLoader.SendWebRequest();
texHandler = new DownloadHandlerTexture();
texLoader = new UnityWebRequest(Game.FileProtocolPrefix + texLoadQueue.Dequeue(), "GET", texHandler, null);
texLoader.SendWebRequest();
#else
texLoader = new WWW(Game.FileProtocolPrefix + texLoadQueue.Dequeue());
#endif
}
else if (!texloaddone) {
texloaddone = true;
texloadtimer.Stop();
Logger.Log("main", 1, "Load/MainThread", "Main thread done ({0}ms)", texloadtimer.Elapsed.TotalMilliseconds);
}
if (!loadThread.IsAlive) {
if (cbus == null) {
Logger.Log("main", 4, "Load/MainThread", "Load failed");
loadThread = null;
}
else if (!texloaddone) {
texloaddone = true;
texloadtimer.Stop();
Logger.Log("main", 1, "Load/MainThread", "Main thread done ({0}ms)", texloadtimer.Elapsed.TotalMilliseconds);
}
if (!loadThread.IsAlive) {
if (threadException != null) {
Logger.Log("main", 4, "Load/MainThread", "Load failed");
loadThread = null;
Popup.CreateException(threadException);
#if BUILD
ReturnToMenu();
ReturnToMenu();
#endif
}
else if (texLoader == null) {
Prehandle();
loadThread = null;
}
}
else if (texLoader == null) {
Prehandle();
loadThread = null;
}
}
#endif
if (logEnabled) {
string _logs = logs.text;
Game.MainLogger.Enumerate((level, module, msg) => {
string color;
switch (level) {
case 0: color = "#888888"; break;
case 1: color = "#bbbbbb"; break;
case 2: color = "#0088ff"; break;
case 3: color = "#ffff00"; break;
case 4: color = "#ff0000"; break;
case 5: color = "#bb0000"; break;
default: color = "#ff00ff"; break;
}
_logs += string.Format(
"\r\n<color={1}bb><{2}> {3}</color>",
DateTime.UtcNow.ToString("s"), color, module, msg
);
});
logs.text = _logs.Substring(Mathf.Max(0, _logs.IndexOf('\n', Mathf.Max(0, _logs.Length - 4096))));
var sttext = string.Format(
}
string timetext = string.Empty;
void LogUpdate() {
string _logs = logs.text;
Game.MainLogger.Enumerate((level, module, msg) => {
string color;
switch (level) {
case 0: color = "#888888"; break;
case 1: color = "#bbbbbb"; break;
case 2: color = "#0088ff"; break;
case 3: color = "#ffff00"; break;
case 4: color = "#ff0000"; break;
case 5: color = "#bb0000"; break;
default: color = "#ff00ff"; break;
}
_logs += string.Format(
"\r\n<color={1}bb><{2}> {3}</color>",
DateTime.UtcNow.ToString("s"), color, module, msg
);
});
logs.text = _logs.Substring(Mathf.Max(0, _logs.IndexOf('\n', Mathf.Max(0, _logs.Length - 4096))));
var sttext = string.Format(
"FPS: i{0:0} / s{1:0}\nSMem: {2:N0} / {3:N0}\nIMem: {4:N0} / {5:N0}",
1 / Time.deltaTime,
1 / Time.smoothDeltaTime,
@@ -242,12 +247,18 @@ namespace Cryville.Crtr {
UnityEngine.Profiling.Profiler.GetTotalReservedMemory()
#endif
);
if (judge != null) sttext += "\n== Scores ==\n" + judge.GetFullFormattedScoreString();
status.text = sttext;
}
else {
Game.MainLogger.Enumerate((level, module, msg) => { });
}
sttext += timetext;
if (judge != null) sttext += "\n== Scores ==\n" + judge.GetFullFormattedScoreString();
status.text = sttext;
}
void OnCameraPostRender(Camera cam) {
if (started) timetext = string.Format(
"\nSTime: {0:R}\nATime: {1:R}\nITime: {2:R}",
cbus.Time,
Game.AudioClient.Position - atime0,
inputProxy.GetTimestampAverage()
);
else timetext = string.Empty;
}
#endregion
@@ -298,14 +309,13 @@ namespace Cryville.Crtr {
autoRenderStep = renderStep == 0;
soundOffset = Settings.Default.SoundOffset;
startOffset = Settings.Default.StartOffset;
sv = Settings.Default.ScrollVelocity;
firstFrame = true;
#if !NO_THREAD
texloaddone = false;
#endif
Game.NetworkTaskWorker.SuspendBackgroundTasks();
Game.AudioSession = Game.AudioSequencer.NewSession();
Camera.onPostRender += OnCameraPostRender;
var hitPlane = new Plane(Vector3.forward, Vector3.zero);
var r0 = Camera.main.ViewportPointToRay(new Vector3(0, 0, 1));
float dist;
@@ -322,12 +332,33 @@ namespace Cryville.Crtr {
FileInfo chartFile = new FileInfo(
Game.GameDataPath + "/charts/" + Settings.Default.LoadChart
);
FileInfo rulesetFile = new FileInfo(
Game.GameDataPath + "/rulesets/" + Settings.Default.LoadRuleset
);
FileInfo skinFile = new FileInfo(
Game.GameDataPath + "/skins/" + Settings.Default.LoadSkin
if (!rulesetFile.Exists) throw new FileNotFoundException("Ruleset for the chart not found\nMake sure you have imported the ruleset");
FileInfo rulesetConfigFile = new FileInfo(
Game.GameDataPath + "/config/rulesets/" + Settings.Default.LoadRulesetConfig
);
if (!rulesetConfigFile.Exists) throw new FileNotFoundException("Ruleset config not found\nPlease open the config to generate");
using (StreamReader cfgreader = new StreamReader(rulesetConfigFile.FullName, Encoding.UTF8)) {
_rscfg = JsonConvert.DeserializeObject<RulesetConfig>(cfgreader.ReadToEnd(), new JsonSerializerSettings() {
MissingMemberHandling = MissingMemberHandling.Error
});
}
sv = _rscfg.generic.ScrollVelocity;
FileInfo skinFile = new FileInfo(
string.Format("{0}/skins/{1}/{2}/.umgs", Game.GameDataPath, rulesetFile.Directory.Name, _rscfg.generic.Skin)
);
if (!skinFile.Exists) throw new FileNotFoundException("Skin not found\nPlease specify an available skin in the config");
loadThread = new Thread(new ParameterizedThreadStart(Load));
loadThread.Start(new LoadInfo() {
chartFile = chartFile,
rulesetFile = rulesetFile,
skinFile = skinFile,
});
Logger.Log("main", 0, "Load/MainThread", "Loading textures...");
texloadtimer = new diag::Stopwatch();
@@ -335,33 +366,8 @@ namespace Cryville.Crtr {
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
texloadtimer.Stop();
Logger.LogFormat("main", 0, "Load/MainThread", "Textures loaded successfully ({0}ms)", texloadtimer.Elapsed.TotalMilliseconds);
Load(new LoadInfo(){
chartFile = chartFile,
rulesetFile = rulesetFile,
skinFile = skinFile,
});
Prehandle();
#else
loadThread = new Thread(new ParameterizedThreadStart(Load));
loadThread.Start(new LoadInfo() {
chartFile = chartFile,
rulesetFile = rulesetFile,
skinFile = skinFile,
});
#endif
}
void Prehandle() {
@@ -381,7 +387,7 @@ namespace Cryville.Crtr {
}
Logger.Log("main", 0, "Load/Prehandle", "Initializing states");
cbus.BroadcastInit();
Game.InputManager.Activate();
inputProxy.Activate();
if (logEnabled) ToggleLogs();
Logger.Log("main", 0, "Load/Prehandle", "Cleaning up");
GC.Collect();
@@ -389,12 +395,14 @@ namespace Cryville.Crtr {
timer.Stop();
Logger.Log("main", 1, "Load/Prehandle", "Prehandling done ({0}ms)", timer.Elapsed.TotalMilliseconds);
Game.AudioSequencer.Playing = true;
Thread.Sleep((int)(Game.AudioClient.BufferPosition - Game.AudioClient.Position));
Game.InputManager.SyncTime(cbus.Time);
atime0 = Game.AudioClient.BufferPosition;
Thread.Sleep((int)((atime0 - Game.AudioClient.Position) * 1000));
inputProxy.SyncTime(cbus.Time);
started = true;
}
catch (Exception ex) {
Game.LogException("Load/Prehandle", "An error occured while prehandling the data", ex);
Popup.CreateException(ex);
Stop();
}
}
@@ -402,19 +410,18 @@ namespace Cryville.Crtr {
public void Stop() {
try {
Logger.Log("main", 1, "Game", "Stopping");
chart = null;
Game.AudioSession = Game.AudioSequencer.NewSession();
if (cbus != null) cbus.Dispose();
if (bbus != null) bbus.Dispose();
if (tbus != null) tbus.Dispose();
if (nbus != null) nbus.Dispose();
// Game.InputManager.Deactivate();
foreach (var t in texs) Texture.Destroy(t.Value);
inputProxy.Deactivate();
if (cbus != null) { cbus.Dispose(); cbus = null; }
if (bbus != null) { bbus.Dispose(); bbus = null; }
if (tbus != null) { tbus.Dispose(); tbus = null; }
if (nbus != null) { nbus.Dispose(); nbus = null; }
Logger.Log("main", 1, "Game", "Stopped");
}
catch (Exception ex) {
if (!logEnabled) ToggleLogs();
Game.LogException("Game", "An error occured while stopping", ex);
Popup.CreateException(ex);
}
finally {
if (started) {
@@ -442,6 +449,7 @@ namespace Cryville.Crtr {
public FileInfo skinFile;
}
Exception threadException;
#if !NO_THREAD
Thread loadThread = null;
diag::Stopwatch workerTimer;
@@ -458,6 +466,7 @@ namespace Cryville.Crtr {
}
catch (Exception ex) {
Game.LogException("Load/WorkerThread", "An error occured while loading the data", ex);
threadException = ex;
}
}
@@ -484,10 +493,16 @@ namespace Cryville.Crtr {
cbus = batcher.Batch();
Logger.Log("main", 0, "Load/WorkerThread", "Batched {0} event batches", cbus.events.Count);
LoadSkin(info.skinFile);
judge = new Judge(pruleset);
etor.ContextJudge = judge;
LoadSkin(info.skinFile);
inputProxy = new InputProxy(pruleset, judge);
inputProxy.LoadFrom(_rscfg.inputs);
if (!inputProxy.IsCompleted) {
throw new ArgumentException("Input config not completed\nPlease complete the input settings");
}
cbus.AttachSystems(pskin, judge);
Logger.Log("main", 0, "Load/WorkerThread", "Attaching handlers");
@@ -499,7 +514,7 @@ namespace Cryville.Crtr {
foreach (var ts in gs.Value.Children) {
ContainerHandler th;
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 {
th = new TrackHandler(gh, (Chart.Track)ts.Key);
@@ -508,11 +523,15 @@ namespace Cryville.Crtr {
}
}
Logger.Log("main", 0, "Load/WorkerThread", "Prehandling (iteration 1)");
cbus.Clone(16).Forward();
using (var pbus = cbus.Clone(16)) {
pbus.Forward();
}
Logger.Log("main", 0, "Load/WorkerThread", "Patching events");
cbus.DoPatch();
Logger.Log("main", 0, "Load/WorkerThread", "Prehandling (iteration 2)");
cbus.Clone(17).Forward();
using (var pbus = cbus.Clone(17)) {
pbus.Forward();
}
Logger.Log("main", 0, "Load/WorkerThread", "Cloning states (type 1)");
bbus = cbus.Clone(1, -clippingDist);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -66,9 +66,9 @@ namespace Cryville.Crtr.Event {
readonly RMVPool RMVPool = new RMVPool();
protected Dictionary<StampedEvent, RealtimeMotionValue> PlayingMotions = new Dictionary<StampedEvent, RealtimeMotionValue>();
protected Dictionary<MotionName, RealtimeMotionValue> Values = new Dictionary<MotionName, RealtimeMotionValue>();
protected Dictionary<MotionName, Vector> CachedValues = new Dictionary<MotionName, Vector>();
protected Dictionary<MotionName, bool> CachedValueStates = new Dictionary<MotionName, bool>();
protected Dictionary<Identifier, RealtimeMotionValue> Values;
protected Dictionary<Identifier, Vector> CachedValues;
protected Dictionary<Identifier, bool> CachedValueStates;
/// <summary>
/// Gets a motion value.
@@ -76,12 +76,12 @@ namespace Cryville.Crtr.Event {
/// <param name="name">The motion name.</param>
/// <param name="clone">Returns a cloned motion value instead.</param>
/// <returns>A motion value.</returns>
RealtimeMotionValue GetMotionValue(MotionName name, bool clone = false) {
RealtimeMotionValue GetMotionValue(Identifier name, bool clone = false) {
RealtimeMotionValue value;
if (!Values.TryGetValue(name, out value)) {
value = new RealtimeMotionValue().Init(Parent == null
? ChartPlayer.motionRegistry[name.MainName].GlobalInitValue
: ChartPlayer.motionRegistry[name.MainName].InitValue
? ChartPlayer.motionRegistry[name].GlobalInitValue
: ChartPlayer.motionRegistry[name].InitValue
);
Values.Add(name, value);
}
@@ -89,7 +89,7 @@ namespace Cryville.Crtr.Event {
return value;
}
void InvalidateMotion(MotionName name) {
void InvalidateMotion(Identifier name) {
CachedValueStates[name] = false;
foreach (var c in Children)
c.Value.InvalidateMotion(name);
@@ -103,8 +103,11 @@ namespace Cryville.Crtr.Event {
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)
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) {
@@ -117,19 +120,19 @@ namespace Cryville.Crtr.Event {
public ContainerState Clone(byte ct) {
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) {
mvs.Add(mv.Key, mv.Value.Clone());
}
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) {
cvs.Add(cv.Key, cv.Value.Clone());
}
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) {
cvss.Add(cv.Key, cv.Value);
}
@@ -193,7 +196,7 @@ namespace Cryville.Crtr.Event {
public void Dispose() {
if (Disposed) return;
Disposed = true;
if (Handler != null) Handler.Dispose();
if (CloneType < 16 && Handler != null) Handler.Dispose();
foreach (var s in Children)
s.Value.Dispose();
RMVPool.ReturnAll();
@@ -211,28 +214,40 @@ namespace Cryville.Crtr.Event {
this.judge = judge;
}
public T GetRawValue<T>(MotionName key) where T : Vector {
public Vector GetRawValue(Identifier key) {
Vector 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);
CachedValueStates[key] = false;
}
T r = (T)tr;
Vector r = tr;
#if !DISABLE_CACHE
if (CachedValueStates[key]) return r;
#endif
float reltime = 0;
if (rootPrototype != null) reltime = Time - rootPrototype.Time;
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
CachedValueStates[key] = true;
#endif
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 {
get {
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 {
get {
Vec3 r = GetRawValue<Vec3>(n_normal);
@@ -254,16 +269,8 @@ namespace Cryville.Crtr.Event {
}
}
static readonly MotionName n_pt = new MotionName("pt");
public Vector2 ScreenPoint {
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");
static readonly Identifier n_sv = new Identifier("sv");
static readonly Identifier n_svm = new Identifier("svm");
public float ScrollVelocity {
get {
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 {
get {
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 {
get {
return GetRawValue<VecI1>(n_corner).Value % 2 >= 1;
}
}
static readonly MotionName n_ctrl0 = new MotionName("ctrl0");
static readonly MotionName n_ctrl1 = new MotionName("ctrl1");
static readonly Identifier n_ctrl0 = new Identifier("ctrl0");
static readonly Identifier n_ctrl1 = new Identifier("ctrl1");
public Vector3 GetControlPoint(bool alt1, float deltaz) {
var mv = GetRawValue<VecCtrl>(alt1 ? n_ctrl1 : n_ctrl0);
if (alt1 && mv.IsZero()) {
@@ -296,7 +303,7 @@ namespace Cryville.Crtr.Event {
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 {
get {
return GetRawValue<Vec1>(n_track).Value;
@@ -314,7 +321,6 @@ namespace Cryville.Crtr.Event {
public void Handle(StampedEvent ev, Action<StampedEvent> callback = null) {
if (breakflag) return;
if (ev != null) {
bool flag = false;
if (ev.Unstamped is Chart.Motion) {
var tev = (Chart.Motion)ev.Unstamped;
var mv = RMVPool.Rent(tev.Name);
@@ -354,18 +360,9 @@ namespace Cryville.Crtr.Event {
}
}
}
if (ev.Unstamped == null) {
Callback(ev, callback);
flag = true;
}
else if (ev.Unstamped.Priority >= 0) {
Callback(ev, callback);
flag = true;
}
if (!flag) Callback(null, callback);
return;
Callback(ev.Unstamped == null || ev.Unstamped.Priority >= 0 ? ev : null, callback);
}
Callback(null, callback);
else Callback(null, 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;
namespace Cryville.Crtr.Event {
@@ -12,16 +13,16 @@ namespace Cryville.Crtr.Event {
return new RealtimeMotionValue().Init(_reg.InitValue);
}
}
static Dictionary<string, Bucket> _buckets;
static Dictionary<Identifier, Bucket> _buckets;
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)
_buckets.Add(reg.Key, new Bucket(reg.Key, 4096));
}
readonly Dictionary<RealtimeMotionValue, string> _rented = new Dictionary<RealtimeMotionValue, string>();
public RealtimeMotionValue Rent(MotionName name) {
var n = name.MainName;
public RealtimeMotionValue Rent(Identifier name) {
var n = name;
var obj = _buckets[n].Rent();
_rented.Add(obj, n);
return obj;

View File

@@ -2,6 +2,7 @@ using Cryville.Crtr.Browsing;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
@@ -17,23 +18,30 @@ namespace Cryville.Crtr.Extensions.Malody {
public override IEnumerable<Resource> ConvertFrom(FileInfo file) {
List<Resource> result = new List<Resource>();
MalodyChart src;
if (file.Extension != ".mc") throw new NotImplementedException("mcz file is not supported");
using (var reader = new StreamReader(file.FullName)) {
src = JsonConvert.DeserializeObject<MalodyChart>(reader.ReadToEnd());
}
if (src.meta.mode != 0) throw new NotImplementedException("The chart mode is not supported");
if (src.meta.mode_ext.column != 4) throw new NotImplementedException("The key count is not supported");
var ruleset = "malody!" + MODES[src.meta.mode];
if (src.meta.mode == 0) {
ruleset += "." + src.meta.mode_ext.column.ToString(CultureInfo.InvariantCulture) + "k";
}
ChartMeta meta = new ChartMeta() {
song = new ChartMeta.MetaInfo() {
name = src.meta.song.titleorg != null ? src.meta.song.titleorg : src.meta.song.title,
author = src.meta.song.artistorg != null ? src.meta.song.artistorg : src.meta.song.artist,
},
ruleset = "malody!" + MODES[src.meta.mode],
ruleset = ruleset,
};
Chart chart = new Chart {
format = 2,
time = new BeatTime(-4, 0, 1),
ruleset = "malody!" + MODES[src.meta.mode],
ruleset = ruleset,
sigs = new List<Chart.Signature>(),
sounds = new List<Chart.Sound>(),
motions = new List<Chart.Motion>(),
@@ -68,7 +76,7 @@ namespace Cryville.Crtr.Extensions.Malody {
float pbeat = 0f, ctime = 0f;
int[] endbeat = new int[] { 0, 0, 1 };
foreach (var ev in events) {
float cbeat = bp(ev.beat);
float cbeat = ConvertBeat(ev.beat);
ctime += baseBpm == null ? 0 : (cbeat - pbeat) / baseBpm.Value * 60f;
pbeat = cbeat;
if (ev is MalodyChart.Time) {
@@ -94,17 +102,18 @@ namespace Cryville.Crtr.Extensions.Malody {
var tev = (MalodyChart.Note)ev;
if (tev.type == 1) {
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 {
time = new BeatTime(0, 0, 1),
id = meta.song.name,
id = res.Name,
offset = -tev.offset / 1000f,
});
}
else throw new NotImplementedException();
}
else {
if (bp(tev.beat) > bp(endbeat)) endbeat = tev.beat;
if (ConvertBeat(tev.beat) > ConvertBeat(endbeat)) endbeat = tev.beat;
var rn = new Chart.Note() {
time = new BeatTime(tev.beat[0], tev.beat[1], tev.beat[2]),
motions = new List<Chart.Motion> {
@@ -112,7 +121,7 @@ namespace Cryville.Crtr.Extensions.Malody {
},
};
if (tev.endbeat != null) {
if (bp(tev.endbeat) > bp(endbeat)) endbeat = tev.endbeat;
if (ConvertBeat(tev.endbeat) > ConvertBeat(endbeat)) endbeat = tev.endbeat;
rn.endtime = new BeatTime(tev.endbeat[0], tev.endbeat[1], tev.endbeat[2]);
longEvents.Add(ev, new StartEventState {
Destination = rn,
@@ -140,9 +149,11 @@ namespace Cryville.Crtr.Extensions.Malody {
};
meta.note_count = group.notes.Count;
string chartName = string.Format("{0} - {1}", meta.song.name, meta.chart.name);
result.Add(new ChartResource(chartName, chart, meta));
if (src.meta.background != null)
if (src.meta.background != null) {
result.Add(new CoverResource(chartName, new FileInfo(file.DirectoryName + "/" + src.meta.background)));
meta.cover = src.meta.background;
}
result.Add(new ChartResource(chartName, chart, meta));
return result;
}
@@ -151,7 +162,7 @@ namespace Cryville.Crtr.Extensions.Malody {
public ChartEvent Destination { get; set; }
}
float bp(int[] beat) {
float ConvertBeat(int[] beat) {
return beat[0] + (float)beat[1] / beat[2];
}
}

View File

@@ -85,12 +85,10 @@ namespace Cryville.Crtr {
AudioSequencer.Playing = true;
AudioClient.Start();
ChartPlayer.motionRegistry = new Dictionary<string, MotionRegistry> {
ChartPlayer.motionRegistry = new Dictionary<Identifier, MotionRegistry> {
{ "pt" , new MotionRegistry(typeof(VecPt)) },
{ "dir" , 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)) },
{ "svm" , new MotionRegistry(new Vec1m(1f)) },
{ "dist" , new MotionRegistry(new VecPtComp(0f, 0f), new VecPtComp(0f, float.PositiveInfinity)) },
@@ -98,8 +96,6 @@ namespace Cryville.Crtr {
{ "ctrl0" , new MotionRegistry(typeof(VecCtrl)) },
{ "ctrl1" , new MotionRegistry(typeof(VecCtrl)) },
{ "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");

View File

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

View File

@@ -1,38 +1,203 @@
using Cryville.Common;
using Cryville.Common.Pdt;
using Cryville.Common.Unity.Input;
using Cryville.Crtr.Event;
using System.Collections.Generic;
namespace Cryville.Crtr {
public class Judge {
readonly PdtEvaluator _etor;
readonly PdtRuleset _rs;
public Judge(PdtRuleset rs) {
_rs = rs;
foreach (var s in rs.scores)
scores.Add(s.Key, s.Value.init);
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; }
}
public void StartFrame() {
}
public void Feed(InputEvent ev) {
}
public void EndFrame() {
}
public readonly Dictionary<string, float> scores = new Dictionary<string, float>();
readonly Dictionary<string, string> ScoreCache = new Dictionary<string, string>();
public Dictionary<string, string> GetFormattedScoreStrings() {
if (ScoreCache.Count == 0) {
foreach (var s in scores)
ScoreCache.Add(s.Key, s.Value.ToString(_rs.scores[s.Key].format));
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) {
_etor = ChartPlayer.etor;
_rs = rs;
foreach (var s in rs.scores) {
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 Prepare(float st, float et, Identifier input, JudgeDefinition def, ContainerState container) {
List<JudgeEvent> list;
if (!evs.TryGetValue(input, out list)) {
ct.Add(input, 0);
evs.Add(input, list = new List<JudgeEvent>());
activeEvs.Add(input, new List<JudgeEvent>());
}
var ev = new JudgeEvent {
StartTime = st,
EndTime = et,
StartClip = st + def.clip[0],
EndClip = et + def.clip[1],
Definition = def,
State = container,
};
var index = list.BinarySearch(ev, _stcmp);
if (index < 0) index = ~index;
list.Insert(index, ev);
}
static bool _flag;
static readonly PropOp.Boolean _flagop = new PropOp.Boolean(v => _flag = v);
static readonly int _var_fn = IdentifierManager.SharedInstance.Request("fn");
static readonly int _var_tn = IdentifierManager.SharedInstance.Request("tn");
static readonly int _var_ft = IdentifierManager.SharedInstance.Request("ft");
static readonly int _var_tt = IdentifierManager.SharedInstance.Request("tt");
readonly byte[] _numbuf1 = new byte[sizeof(float)];
readonly byte[] _numbuf2 = new byte[sizeof(float)];
readonly byte[] _numbuf3 = new byte[sizeof(float)];
readonly byte[] _numbuf4 = new byte[sizeof(float)];
unsafe void LoadNum(byte[] buffer, float value) {
fixed (byte* ptr = buffer) *(float*)ptr = value;
}
// Adopted from System.Collections.Generic.ArraySortHelper<T>.InternalBinarySearch(T[] array, int index, int length, T value, IComparer<T> comparer)
int BinarySearch(List<JudgeEvent> list, float time, int stack) {
int num = 0;
int num2 = list.Count - 1;
while (num <= num2) {
int num3 = num + (num2 - num >> 1);
int num4 = -list[num3].Definition.stack.CompareTo(stack);
if (num4 == 0) num4 = list[num3].StartClip.CompareTo(time);
if (num4 == 0) return num3;
else if (num4 < 0) num = num3 + 1;
else num2 = num3 - 1;
}
return ~num;
}
int BinarySearchFirst(List<JudgeEvent> list, float time, int stack) {
if (list[0].Definition.stack == stack && list[0].StartClip == time) return 0;
int num = 0;
int num2 = list.Count - 1;
while (num <= num2) {
int num3 = num + (num2 - num >> 1);
int num4 = -list[num3].Definition.stack.CompareTo(stack);
if (num4 == 0) num4 = list[num3].StartClip.CompareTo(time);
if (num4 >= 0) num2 = num3 - 1;
else num = num3 + 1;
}
return num + 1;
}
public void Feed(Identifier target, float ft, float tt) {
Forward(target, tt);
var actlist = activeEvs[target];
if (actlist.Count > 0) {
LoadNum(_numbuf3, ft); _etor.ContextCascadeUpdate(_var_ft, new PropSrc.Arbitrary(PdtInternalType.Number, _numbuf3));
LoadNum(_numbuf4, tt); _etor.ContextCascadeUpdate(_var_tt, new PropSrc.Arbitrary(PdtInternalType.Number, _numbuf4));
var index = 0;
while (index >= 0 && index < actlist.Count) {
var ev = actlist[index];
LoadNum(_numbuf1, ev.StartTime); _etor.ContextCascadeUpdate(_var_fn, new PropSrc.Arbitrary(PdtInternalType.Number, _numbuf1));
LoadNum(_numbuf2, ev.EndTime); _etor.ContextCascadeUpdate(_var_tn, new PropSrc.Arbitrary(PdtInternalType.Number, _numbuf2));
var def = ev.Definition;
if (def.hit != null) _etor.Evaluate(_flagop, def.hit);
else _flag = true;
if (_flag) {
if (def.scores != null) UpdateScore(def.scores);
if (def.pass != null) Pass(def.pass);
actlist.RemoveAt(index);
if (def.prop != 0 && actlist.Count > 0) {
index = BinarySearchFirst(actlist, ev.StartClip, def.stack - def.prop);
if (index < 0) index = ~index;
}
else index++;
}
else index++;
}
}
}
bool Pass(Identifier[] ids) {
foreach (var i in ids) {
var def = _rs.judges[i];
if (def.hit != null) _etor.Evaluate(_flagop, def.hit);
else _flag = true;
if (_flag) {
if (def.scores != null) UpdateScore(def.scores);
if (def.pass != null) Pass(def.pass);
return true;
}
}
return false;
}
public void Cleanup(Identifier target, float ft, float tt) {
Forward(target, tt);
var actlist = activeEvs[target];
for (int i = actlist.Count - 1; i >= 0; i--) {
JudgeEvent ev = actlist[i];
if (tt > ev.EndClip) {
actlist.RemoveAt(i);
if (ev.Definition.miss != null) Pass(ev.Definition.miss);
}
}
}
void Forward(Identifier target, float tt) {
var list = evs[target];
var actlist = activeEvs[target];
JudgeEvent ev;
while (list.Count > 0 && (ev = list[0]).StartClip <= tt) {
list.RemoveAt(0);
var index = BinarySearch(actlist, ev.StartClip, ev.Definition.stack);
if (index < 0) index = ~index;
actlist.Insert(index, ev);
}
}
void UpdateScore(Dictionary<ScoreOperation, PdtExpression> scoreops) {
foreach (var scoreop in scoreops) {
var key = scoreop.Key;
_etor.ContextSelfValue = scoreSrcs[key.name.Key];
_etor.Evaluate(scoreOps[key.name.Key], scoreop.Value);
scoreSrcs[key.name.Key].Invalidate();
foreach (var s in _rs.scores) {
if (s.Value.value != null) {
_etor.ContextSelfValue = scoreSrcs[s.Key.Key];
_etor.Evaluate(scoreOps[s.Key.Key], s.Value.value);
scoreSrcs[s.Key.Key].Invalidate();
}
}
}
ScoreCache.Clear();
}
readonly Dictionary<int, int> scoreFmtKeys = new Dictionary<int, int>();
readonly Dictionary<int, PropSrc> scoreSrcs = new Dictionary<int, PropSrc>();
readonly Dictionary<int, PropOp> scoreOps = new Dictionary<int, PropOp>();
readonly Dictionary<int, ScoreDefinition> scoreDefs = new Dictionary<int, ScoreDefinition>();
public readonly Dictionary<int, float> scores = new Dictionary<int, float>();
readonly Dictionary<int, string> ScoreCache = new Dictionary<int, string>();
readonly object _lock = new object();
public Dictionary<int, string> GetFormattedScoreStrings() {
lock (_lock) {
if (ScoreCache.Count == 0) {
foreach (var s in scores)
ScoreCache.Add(scoreFmtKeys[s.Key], s.Value.ToString(scoreDefs[s.Key].format));
}
return ScoreCache;
}
return ScoreCache;
}
public string GetFullFormattedScoreString() {
bool flag = false;
string result = "";
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;
}
return result;
@@ -41,18 +206,25 @@ namespace Cryville.Crtr {
public class InputDefinition {
public int dim;
public bool notnull;
public Dictionary<string, PdtExpression> pass;
public Dictionary<Identifier, PdtExpression> pass;
}
public class JudgeDefinition {
public PdtExpression clip;
public float[] clip;
public PdtExpression input;
public PdtExpression hit;
public string[] pass;
public string miss;
public Dictionary<string, PdtExpression> scores;
public Identifier[] pass;
public Identifier[] miss;
public Dictionary<ScoreOperation, PdtExpression> scores;
public int stack;
public int prop = 1;
}
public class ScoreOperation {
public string name;
public PdtOperator op;
public Identifier name;
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 PdtExpression value;

View File

@@ -6,11 +6,13 @@ namespace Cryville.Crtr {
public class Menu : MonoBehaviour {
#pragma warning disable IDE0044
[SerializeField]
private ResourceBrowserMaster m_browserMaster;
ResourceBrowserMaster m_browserMaster;
[SerializeField]
private Animator m_targetAnimator;
Animator m_targetAnimator;
[SerializeField]
private ProgressBar m_progressBar;
ProgressBar m_progressBar;
[SerializeField]
SettingsPanel m_settingsPanel;
#pragma warning restore IDE0044
bool initialized = false;
@@ -19,6 +21,7 @@ namespace Cryville.Crtr {
void Awake() {
Game.Init();
transform.parent.Find("Canvas/Contents").gameObject.SetActive(true);
m_settingsPanel.Target = Settings.Default;
}
void Update() {
if (!initialized) {

View File

@@ -139,41 +139,6 @@ namespace Cryville.Crtr {
}
}
public struct MotionName : IEquatable<MotionName> {
public string MainName { get; private set; }
public string SubName { get; private set; }
public string FullName { get; private set; }
readonly int hash;
public MotionName(string mainName, string subName) {
MainName = mainName;
SubName = subName;
FullName = subName == null ? mainName : string.Format("{0}!{1}", mainName, subName);
hash = FullName.GetHashCode();
}
public MotionName(string fullName) {
var names = fullName.Split('!');
if (names.Length > 2) throw new ArgumentException("Invalid name");
FullName = fullName;
hash = FullName.GetHashCode();
MainName = names[0];
SubName = names.Length == 1 ? "" : names[1];
}
public override bool Equals(object obj) {
if (!(obj is MotionName)) return false;
return Equals((MotionName)obj);
}
public bool Equals(MotionName other) {
return hash == other.hash;
}
public override int GetHashCode() {
return hash;
}
public override string ToString() {
return FullName;
}
}
public struct MotionRegistry {
readonly Type m_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)
internal int BinarySearch(float value) {
int BinarySearch(float value) {
int num = 0;
int num2 = RelativeNodes.Count - 1;
while (num <= num2) {
int num3 = num + (num2 - num >> 1);
int num4 = RelativeNodes[num3].Time.Value.CompareTo(value);
if (num4 == 0) {
return num3;
}
if (num4 < 0) {
num = num3 + 1;
}
else {
num2 = num3 - 1;
}
if (num4 == 0) return num3;
if (num4 < 0) num = num3 + 1;
else num2 = num3 - 1;
}
return ~num;
}

View File

@@ -1,3 +1,4 @@
using Cryville.Common;
using Cryville.Common.Math;
using Cryville.Crtr.Components;
using Cryville.Crtr.Event;
@@ -9,10 +10,12 @@ namespace Cryville.Crtr {
class NoteHandler : ContainerHandler {
readonly GroupHandler gh;
public readonly Chart.Note Event;
readonly PdtRuleset ruleset;
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;
Event = ev;
ruleset = rs;
judge = j;
}
@@ -90,29 +93,39 @@ namespace Cryville.Crtr {
else if (s.CloneType == 16) {
if (ev == 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) {
var tev = (Chart.Motion)ev.Unstamped;
if (tev.Name.MainName != "judge") return;
phMotions.Add(tev, (Vec1)s.GetRawValue<Vec1>(tev.Name).Clone());
/*var tev = (Chart.Motion)ev.Unstamped;
if (tev.Name != "judge") return;
phMotions.Add(tev, (Vec1)s.GetRawValue<Vec1>(tev.Name).Clone());*/
}
else if (ev.Unstamped is InstantEvent) {
var oev = ((InstantEvent)ev.Unstamped).Original;
/*var oev = ((InstantEvent)ev.Unstamped).Original;
if (oev is Chart.Motion) {
var tev = (Chart.Motion)oev;
if (tev.Name.MainName != "judge") return;
if (tev.Name != "judge") return;
var v0 = phMotions[tev];
var v1 = s.GetRawValue<Vec1>(tev.Name);
// var etor = new Evaluator();
for (var vi = Mathf.Ceil(v0.Value); vi < v1.Value; vi++) {
var v = new Vec1(vi);
var t = MotionLerper.Delerp(v, ev.Time, v1, ev.Origin.Time, v0, tev.transition, tev.rate);
/*CompiledRuleset.PatchJudge(
CompiledRuleset.PatchJudge(
Event, ChartPlayer.cruleset.primary_judges[tev.Name.SubName],
t, etor, patchedJudgeEvents
);*/
);
}
phMotions.Remove(tev);
}
}*/
}
}
}
@@ -137,12 +150,12 @@ namespace Cryville.Crtr {
public override void MotionUpdate(byte ct, Chart.Motion ev) {
base.MotionUpdate(ct, ev);
if (ct == 0) {
if (ev.Name.MainName == "judge") {
/*if (ev.Name == "judge") {
if (invalidated) return;
if (ev.Name.SubName == null)
if (ev.Name == null)
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) {
/*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.Collections.Generic;
using UnityEngine;
namespace Cryville.Crtr {
public class PdtEvaluator : PdtEvaluatorBase {
static readonly Dictionary<OperatorSignature, PdtOperator> _shortops = new Dictionary<OperatorSignature, PdtOperator>();
static readonly Dictionary<string, PdtOperator> _longops = new Dictionary<string, 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;
}
}
static readonly Dictionary<PdtOperatorSignature, PdtOperator> _shortops = new Dictionary<PdtOperatorSignature, PdtOperator>();
readonly Dictionary<int, PdtOperator> _ctxops = new Dictionary<int, PdtOperator>();
readonly byte[] _numbuf = new byte[4];
protected override void GetVariable(string name, out int type, out byte[] value) {
switch (name) {
case "w": LoadNum(ChartPlayer.hitRect.width); type = PdtInternalType.Number; value = _numbuf; return;
case "h": LoadNum(ChartPlayer.hitRect.height); type = PdtInternalType.Number; value = _numbuf; return;
case "true": LoadNum(1); type = PdtInternalType.Number; value = _numbuf; return;
case "false": LoadNum(0); type = PdtInternalType.Number; value = _numbuf; return;
default:
PropSrc prop;
string str;
if (ContextEvent != null && ContextEvent.PropSrcs.TryGetValue(name, out prop)) {
prop.Get(out type, out value);
}
else if (ContextJudge != null && ContextJudge.GetFormattedScoreStrings().TryGetValue(name, out str)) {
type = PdtInternalType.String;
value = GetBytes(str);
RevokePotentialConstant();
static readonly int _var_w = IdentifierManager.SharedInstance.Request("w");
static readonly int _var_h = IdentifierManager.SharedInstance.Request("h");
static readonly int _var_true = IdentifierManager.SharedInstance.Request("true");
static readonly int _var_false = IdentifierManager.SharedInstance.Request("false");
protected override void GetVariable(int name, out int type, out byte[] value) {
if (name == _var_w) { LoadNum(ChartPlayer.hitRect.width); type = PdtInternalType.Number; value = _numbuf; }
else if (name == _var_h) { LoadNum(ChartPlayer.hitRect.height); type = PdtInternalType.Number; value = _numbuf; }
else if (name == _var_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;
string str;
float num;
if (ContextEvent != null && ContextEvent.PropSrcs.TryGetValue(name, out prop)) {
prop.Get(out type, out value);
}
else if (ContextState != null && ChartPlayer.motionRegistry.ContainsKey(id)) {
var vec = ContextState.GetRawValue(id);
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)) {
type = PdtInternalType.String;
value = GetBytes(str);
RevokePotentialConstant();
}
else {
PropSrc.Arbitrary result = ContextCascadeLookup(name);
if (result != null) {
result.Get(out type, out value);
}
else {
PropSrc.Arbitrary result;
foreach (var cas in ContextCascade) {
if (cas.TryGetValue(name, out result)) {
result.Get(out type, out value);
return;
}
}
type = PdtInternalType.Undefined;
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) {
fixed (byte* ptr = _numbuf) *(float*)ptr = value;
}
@@ -75,76 +73,106 @@ namespace Cryville.Crtr {
}
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;
if (name.Length == 1 && _shortops.TryGetValue(new OperatorSignature(name, pc), out result)) {
if (_shortops.TryGetValue(sig, out result)) {
return result;
}
else if (name == ",") {
result = new op_arr(pc);
_shortops.Add(new OperatorSignature(",", pc), result);
else if (sig.Name == _op_sep) {
result = new op_arr(sig.ParamCount);
_shortops.Add(new PdtOperatorSignature(_op_sep, sig.ParamCount), 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;
}
else if (_ctxops.TryGetValue(name, out result)) {
else if (_ctxops.TryGetValue(sig.Name, out 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) {
switch (name) {
case "&": return param.AsNumber() == 0;
case "|": return param.AsNumber() != 0;
default: throw new KeyNotFoundException(string.Format("Undefined collapse operator {0}", name));
}
static readonly int _colop_and = IdentifierManager.SharedInstance.Request("&");
static readonly int _colop_or = IdentifierManager.SharedInstance.Request("|");
protected override bool Collapse(int name, PdtVariableMemory param) {
if (name == _colop_and) return param.Type == PdtInternalType.Number && param.AsNumber() <= 0;
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 ContainerState ContextState { private get; set; }
public Transform ContextTransform { private get; set; }
public Judge ContextJudge { 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() {
ContextCascade.Add(new Dictionary<string, PropSrc.Arbitrary>());
ContextCascade[_cascadeHeight++].Clear();
}
public void ContextCascadeUpdate(string key, PropSrc.Arbitrary value) {
ContextCascade[ContextCascade.Count - 1][key] = value;
public void ContextCascadeUpdate(int key, PropSrc.Arbitrary 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() {
ContextCascade.RemoveAt(ContextCascade.Count - 1);
--_cascadeHeight;
}
public PdtEvaluator() {
_ctxops.Add("screen_edge", new func_screen_edge(() => ContextTransform));
_ctxops.Add("int", new func_int(() => ContextSelfValue));
_ctxops.Add("clamp", new func_clamp(() => ContextSelfValue));
_ctxops.Add("min", new func_min(() => ContextSelfValue));
_ctxops.Add("max", new func_max(() => ContextSelfValue));
for (int i = 0; i < ContextCascade.Length; i++) ContextCascade[i] = new Dictionary<int, PropSrc.Arbitrary>();
_ctxops.Add(IdentifierManager.SharedInstance.Request("screen_edge"), new func_screen_edge(() => ContextTransform));
_ctxops.Add(IdentifierManager.SharedInstance.Request("int"), new func_int(() => ContextSelfValue));
_ctxops.Add(IdentifierManager.SharedInstance.Request("clamp"), new func_clamp(() => ContextSelfValue));
_ctxops.Add(IdentifierManager.SharedInstance.Request("min"), new func_min(() => ContextSelfValue));
_ctxops.Add(IdentifierManager.SharedInstance.Request("max"), new func_max(() => ContextSelfValue));
_ctxops.Add(IdentifierManager.SharedInstance.Request("abs"), new func_abs(() => ContextSelfValue));
Func<int, PropSrc> cccb = k => ContextCascadeLookup(k);
_ctxops.Add(IdentifierManager.SharedInstance.Request("attack_timing"), new func_attack_timing(cccb));
_ctxops.Add(IdentifierManager.SharedInstance.Request("enter_timing"), new func_enter_timing(cccb));
_ctxops.Add(IdentifierManager.SharedInstance.Request("release_timing"), new func_release_timing(cccb));
_ctxops.Add(IdentifierManager.SharedInstance.Request("leave_timing"), new func_leave_timing(cccb));
_ctxops.Add(IdentifierManager.SharedInstance.Request("contact_timing"), new func_contact_timing(cccb));
}
static PdtEvaluator() {
_shortops.Add(new OperatorSignature("*", 2), new op_mul_2());
_shortops.Add(new OperatorSignature("/", 2), new op_div_2());
_shortops.Add(new OperatorSignature("%", 2), new op_mod_2());
_shortops.Add(new PdtOperatorSignature("@", 2), new op_at_2());
_shortops.Add(new OperatorSignature("+", 1), new op_add_1());
_shortops.Add(new OperatorSignature("+", 2), new op_add_2());
_shortops.Add(new OperatorSignature("-", 1), new op_sub_1());
_shortops.Add(new OperatorSignature("-", 2), new op_sub_2());
_shortops.Add(new PdtOperatorSignature("*", 2), new op_mul_2());
_shortops.Add(new PdtOperatorSignature("/", 2), new op_div_2());
_shortops.Add(new PdtOperatorSignature("%", 2), new op_mod_2());
_shortops.Add(new OperatorSignature("=", 2), new op_eq_2());
_shortops.Add(new OperatorSignature("<", 2), new op_lt_2());
_shortops.Add(new OperatorSignature(">", 2), new op_gt_2());
_shortops.Add(new PdtOperatorSignature("+", 1), new op_add_1());
_shortops.Add(new PdtOperatorSignature("+", 2), new op_add_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
#pragma warning disable IDE1006
#region Basic Operators
class op_add_1 : PdtOperator {
public op_add_1() : base(1) { }
protected override void Execute() {
@@ -218,7 +246,7 @@ namespace Cryville.Crtr {
class op_not_1 : PdtOperator {
public op_not_1() : base(1) { }
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);
}
}
@@ -229,19 +257,39 @@ namespace Cryville.Crtr {
int type = o0.Type;
int len = o0.Length;
bool blit = !IsBlittable(type);
for (var i = 1; i < ParamCount; i++) {
for (var i = 1; i < LoadedOperandCount; i++) {
var o = GetOperand(i);
if (o.Type != type) throw new InvalidOperationException("Cannot create variant type array");
else if (!IsBlittable(o.Type)) blit = true;
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);
}
bool IsBlittable(int type) {
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 {
public func_frame_seq() : base(3) { }
protected override unsafe void Execute() {
@@ -272,6 +320,39 @@ namespace Cryville.Crtr {
}
}
}
class func_in_area : PdtOperator {
public func_in_area() : base(1) { }
protected override unsafe void Execute() {
var arg = GetOperand(0);
if (arg.Type == PdtInternalType.Error) {
throw new InvalidOperationException("Error");
}
else if (arg.Type == PdtInternalType.Number && arg.AsNumber() <= 0) {
GetReturnFrame(PdtInternalType.Null, 0);
}
else {
var ret = GetReturnFrame(arg.Type, arg.Length);
arg.CopyTo(ret);
}
}
}
class func_int_map : PdtOperator {
public func_int_map(int pc) : base(pc) {
if (pc < 4) throw new ArgumentOutOfRangeException("Too few parameters for int_map");
}
protected override unsafe void Execute() {
var value = GetOperand(0).AsNumber();
var offset = GetOperand(1).AsNumber();
var step = GetOperand(2).AsNumber();
var index = (int)((value - offset) / step);
if (index < 0 || index >= LoadedOperandCount - 3) index = 0;
var hit = GetOperand(index + 3);
var ret = GetReturnFrame(hit.Type, hit.Length);
hit.CopyTo(ret);
}
}
#endregion
#region Contextual Functions
class func_screen_edge : PdtOperator {
readonly Func<Transform> _ctxcb;
public func_screen_edge(Func<Transform> ctxcb) : base(1) {
@@ -361,10 +442,93 @@ namespace Cryville.Crtr {
ret.SetNumber(Mathf.Max(a, b));
}
}
class func_abs : PdtOperator {
readonly Func<PropSrc> _ctxcb;
public func_abs(Func<PropSrc> ctxcb) : base(1) {
_ctxcb = ctxcb;
}
protected override unsafe void Execute() {
var ret = GetReturnFrame(PdtInternalType.Number, sizeof(float));
float arg;
switch (LoadedOperandCount) {
case 0: arg = oputil.AsNumber(_ctxcb()); break;
case 1: arg = GetOperand(0).AsNumber(); break;
default: throw new ArgumentException("Argument count not 0 or 1");
}
ret.SetNumber(Mathf.Abs(arg));
}
}
#endregion
#region Judge Functions
static readonly int _var_fn = IdentifierManager.SharedInstance.Request("fn");
static readonly int _var_tn = IdentifierManager.SharedInstance.Request("tn");
static readonly int _var_ft = IdentifierManager.SharedInstance.Request("ft");
static readonly int _var_tt = IdentifierManager.SharedInstance.Request("tt");
static readonly int _var_fv = IdentifierManager.SharedInstance.Request("fv");
static readonly int _var_tv = IdentifierManager.SharedInstance.Request("tv");
abstract class JudgeFunction : PdtOperator {
readonly Func<int, PropSrc> _ctxcb;
protected JudgeFunction(int pc, Func<int, PropSrc> ctxcb) : base(pc) {
_ctxcb = ctxcb;
}
protected sealed override void Execute() {
var ret = GetReturnFrame(PdtInternalType.Number, sizeof(float));
var fn = oputil.AsNumber(_ctxcb(_var_fn));
var tn = oputil.AsNumber(_ctxcb(_var_tn));
var ft = oputil.AsNumber(_ctxcb(_var_ft));
var tt = oputil.AsNumber(_ctxcb(_var_tt));
var fv = oputil.AsVector(_ctxcb(_var_fv));
var tv = oputil.AsVector(_ctxcb(_var_tv));
ret.SetNumber(ExecuteImpl(fn, tn, ft, tt, fv, tv) ? 1 : 0);
}
protected abstract bool ExecuteImpl(float fn, float tn, float ft, float tt, Vector3? fv, Vector3? tv);
}
class func_attack_timing : JudgeFunction {
public func_attack_timing(Func<int, PropSrc> ctxcb) : base(2, ctxcb) { }
protected override bool ExecuteImpl(float fn, float tn, float ft, float tt, Vector3? fv, Vector3? tv) {
if (fv != null) return false;
var t0 = GetOperand(0).AsNumber() + fn;
var t1 = GetOperand(1).AsNumber() + tn;
return tt > t0 && tt <= t1;
}
}
class func_enter_timing : JudgeFunction {
public func_enter_timing(Func<int, PropSrc> ctxcb) : base(1, ctxcb) { }
protected override bool ExecuteImpl(float fn, float tn, float ft, float tt, Vector3? fv, Vector3? tv) {
if (fv == null || tv == null) return false;
var t0 = GetOperand(0).AsNumber() + fn;
return ft < t0 && tt >= t0;
}
}
class func_release_timing : JudgeFunction {
public func_release_timing(Func<int, PropSrc> ctxcb) : base(2, ctxcb) { }
protected override bool ExecuteImpl(float fn, float tn, float ft, float tt, Vector3? fv, Vector3? tv) {
if (tv != null) return false;
var t0 = GetOperand(0).AsNumber() + fn;
var t1 = GetOperand(1).AsNumber() + tn;
return ft > t0 && ft <= t1;
}
}
class func_leave_timing : JudgeFunction {
public func_leave_timing(Func<int, PropSrc> ctxcb) : base(1, ctxcb) { }
protected override bool ExecuteImpl(float fn, float tn, float ft, float tt, Vector3? fv, Vector3? tv) {
if (fv == null || tv == null) return false;
var t1 = GetOperand(0).AsNumber() + tn;
return ft < t1 && tt >= t1;
}
}
class func_contact_timing : JudgeFunction {
public func_contact_timing(Func<int, PropSrc> ctxcb) : base(2, ctxcb) { }
protected override bool ExecuteImpl(float fn, float tn, float ft, float tt, Vector3? fv, Vector3? tv) {
var t0 = GetOperand(0).AsNumber() + fn;
var t1 = GetOperand(1).AsNumber() + tn;
return (fv == null || ft < t1) && (tv == null || tt >= t0);
}
}
#endregion
unsafe static class oputil {
public static float AsNumber(PropSrc src) {
if (src == null)
throw new ArgumentNullException("src");
if (src == null) throw new ArgumentNullException("src");
int type; byte[] value;
src.Get(out type, out value);
if (type != PdtInternalType.Number)
@@ -373,6 +537,25 @@ namespace Cryville.Crtr {
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
#endregion

View File

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

View File

@@ -1,4 +1,5 @@
using Cryville.Common.Pdt;
using Cryville.Common;
using Cryville.Common.Pdt;
using System;
using System.Collections.Generic;
using System.Reflection;
@@ -7,11 +8,20 @@ using RBeatTime = Cryville.Crtr.BeatTime;
namespace Cryville.Crtr {
public abstract class PropOp : PdtOperator {
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 {
readonly Action<bool> _cb;
public Boolean(Action<bool> cb) { _cb = cb; }
protected override void Execute() {
_cb(GetOperand(0).AsNumber() != 0);
_cb(GetOperand(0).AsNumber() > 0);
}
}
public class Integer : PropOp {
@@ -35,15 +45,22 @@ namespace Cryville.Crtr {
_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 {
readonly static Dictionary<string, int> _cache = new Dictionary<string, int>();
readonly static Dictionary<int, int> _cache = new Dictionary<int, int>();
readonly Action<T> _cb;
public Enum(Action<T> cb) {
if (!typeof(T).IsEnum)
throw new ArgumentException("Type is not enum");
var names = typeof(T).GetFields(BindingFlags.Public | BindingFlags.Static);
for (int i = 0; i < names.Length; i++)
_cache[names[i].Name] = Convert.ToInt32(names[i].GetValue(null));
_cache[IdentifierManager.SharedInstance.Request(names[i].Name)] = Convert.ToInt32(names[i].GetValue(null));
_cb = cb;
}
protected override void Execute() {

View File

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

View File

@@ -6,6 +6,8 @@ using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using SIdentifier = Cryville.Common.Identifier;
namespace Cryville.Crtr {
public class Ruleset {
@@ -31,9 +33,9 @@ namespace Cryville.Crtr {
[Binder(typeof(PdtRulesetBinder))]
public class PdtRuleset {
public Dictionary<string, InputDefinition> inputs;
public Dictionary<string, JudgeDefinition> judges;
public Dictionary<string, ScoreDefinition> scores;
public Dictionary<Identifier, InputDefinition> inputs;
public Dictionary<Identifier, JudgeDefinition> judges;
public Dictionary<Identifier, ScoreDefinition> scores;
public Constraint constraints;
public void Optimize(PdtEvaluatorBase etor) {
foreach (var i in inputs.Values) {
@@ -42,10 +44,13 @@ namespace Cryville.Crtr {
}
}
foreach (var j in judges.Values) {
if (j.clip != null) etor.Optimize(j.clip);
if (j.hit != null) etor.Optimize(j.hit);
if (j.scores != null) foreach (var e in j.scores.Values) {
etor.Optimize(e);
if (j.scores != null) {
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) {
@@ -58,16 +63,7 @@ namespace Cryville.Crtr {
}
}
public class Constraint {
class ArbitraryOp : PropOp {
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();
static readonly PropOp.Arbitrary _arbop = new PropOp.Arbitrary();
[ElementList]
public Dictionary<RulesetSelectors, Constraint> Elements = new Dictionary<RulesetSelectors, Constraint>();
[PropertyList]
@@ -96,7 +92,7 @@ namespace Cryville.Crtr {
etor.ContextSelfValue = null;
break;
case PropertyType.Variable:
_arbop.name = name;
_arbop.Name = name;
etor.Evaluate(_arbop, prop.Value);
break;
default: throw new NotSupportedException("Unknown property key type");
@@ -114,16 +110,16 @@ namespace Cryville.Crtr {
}
public class PropertyKey {
public PropertyType Type { get; private set; }
public string Name { get; private set; }
public int Name { get; private set; }
public PropertyKey(PropertyType type, string name) {
Type = type;
Name = name;
Name = IdentifierManager.SharedInstance.Request(name);
}
public override string ToString() {
switch (Type) {
case PropertyType.Property: return Name;
case PropertyType.Variable: return "@var " + Name;
default: return string.Format("<{0}> {1}", Type, Name);
case PropertyType.Property: return (string)IdentifierManager.SharedInstance.Retrieve(Name);
case PropertyType.Variable: return string.Format("@var {0}", IdentifierManager.SharedInstance.Retrieve(Name));
default: return string.Format("<{0}> {1}", Type, IdentifierManager.SharedInstance.Retrieve(Name));
}
}
}
@@ -151,39 +147,73 @@ namespace Cryville.Crtr {
return result;
}
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);
return result;
}
else if (type.Equals(typeof(string[]))) {
string[] result = null;
else if (type.Equals(typeof(Identifier[]))) {
Identifier[] result = null;
ChartPlayer.etor.Evaluate(new pop_identstrarr(r => result = r), exp);
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);
}
#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 {
readonly Action<string> _cb;
public pop_identstr(Action<string> cb) { _cb = cb; }
readonly Action<SIdentifier> _cb;
public pop_identstr(Action<SIdentifier> cb) { _cb = cb; }
protected override void Execute() {
var op = GetOperand(0);
if (op.Type == PdtInternalType.Undefined) _cb(op.AsIdentifier());
else if (op.Type == PdtInternalType.String) _cb(op.AsString());
if (op.Type == PdtInternalType.Undefined) _cb(new SIdentifier(op.AsIdentifier()));
else if (op.Type == PdtInternalType.String) _cb(new SIdentifier(op.AsString()));
else throw new InvalidCastException("Not an identifier or string");
}
}
class pop_identstrarr : PdtOperator {
readonly Action<string[]> _cb;
public pop_identstrarr(Action<string[]> cb) : base(16) { _cb = cb; }
readonly Action<SIdentifier[]> _cb;
public pop_identstrarr(Action<SIdentifier[]> cb) : base(16) { _cb = cb; }
protected override void Execute() {
var result = new string[LoadedOperandCount];
var result = new SIdentifier[LoadedOperandCount];
for (int i = 0; i < LoadedOperandCount; i++) {
var op = GetOperand(i);
if (op.Type != PdtInternalType.Undefined)
throw new InvalidCastException("Not an identifier");
result[i] = op.AsIdentifier();
result[i] = new SIdentifier(op.AsIdentifier());
}
_cb(result);
}

View File

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

View File

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

View File

@@ -30,6 +30,8 @@ namespace Cryville.Crtr {
ChartPlayer.etor.ContextTransform = obj;
ChartPlayer.etor.ContextEvent = context.Container;
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.ContextEvent = context.Container;
ChartPlayer.etor.Evaluate(GetPropOp(obj, p.Key), p.Value);
ChartPlayer.etor.ContextEvent = null;
ChartPlayer.etor.ContextTransform = null;
}
}
Profiler.EndSample();

View File

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

View File

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

View File

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

Binary file not shown.

View File

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

View File

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

Binary file not shown.

View File

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

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

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