42 Commits

Author SHA1 Message Date
87362b47c5 Cleanup CategorizedPool. 2023-02-12 17:27:54 +08:00
f60ba1088d Fix input conflict in input config. 2023-02-12 17:27:15 +08:00
abb7ad6f24 Adjust offset for osu chart converter. 2023-02-11 23:13:30 +08:00
880b475c07 Update project version. 2023-02-11 23:12:01 +08:00
4707c40e6a Add object pool related debug status info. 2023-02-11 23:11:45 +08:00
7f87c23da2 Fix contextual state variables available in static context. 2023-02-11 23:11:15 +08:00
6df10837fe Eliminate Array.Copy GC in SquareMatrix. 2023-02-11 23:09:46 +08:00
42cb54de1d Add RentedCount for ObjectPool. 2023-02-11 23:09:05 +08:00
9fd685b8b3 Pull up CategorizedPool. Add Reset method for ObjectPool. 2023-02-11 23:08:43 +08:00
b364005741 Update UnsafeIL. 2023-02-10 17:52:45 +08:00
7d938de409 Code cleanup. 2023-02-10 17:36:36 +08:00
bb4ecfcd8c Add graphical offset global settings. 2023-02-10 17:36:19 +08:00
ff410529b0 Add invisible_bounds contextual variable. 2023-02-10 17:35:36 +08:00
fdc55a8e3b Pull current_time to container handler. 2023-02-10 17:34:40 +08:00
fc8512ff63 Combine score and score string property sources. 2023-02-10 17:32:59 +08:00
1b1ed42a1b Code cleanup. 2023-02-10 15:50:49 +08:00
b437925f92 Replace TrustedAsOfLength with safe As and Set. 2023-02-10 15:47:20 +08:00
c04e50e959 Modify priority logic for normal/temporary events. 2023-02-09 18:22:39 +08:00
314cdb9935 Implement transform update for static judge anchor. 2023-02-09 18:21:17 +08:00
77c91d015a Add standalone event property. 2023-02-09 18:20:36 +08:00
291a018c13 Activates anchors only on set. 2023-02-09 18:19:46 +08:00
18ff4b8e16 Code cleanup. 2023-02-09 18:18:34 +08:00
7714c277fd Modify text in status debug info. 2023-02-09 18:14:07 +08:00
d6c2ac6be6 Fix TypedChildren shared across ContainerState. 2023-02-09 18:12:33 +08:00
682fe38d40 Fix priority for manually set special anchors. 2023-02-09 18:11:32 +08:00
3e525842cb Modify texts in input config panel. 2023-02-09 18:09:40 +08:00
3dd25b51a8 Fix wrong context access in component creation. 2023-02-09 18:08:12 +08:00
041c1e374e Optimize GC for frame calculation. 2023-02-09 18:07:06 +08:00
16b1d323dc Add exception handling for invalid key interpretation in PDT. 2023-02-09 12:21:41 +08:00
c4d5e5f480 Matches member name first then generic list in PDT. 2023-02-09 12:15:07 +08:00
187f07d2c9 Optimize GC for motions. 2023-02-07 23:15:52 +08:00
4e9d7e5b87 Optimize GC for SectionalGameObject. 2023-02-07 23:15:11 +08:00
7df5b15e2e Animation cleanup. 2023-02-07 16:36:17 +08:00
4863aa0ae7 Add persist in judge definition. 2023-02-07 16:24:27 +08:00
eb53c3465b Implement pausing. 2023-02-07 16:23:16 +08:00
f683d61298 Reorganize resources. 2023-02-07 14:20:47 +08:00
fbd03c8037 Add sound offset for ruleset config. 2023-02-06 22:55:43 +08:00
da68c8b877 Move ruleset config to main scene. Add title for UI. 2023-02-06 22:55:14 +08:00
c0744a3464 Add interval function. 2023-02-06 15:16:35 +08:00
3ca3746cec Fix judge passing for inputs without any events. 2023-02-06 15:16:02 +08:00
5e76ddf2cd Fix use of discarded digits in rounded numbers in string formatter. 2023-02-06 15:14:54 +08:00
dca1ba304e Code cleanup. 2023-02-05 23:01:46 +08:00
76 changed files with 699 additions and 334 deletions

Binary file not shown.

Binary file not shown.

View File

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

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

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

Binary file not shown.

View File

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

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,7 +1,21 @@
using System;
namespace Cryville.Common.Pdt {
/// <summary>
/// Indicates that the attributed member is an element list.
/// </summary>
/// <remarks>
/// <para>An element list is a <see cref="System.Collections.IDictionary" /> that represents a collection of PDT elements. There must be at most one element list in a class.</para>
/// </remarks>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class ElementListAttribute : Attribute { }
public class ComponentListAttribute : Attribute { }
/// <summary>
/// Indicates that the attributed member is a property list.
/// </summary>
/// <remarks>
/// <para>A property list is a <see cref="System.Collections.IDictionary" /> that represents a collection of PDT properties. There must be at most one property list in a class.</para>
/// </remarks>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class PropertyListAttribute : Attribute { }
}

View File

@@ -11,7 +11,7 @@ namespace Cryville.Common.Pdt {
/// <summary>
/// Whether the value of this expression is constant.
/// </summary>
/// <remarks>The value of this property is <c>false</c> until it is optimized.</remarks>
/// <remarks>The value of this property is <see langword="false" /> until it is optimized.</remarks>
public bool IsConstant { get; internal set; }
internal bool IsPotentialConstant;
internal PdtExpression(LinkedList<PdtInstruction> ins) {

View File

@@ -34,9 +34,9 @@ namespace Cryville.Common.Pdt {
0x0001, 0x0080, 0x0100, 0x0000, 0x0030, 0x0080, 0x0080, 0x0000, 0x0200, 0x0400, 0x0080, 0x0080, 0x0080, 0x0080, 0x0040, 0x0080,
0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x1000, 0x1800, 0x0080, 0x0080, 0x0080, 0x0030,
0x0080, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030,
0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0000, 0x0000, 0x0000, 0x0000, 0x0030,
0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0000, 0x0080, 0x0000, 0x0080, 0x0030,
0x0000, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030,
0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x1000, 0x0080, 0x1000, 0x0000, 0x0000,
0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x1000, 0x0080, 0x1000, 0x0080, 0x0000,
};
/// <summary>
@@ -57,40 +57,90 @@ namespace Cryville.Common.Pdt {
return (T)new PdtInterpreter(src, typeof(T), binder).Interpret();
}
/// <summary>
/// The source string.
/// </summary>
public string Source { get; private set; }
readonly Type _type;
readonly Binder _binder;
/// <summary>
/// The current position in the string being parsed by the interpreter.
/// </summary>
public int Position { get; private set; }
#pragma warning disable IDE1006
/// <summary>
/// The character at the current position.
/// </summary>
/// <exception cref="IndexOutOfRangeException">The end of the source string is reached.</exception>
protected char cc { get { return Source[Position]; } }
/// <summary>
/// The category of the character.
/// </summary>
/// <exception cref="IndexOutOfRangeException">The end of the source string is reached.</exception>
protected int ct { get { return cm[cc]; } }
protected string tokenb(int flag) { // Token Whitelist
/// <summary>
/// Reads a token until a character of type <paramref name="flag" /> is met.
/// </summary>
/// <param name="flag">The type filter.</param>
/// <returns>A token from the current position (inclusive) to the next character of type <paramref name="flag" /> (exclusive).</returns>
/// <exception cref="IndexOutOfRangeException">No character of type <paramref name="flag" /> is met.</exception>
protected string tokenb(int flag) {
int sp = Position;
while ((ct & flag) == 0) Position++;
return Source.Substring(sp, Position - sp);
}
protected string tokenw(int flag) { // Token Whitelist
/// <summary>
/// Reads a token until a character that is not of type <paramref name="flag" /> is met.
/// </summary>
/// <param name="flag">The type filter.</param>
/// <returns>A token from the current position (inclusive) to the next character that is not of type <paramref name="flag" /> (exclusive).</returns>
/// <exception cref="IndexOutOfRangeException">No character that is not of type <paramref name="flag" /> is met.</exception>
protected string tokenw(int flag) {
int sp = Position;
while ((ct & flag) != 0) Position++;
return Source.Substring(sp, Position - sp);
}
/// <summary>
/// Skips over whitespaces.
/// </summary>
/// <exception cref="IndexOutOfRangeException">The end of the source string is reached.</exception>
protected void ws() {
while ((ct & 0x0001) != 0) Position++;
}
#pragma warning restore IDE1006
/// <summary>
/// Reads the current character and increments the position.
/// </summary>
/// <returns>The current character.</returns>
/// <exception cref="IndexOutOfRangeException">The end of the source string is reached.</exception>
protected char GetChar() {
char r = cc;
Position++;
return r;
}
/// <summary>
/// Reads an identifier.
/// </summary>
/// <returns>An identifier.</returns>
/// <exception cref="IndexOutOfRangeException">The end of the source string is reached.</exception>
protected string GetIdentifier() {
if ((ct & 0x0020) == 0) return "";
return tokenw(0x0010);
}
/// <summary>
/// Reads a number.
/// </summary>
/// <returns>A number.</returns>
/// <exception cref="IndexOutOfRangeException">The end of the source string is reached.</exception>
protected string GetNumber() {
return tokenw(0x0040);
}
/// <summary>
/// Reads a string.
/// </summary>
/// <returns>A string.</returns>
/// <exception cref="IndexOutOfRangeException">The end of the source string is reached.</exception>
protected string GetString() {
int sp = Position;
do {
@@ -100,6 +150,11 @@ namespace Cryville.Common.Pdt {
Position++;
return Regex.Replace(Source.Substring(sp + 1, Position - sp - 2), @"\\(.)", "$1");
}
/// <summary>
/// Reads an expression.
/// </summary>
/// <returns>An expression.</returns>
/// <exception cref="IndexOutOfRangeException">The end of the source string is reached.</exception>
protected PdtExpression GetExp() {
var ins = new LinkedList<PdtInstruction>();
int _;
@@ -167,7 +222,7 @@ namespace Cryville.Common.Pdt {
}
object InterpretObject(Type type) {
var result = ReflectionHelper.InvokeEmptyConstructor(type);
bool dictflag = ReflectionHelper.IsGenericDictionary(type);
bool dictflag = typeof(IDictionary).IsAssignableFrom(type);
while (true) {
try { ws(); }
catch (IndexOutOfRangeException) { return result; }
@@ -183,19 +238,20 @@ namespace Cryville.Common.Pdt {
((IDictionary)result).Add(key, value);
}
else {
MemberInfo prop;
bool flag = ReflectionHelper.TryFindMemberWithAttribute<ElementListAttribute>(type, out prop);
if (!flag && pkey is string) prop = ReflectionHelper.GetMember(type, (string)pkey);
MemberInfo prop = null;
bool flag = false;
if (pkey is string) prop = ReflectionHelper.GetMember(type, (string)pkey);
if (prop == null) flag = ReflectionHelper.TryFindMemberWithAttribute<ElementListAttribute>(type, out prop);
if (prop == null) throw new MissingMemberException(string.Format("The property \"{0}\" is not found", pkey));
Type ptype = ReflectionHelper.GetMemberType(prop);
if (ReflectionHelper.IsGenericDictionary(ptype)) {
if (flag) {
if (!typeof(IDictionary).IsAssignableFrom(ptype))
throw new InvalidOperationException("Internal error: Element list is not a dictionary");
var ktype = ptype.GetGenericArguments()[0];
var vtype = ptype.GetGenericArguments()[1];
if (flag) {
object key = _binder.ChangeType(pkey, ktype, null);
object value = InterpretObject(vtype);
((IDictionary)ReflectionHelper.GetValue(prop, result)).Add(key, value);
}
else ReflectionHelper.SetValue(prop, result, InterpretObject(ptype));
object key = _binder.ChangeType(pkey, ktype, null);
object value = InterpretObject(vtype);
((IDictionary)ReflectionHelper.GetValue(prop, result)).Add(key, value);
}
else ReflectionHelper.SetValue(prop, result, InterpretObject(ptype));
}
@@ -211,28 +267,38 @@ namespace Cryville.Common.Pdt {
((IDictionary)result).Add(key, value);
}
else {
MemberInfo prop;
bool flag = ReflectionHelper.TryFindMemberWithAttribute<PropertyListAttribute>(type, out prop);
if (!flag && pkey is string) prop = ReflectionHelper.GetMember(type, (string)pkey);
MemberInfo prop = null;
bool flag = false;
if (pkey is string) prop = ReflectionHelper.GetMember(type, (string)pkey);
if (prop == null) flag = ReflectionHelper.TryFindMemberWithAttribute<PropertyListAttribute>(type, out prop);
if (prop == null) throw new MissingMemberException(string.Format("The property \"{0}\" is not found", pkey));
var ptype = ReflectionHelper.GetMemberType(prop);
if (!typeof(IDictionary).IsAssignableFrom(ptype)) {
object value = _binder.ChangeType(exp, ptype, null);
ReflectionHelper.SetValue(prop, result, value, _binder);
}
else {
if (flag) {
if (!typeof(IDictionary).IsAssignableFrom(ptype))
throw new InvalidOperationException("Internal error: Property list is not a dictionary");
var ktype = ptype.GetGenericArguments()[0];
var vtype = ptype.GetGenericArguments()[1];
object key = _binder.ChangeType(pkey, ktype, null);
object value = _binder.ChangeType(exp, vtype, null);
((IDictionary)ReflectionHelper.GetValue(prop, result)).Add(key, value);
}
else {
object value = _binder.ChangeType(exp, ptype, null);
ReflectionHelper.SetValue(prop, result, value, _binder);
}
}
break;
case '}':
return result;
default:
throw new InvalidOperationException("Internal error: Invalid key interpretation");
}
}
}
/// <summary>
/// Interprets a key from the current position.
/// </summary>
/// <returns>The interpreted key.</returns>
protected virtual object InterpretKey(Type type) {
return tokenb(0x1000).Trim();
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -109,10 +109,11 @@ namespace Cryville.Crtr {
public float BeatOffset;
[JsonIgnore]
public abstract int Priority {
get;
}
public abstract int Priority { get; }
[JsonIgnore]
public virtual bool Standalone { get { return false; } }
public ChartEvent Clone() {
return (ChartEvent)MemberwiseClone();
}
@@ -259,9 +260,7 @@ namespace Cryville.Crtr {
}
}
public override int Priority {
get { return 10; }
}
public override int Priority { get { return 10; } }
public class Group : EventContainer {
public List<Track> tracks = new List<Track>();
@@ -281,15 +280,11 @@ namespace Cryville.Crtr {
default: return base.GetEventsOfType(type);
}
}
public override int Priority {
get { return 10; }
}
public override int Priority { get { return 10; } }
}
public class Track : EventContainer {
public override int Priority {
get { return 10; }
}
public override int Priority { get { return 10; } }
}
public class Motion : ChartEvent {
@@ -375,9 +370,7 @@ namespace Cryville.Crtr {
[DefaultValue(0.0f)]
public float sumfix = 0.0f;
public override int Priority {
get { return -2; }
}
public override int Priority { get { return -2; } }
public Motion() {
SubmitPropOp("motion", new PropOp.String(v => motion = v));
@@ -413,9 +406,7 @@ namespace Cryville.Crtr {
default: return base.GetEventsOfType(type);
}
}
public override int Priority {
get { return 12; }
}
public override int Priority { get { return 12; } }
}
public class Judge : ChartEvent {
@@ -428,9 +419,8 @@ namespace Cryville.Crtr {
}
#pragma warning restore IDE1006
public override int Priority {
get { return 0; }
}
public override int Priority { get { return 0; } }
public override bool Standalone { get { return true; } }
public Judge() {
SubmitPropSrc("name", new PropSrc.Identifier(() => Id.Key));
@@ -444,9 +434,7 @@ namespace Cryville.Crtr {
public class Signature : ChartEvent {
public float? tempo;
public override int Priority {
get { return -4; }
}
public override int Priority { get { return -4; } }
}
public List<Sound> sounds;
@@ -457,9 +445,7 @@ namespace Cryville.Crtr {
// TODO [Obsolete]
public float offset;
public override int Priority {
get { return 0; }
}
public override int Priority { get { return 0; } }
}
}
}

View File

@@ -63,6 +63,7 @@ namespace Cryville.Crtr {
static double renderStep = 0.05;
public static double actualRenderStep = 0;
static bool autoRenderStep = false;
public static float graphicalOffset = 0;
public static float soundOffset = 0;
static float startOffset = 0;
public static float sv = 16f;
@@ -133,7 +134,7 @@ namespace Cryville.Crtr {
if (forceSyncFrames != 0) {
forceSyncFrames--;
double target = Game.AudioClient.Position - atime0;
dt = target - cbus.Time;
dt = target - cbus.Time - graphicalOffset;
step = autoRenderStep ? 1f / Application.targetFrameRate : renderStep;
inputProxy.SyncTime(target);
}
@@ -142,6 +143,7 @@ namespace Cryville.Crtr {
step = autoRenderStep ? Time.smoothDeltaTime : renderStep;
}
inputProxy.ForceTick();
if (paused) return;
cbus.ForwardByTime(dt);
bbus.ForwardByTime(dt);
UnityEngine.Profiling.Profiler.BeginSample("ChartPlayer.Forward");
@@ -258,15 +260,19 @@ namespace Cryville.Crtr {
);
if (started) {
statusbuf.AppendFormat(
"\nStates: c{0} / b{1}",
cbus.ActiveStateCount, bbus.ActiveStateCount
"\nStates: c{0} / b{1}\nPools: RMV {2}, MC {3}",
cbus.ActiveStateCount, bbus.ActiveStateCount,
ContainerState.RMVPool.RentedCount,
ContainerState.MCPool.RentedCount
);
statusbuf.AppendFormat(
"\nSTime: {0:G17}s {3}\ndATime: {1:+0.0ms;-0.0ms;0} {3}\ndITime: {2:+0.0ms;-0.0ms;0} {3}",
"\nSTime: {0:G17}s {3} {4}\ndATime: {1:+0.0ms;-0.0ms;0} {3} {4}\ndITime: {2:+0.0ms;-0.0ms;0} {3} {5}",
cbus.Time,
(Game.AudioClient.Position - atime0 - cbus.Time) * 1e3,
(inputProxy.GetTimestampAverage() - cbus.Time) * 1e3,
forceSyncFrames != 0 ? "(force sync)" : ""
forceSyncFrames != 0 ? "(force sync)" : "",
paused ? "(paused)" : "",
paused ? "(semi-locked)" : ""
);
if (judge != null) {
statusbuf.Append("\n== Scores ==\n");
@@ -319,6 +325,20 @@ namespace Cryville.Crtr {
else Logger.Log("main", 2, "Load/MainThread", "The chart is currently loading");
}
}
bool paused = false;
public void TogglePause() {
paused = !paused;
if (!paused) {
forceSyncFrames = Settings.Default.ForceSyncFrames;
Game.AudioClient.Start();
inputProxy.UnlockTime();
}
else {
Game.AudioClient.Pause();
inputProxy.LockTime();
}
}
#endregion
#region Load
@@ -329,9 +349,10 @@ namespace Cryville.Crtr {
renderStep = Settings.Default.RenderStep;
actualRenderStep = renderStep;
autoRenderStep = renderStep == 0;
graphicalOffset = Settings.Default.GraphicalOffset;
soundOffset = Settings.Default.SoundOffset;
startOffset = Settings.Default.StartOffset;
forceSyncFrames= Settings.Default.ForceSyncFrames;
forceSyncFrames = Settings.Default.ForceSyncFrames;
texloaddone = false;
Game.NetworkTaskWorker.SuspendBackgroundTasks();
Game.AudioSession = Game.AudioSequencer.NewSession();
@@ -368,6 +389,7 @@ namespace Cryville.Crtr {
});
}
sv = _rscfg.generic.ScrollVelocity;
soundOffset += _rscfg.generic.SoundOffset;
FileInfo skinFile = new FileInfo(
string.Format("{0}/skins/{1}/{2}/.umgs", Game.GameDataPath, rulesetFile.Directory.Name, _rscfg.generic.Skin)
@@ -447,6 +469,7 @@ namespace Cryville.Crtr {
public void Stop() {
try {
Logger.Log("main", 1, "Game", "Stopping");
Game.AudioClient.Start();
Game.AudioSession = Game.AudioSequencer.NewSession();
inputProxy.Deactivate();
if (nbus != null) { nbus.Dispose(); nbus = null; }
@@ -496,8 +519,6 @@ namespace Cryville.Crtr {
try {
workerTimer = new diag::Stopwatch();
workerTimer.Start();
RMVPool.Prepare();
MotionCachePool.Prepare();
LoadChart(info);
workerTimer.Stop();
Logger.Log("main", 1, "Load/WorkerThread", "Worker thread done ({0}ms)", workerTimer.Elapsed.TotalMilliseconds);
@@ -533,7 +554,7 @@ namespace Cryville.Crtr {
LoadSkin(info.skinFile);
Logger.Log("main", 0, "Load/WorkerThread", "Initializing judge and input");
judge = new Judge(pruleset);
judge = new Judge(this, pruleset);
etor.ContextJudge = judge;
inputProxy = new InputProxy(pruleset, judge);
@@ -586,6 +607,8 @@ namespace Cryville.Crtr {
pruleset = ruleset.Root;
pruleset.Optimize(etor);
}
ContainerState.RMVPool = new RMVPool();
ContainerState.MCPool = new MotionCachePool();
}
void LoadSkin(FileInfo file) {

View File

@@ -80,11 +80,10 @@ namespace Cryville.Crtr.Components {
var o = GetOperand(0);
if (o.Type != PdtInternalType.Vector) throw new ArgumentException("Not a vector");
_self._shapeLength = (o.Length - sizeof(int)) / sizeof(Vector2);
var ptr = (Vector2*)o.TrustedAsOfLength(sizeof(Vector2));
if (_self._shape != null) _shapePool.Return(_self._shape);
_self._shape = _shapePool.Rent(_self._shapeLength);
for (int i = 0; i < _self._shapeLength; i++) {
_self._shape[i] = ptr[i];
_self._shape[i] = o.As<Vector2>(i * sizeof(Vector2));
}
}
}
@@ -104,6 +103,7 @@ namespace Cryville.Crtr.Components {
public SpriteInfo body = new SpriteInfo();
public SpriteInfo tail = new SpriteInfo();
Material[] mats;
List<Vector3> vertices;
List<float> lengths;
float sumLength = 0;
@@ -112,7 +112,7 @@ namespace Cryville.Crtr.Components {
base.Init();
mesh.Init(transform);
var mats = mesh.Renderer.materials = new Material[] { mesh.NewMaterial, mesh.NewMaterial, mesh.NewMaterial };
mats = mesh.Renderer.materials = new Material[] { mesh.NewMaterial, mesh.NewMaterial, mesh.NewMaterial };
head.Bind(mats[0]);
body.Bind(mats[1]);
tail.Bind(mats[2]);
@@ -123,7 +123,7 @@ namespace Cryville.Crtr.Components {
protected override void OnDestroy() {
base.OnDestroy();
Reset();
foreach (var m in mesh.Renderer.materials) Material.Destroy(m);
foreach (var m in mats) Material.Destroy(m);
if (_shape != null) _shapePool.Return(_shape);
if (vertices != null) {
_ptPool.Return(vertices);
@@ -152,7 +152,7 @@ namespace Cryville.Crtr.Components {
List<Vector3> verts;
List<Vector2> uvs;
List<int> trih = null, trib = null, trit = null;
static List<int> _emptyTris = new List<int>();
static readonly List<int> _emptyTris = new List<int>();
public override void Seal() {
if (vertCount <= 1 || sumLength == 0) return;

View File

@@ -16,10 +16,10 @@ namespace Cryville.Crtr.Components {
public op_set_bound(SpriteBase self) : base(2) {
_self = self;
}
protected unsafe override void Execute() {
protected override void Execute() {
_self.SetBound(
*(Vector2*)GetOperand(0).TrustedAsOfLength(sizeof(Vector2)),
*(Vector3*)GetOperand(1).TrustedAsOfLength(sizeof(Vector3))
GetOperand(0).As<Vector2>(),
GetOperand(1).As<Vector3>()
);
}
}

View File

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

View File

@@ -7,7 +7,7 @@ using UnityEngine.UI;
namespace Cryville.Crtr.Config {
public class InputConfigPanel : MonoBehaviour {
[SerializeField]
ConfigScene m_configScene;
ConfigPanelMaster m_configScene;
[SerializeField]
GameObject m_inputDialog;
@@ -24,7 +24,7 @@ namespace Cryville.Crtr.Config {
[SerializeField]
GameObject m_prefabInputConfigEntry;
readonly SimpleInputConsumer _consumer = new SimpleInputConsumer(Game.InputManager);
SimpleInputConsumer _consumer;
public InputProxy proxy;
readonly Dictionary<string, InputConfigPanelEntry> _entries = new Dictionary<string, InputConfigPanelEntry>();
@@ -50,7 +50,10 @@ namespace Cryville.Crtr.Config {
CloseDialog();
}
void Start() {
public void OnConfigEnable() {
CallHelper.Purge(m_entryList);
_entries.Clear();
_consumer = new SimpleInputConsumer(Game.InputManager);
_consumer.Activate();
foreach (var i in m_configScene.ruleset.Root.inputs) {
var e = GameObject.Instantiate(m_prefabInputConfigEntry, m_entryList.transform).GetComponent<InputConfigPanelEntry>();
@@ -61,13 +64,12 @@ namespace Cryville.Crtr.Config {
proxy.ProxyChanged += OnProxyChanged;
}
void OnDestroy() {
public void OnConfigDisable() {
_consumer.Deactivate();
}
void OnProxyChanged(object sender, ProxyChangedEventArgs e) {
_entries[e.Name].SetEnabled(!e.Used);
_entries[e.Name].SetValue(e.Proxy == null ? "None" : e.Proxy.Value.Handler.GetTypeName(e.Proxy.Value.Type));
_entries[e.Name].OnProxyChanged(e);
}
readonly List<InputSource?> _recvsrcs = new List<InputSource?>();
@@ -83,7 +85,7 @@ namespace Cryville.Crtr.Config {
if (_recvsrcs.Contains(src)) return;
_recvsrcs.Add(src);
var obj = Instantiate(m_prefabListItem, m_deviceList);
obj.transform.Find("Text").GetComponent<Text>().text = src == null ? "None" : src.Value.Handler.GetTypeName(src.Value.Type);
obj.transform.Find("Text").GetComponent<Text>().text = src == null ? "(None)" : src.Value.Handler.GetTypeName(src.Value.Type);
var btn = obj.GetComponent<Button>();
if (src != null) btn.interactable = !proxy.IsUsed(src.Value);
btn.onClick.AddListener(() => {

View File

@@ -1,4 +1,5 @@
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
namespace Cryville.Crtr.Config {
@@ -17,9 +18,29 @@ namespace Cryville.Crtr.Config {
m_value.text = "None";
m_button.onClick.AddListener(() => {
master.OpenDialog(name);
EventSystem.current.SetSelectedGameObject(null);
});
}
public void OnProxyChanged(ProxyChangedEventArgs e) {
if (e.Used) {
m_button.interactable = false;
m_value.text = "(Not Required)";
m_value.color = Color.black;
}
else {
m_button.interactable = true;
if (e.Proxy == null) {
m_value.text = "(Unassigned)";
m_value.color = Color.yellow;
}
else {
m_value.text = e.Proxy.Value.Handler.GetTypeName(e.Proxy.Value.Type);
m_value.color = Color.black;
}
}
}
public void SetValue(string name) {
m_value.text = name;
}

View File

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

View File

@@ -66,6 +66,9 @@ namespace Cryville.Crtr.Event {
get { return cs.Container; }
}
static readonly int _var_current_time = IdentifierManager.SharedInstance.Request("current_time");
static readonly int _var_invisible_bounds = IdentifierManager.SharedInstance.Request("invisible_bounds");
public readonly Dictionary<int, PropSrc> PropSrcs = new Dictionary<int, PropSrc>();
SkinContainer skinContainer;
protected Judge judge;
public void AttachSystems(PdtSkin skin, Judge judge) {
@@ -77,12 +80,14 @@ namespace Cryville.Crtr.Event {
public readonly Dictionary<int, Anchor> DynamicAnchors = new Dictionary<int, Anchor>();
public readonly Dictionary<int, bool> DynamicAnchorSet = new Dictionary<int, bool>();
public Anchor OpenedAnchor;
protected Anchor a_cur;
protected Anchor a_head;
protected Anchor a_tail;
protected readonly static int _a_cur = IdentifierManager.SharedInstance.Request("cur");
protected readonly static int _a_head = IdentifierManager.SharedInstance.Request("head");
protected readonly static int _a_tail = IdentifierManager.SharedInstance.Request("tail");
Anchor a_cur;
Anchor a_head;
Anchor a_tail;
readonly static int _a_cur = IdentifierManager.SharedInstance.Request("cur");
readonly static int _a_head = IdentifierManager.SharedInstance.Request("head");
readonly static int _a_tail = IdentifierManager.SharedInstance.Request("tail");
double atime_head;
double atime_tail;
public Anchor RegisterAnchor(int name, bool dyn = false, int propSrcCount = 0) {
var strname = IdentifierManager.SharedInstance.Retrieve(name);
var go = new GameObject("." + strname).transform;
@@ -102,6 +107,7 @@ namespace Cryville.Crtr.Event {
}
protected void OpenAnchor(Anchor anchor) {
if (OpenedAnchor != null) throw new InvalidOperationException("An anchor has been opened");
anchor.Transform.gameObject.SetActive(true);
OpenedAnchor = anchor;
}
protected void CloseAnchor() {
@@ -126,6 +132,8 @@ namespace Cryville.Crtr.Event {
i.Init();
}
public virtual void PostInit() {
PropSrcs.Add(_var_current_time, new PropSrc.Float(() => (float)cs.rootPrototype.Time));
PropSrcs.Add(_var_invisible_bounds, new PropSrc.Boolean(() => atime_head > atime_tail));
gogroup.gameObject.SetActive(false);
}
#endregion
@@ -144,23 +152,23 @@ namespace Cryville.Crtr.Event {
if (s.CloneType == 3) SetPreGraphicalActive(true, s);
else if (ev is StampedEvent.Anchor) {
var tev = (StampedEvent.Anchor)ev;
if (tev.Target == a_head) {
SetGraphicalActive(true, s);
}
else if (tev.Target == a_tail) {
SetGraphicalActive(false, s);
}
if (gogroup) {
OpenAnchor(tev.Target);
#if UNITY_5_6_OR_NEWER
tev.Target.Transform.SetPositionAndRotation(Position, Rotation);
#else
tev.Target.Transform.position = GetCurrentWorldPoint();
tev.Target.Transform.rotation = Quaternion.Euler(s.Direction);
tev.Target.Transform.position = Position;
tev.Target.Transform.rotation = Rotation;
#endif
skinContainer.MatchDynamic(s);
CloseAnchor();
}
if (tev.Target == a_head) {
SetGraphicalActive(true, s);
}
else if (tev.Target == a_tail) {
SetGraphicalActive(false, s);
}
anchorEvPool.Return(tev);
}
else if (gogroup && s.CloneType == 2) skinContainer.MatchDynamic(s);
@@ -181,12 +189,16 @@ namespace Cryville.Crtr.Event {
protected static bool CanDoGraphicalUpdate(ContainerState s) { return s.CloneType >= 2 && s.CloneType < 16; }
#region Anchor
public virtual void Anchor() {
foreach (var p in PropSrcs.Values) p.Invalidate();
foreach (var a in DynamicAnchors.Keys) DynamicAnchorSet[a] = false;
atime_head = cs.StampedContainer.Time;
atime_tail = atime_head + cs.StampedContainer.Duration;
skinContainer.MatchDynamic(cs);
if (cs.Active) PushAnchorEvent(cs.Time, a_cur);
if (Alive) {
if (!DynamicAnchorSet[_a_head]) PushAnchorEvent(cs.StampedContainer.Time, a_head, -1, true);
if (!DynamicAnchorSet[_a_tail]) PushAnchorEvent(cs.StampedContainer.Time + cs.StampedContainer.Duration, a_tail, 1, true);
if (!DynamicAnchorSet[_a_head]) PushAnchorEvent(atime_head, a_head, -1, true);
if (!DynamicAnchorSet[_a_tail]) PushAnchorEvent(atime_tail, a_tail, 1, true);
foreach (var anchors in Anchors.Values) foreach (var anchor in anchors) anchor.Transform.gameObject.SetActive(false);
}
}
static readonly SimpleObjectPool<StampedEvent.Anchor> anchorEvPool
@@ -197,7 +209,12 @@ namespace Cryville.Crtr.Event {
throw new ArgumentException(string.Format("Specified anchor \"{0}\" not found", IdentifierManager.SharedInstance.Retrieve(name)));
if (DynamicAnchorSet[name])
throw new InvalidOperationException(string.Format("Specified anchor \"{0}\" has been set", IdentifierManager.SharedInstance.Retrieve(name)));
PushAnchorEvent(time, anchor);
int priority = 0;
bool forced = true;
if (name == _a_head) { priority = -1; atime_head = time; }
else if (name == _a_tail) { priority = 1; atime_tail = time; }
else forced = false;
PushAnchorEvent(time, anchor, priority, forced);
DynamicAnchorSet[name] = true;
}
void PushAnchorEvent(double time, Anchor anchor, int priority = 0, bool forced = false) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -10,7 +10,7 @@ namespace Cryville.Crtr.Extensions.osu {
public class osuChartConverter : ResourceConverter {
#pragma warning restore IDE1006
static readonly string[] SUPPORTED_FORMATS = { ".osu" };
const double OFFSET = 0.07;
const double OFFSET = 0.05;
public override string[] GetSupportedFormats() {
return SUPPORTED_FORMATS;

View File

@@ -26,11 +26,10 @@ namespace Cryville.Crtr {
Components.Add("sprite", typeof(SpriteBase));
Components.Add("text", typeof(SpriteText));
Meshes.Add("quad", Resources.Load<Mesh>("quad"));
Meshes.Add("quad_scale3h", Resources.Load<Mesh>("quad_scale3h"));
Meshes.Add("quad_scale9", Resources.Load<Mesh>("quad_scale9"));
Meshes.Add("quad", Resources.Load<Mesh>("Meshes/quad"));
Meshes.Add("quad_scale3h", Resources.Load<Mesh>("Meshes/quad_scale3h"));
Materials.Add("-SpriteMat", Resources.Load<Material>("SpriteMat"));
Materials.Add("-SpriteMat", Resources.Load<Material>("Materials/SpriteMat"));
loaded = true;
}

View File

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

View File

@@ -180,12 +180,13 @@ namespace Cryville.Crtr {
readonly Dictionary<InputIdentifier, float> _vect = new Dictionary<InputIdentifier, float>();
readonly Dictionary<ProxiedInputIdentifier, PropSrc> _vecs = new Dictionary<ProxiedInputIdentifier, PropSrc>();
static readonly PropSrc.Arbitrary _nullsrc = new PropSrc.Arbitrary(PdtInternalType.Null, new byte[0]);
double? _lockTime = null;
unsafe void OnInput(InputIdentifier id, InputVector vec) {
lock (_lock) {
InputProxyEntry proxy;
if (_sproxies.TryGetValue(id.Source, out proxy)) {
_etor.ContextCascadeInsert();
float ft, tt = (float)(vec.Time - _timeOrigins[id.Source.Handler]);
float ft, tt = (float)(_lockTime != null ? _lockTime.Value : (vec.Time - _timeOrigins[id.Source.Handler]));
if (!_vect.TryGetValue(id, out ft)) ft = tt;
if (vec.IsNull) {
_etor.ContextCascadeUpdate(_var_value, _nullsrc);
@@ -243,7 +244,7 @@ namespace Cryville.Crtr {
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()));
OnInput(new InputIdentifier { Source = src, Id = 0 }, new InputVector(_lockTime != null ? _lockTime.Value : src.Handler.GetCurrentTimestamp()));
}
}
}
@@ -254,6 +255,8 @@ namespace Cryville.Crtr {
}
return result / _sproxies.Count;
}
public void LockTime() { _lockTime = GetTimestampAverage(); }
public void UnlockTime() { _lockTime = null; }
#endregion
}

View File

@@ -9,14 +9,15 @@ using System.Text.Formatting;
namespace Cryville.Crtr {
public class Judge {
#region Data
readonly ChartPlayer _sys;
readonly PdtEvaluator _etor;
readonly PdtRuleset _rs;
readonly Dictionary<Identifier, float> ct
= new Dictionary<Identifier, float>();
readonly Dictionary<Identifier, List<JudgeEvent>> evs
= new Dictionary<Identifier, List<JudgeEvent>>();
readonly Dictionary<Identifier, List<JudgeEvent>> activeEvs
= new Dictionary<Identifier, List<JudgeEvent>>();
static readonly int _var_pause = IdentifierManager.SharedInstance.Request("pause");
readonly JudgeDefinition _judgePause;
public struct JudgeEvent {
public double StartTime { get; set; }
public double EndTime { get; set; }
@@ -32,27 +33,37 @@ namespace Cryville.Crtr {
return x.StartClip.CompareTo(y.StartClip);
}
}
public Judge(PdtRuleset rs) {
public Judge(ChartPlayer sys, PdtRuleset rs) {
_sys = sys;
_etor = ChartPlayer.etor;
_rs = rs;
_numsrc1 = new PropSrc.Float(() => _numbuf1);
_numsrc2 = new PropSrc.Float(() => _numbuf2);
_numsrc3 = new PropSrc.Float(() => _numbuf3);
_numsrc4 = new PropSrc.Float(() => _numbuf4);
_rs.judges.TryGetValue(new Identifier(_var_pause), out _judgePause);
foreach (var i in rs.inputs.Keys) {
var l = new List<JudgeEvent>();
evs.Add(i, l);
activeEvs.Add(i, new List<JudgeEvent>());
if (_judgePause != null && i.Key == _var_pause) {
l.Add(new JudgeEvent {
StartTime = double.NegativeInfinity, EndTime = double.PositiveInfinity,
StartClip = double.NegativeInfinity, EndClip = double.PositiveInfinity,
Definition = _judgePause,
});
}
}
InitJudges();
InitScores();
}
public void Prepare(StampedEvent sev, NoteHandler handler) {
var tev = (Chart.Judge)sev.Unstamped;
if (tev.Id.Key == _var_pause) throw new InvalidOperationException("Cannot assign the special judge \"pause\" to notes");
Identifier input = default(Identifier);
ChartPlayer.etor.Evaluate(new PropOp.Identifier(v => input = new Identifier(v)), _rs.judges[tev.Id].input);
double st = sev.Time, et = st + sev.Duration;
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 list = evs[input];
var def = _rs.judges[tev.Id];
var ev = new JudgeEvent {
StartTime = st,
@@ -130,9 +141,12 @@ namespace Cryville.Crtr {
if (def.hit != null) _etor.Evaluate(_flagop, def.hit);
else _flag = true;
if (_flag) {
if (ev.Definition == _judgePause) _sys.TogglePause();
if (def.scores != null) UpdateScore(def.scores);
if (def.pass != null) Pass(ev, (ft + tt) / 2, def.pass);
actlist.RemoveAt(index);
if (def.persist != null) _etor.Evaluate(_flagop, def.persist);
else _flag = false;
if (!_flag) actlist.RemoveAt(index);
if (def.prop != 0 && actlist.Count > 0) {
index = BinarySearchFirst(actlist, (float)ev.StartClip, def.stack - def.prop);
if (index < 0) index = ~index;
@@ -203,7 +217,6 @@ namespace Cryville.Crtr {
readonly Dictionary<int, ScoreDefinition> scoreDefs = new Dictionary<int, ScoreDefinition>();
readonly Dictionary<int, float> scores = new Dictionary<int, float>();
readonly Dictionary<int, string> scoreStringCache = new Dictionary<int, string>();
readonly Dictionary<int, PropSrc> scoreStringSrcs = new Dictionary<int, PropSrc>();
readonly ArrayPool<byte> scoreStringPool = new ArrayPool<byte>();
readonly Dictionary<int, string> scoreFormatCache = new Dictionary<int, string>();
readonly TargetString scoreFullStr = new TargetString();
@@ -219,21 +232,18 @@ namespace Cryville.Crtr {
scoreDefs.Add(key, s.Value);
scores.Add(key, s.Value.init);
scoreStringCache.Add(scoreStringKeys[key], null);
scoreStringSrcs.Add(scoreStringKeys[key], new ScoreStringSrc(scoreStringPool, () => scores[key], scoreDefs[key].format));
scoreSrcs.Add(scoreStringKeys[key], new ScoreStringSrc(scoreStringPool, () => scores[key], scoreDefs[key].format));
scoreFormatCache[key] = string.Format("{{0:{0}}}", s.Value.format);
}
}
void InvalidateScore(int key) {
scoreSrcs[key].Invalidate();
scoreStringCache[scoreStringKeys[key]] = null;
scoreStringSrcs[scoreStringKeys[key]].Invalidate();
scoreSrcs[scoreStringKeys[key]].Invalidate();
}
public bool TryGetScoreSrc(int key, out PropSrc value) {
return scoreSrcs.TryGetValue(key, out value);
}
public bool TryGetScoreStringSrc(int key, out PropSrc value) {
return scoreStringSrcs.TryGetValue(key, out value);
}
public TargetString GetFullFormattedScoreString() {
bool flag = false;
scoreFullBuf.Clear();
@@ -289,6 +299,7 @@ namespace Cryville.Crtr {
public Clip clip;
public PdtExpression input;
public PdtExpression hit;
public PdtExpression persist;
public Identifier[] pass;
public Identifier[] miss;
public Dictionary<ScoreOperation, PdtExpression> scores;

View File

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

View File

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

View File

@@ -911,11 +911,11 @@ namespace Cryville.Crtr {
}
public override bool IsZero() {
if (!xw.Equals(0)) return false;
if (!xh.Equals(0)) return false;
if (!yw.Equals(0)) return false;
if (!yh.Equals(0)) return false;
if (!z.Equals(0)) return false;
if (xw == null || xw != 0) return false;
if (xh == null || xh != 0) return false;
if (yw == null || yw != 0) return false;
if (xh == null || xh != 0) return false;
if (z == null || z != 0) return false;
return true;
}

View File

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

View File

@@ -35,16 +35,11 @@ namespace Cryville.Crtr {
var vec = ContextState.GetRawValue(id);
VectorSrc.Construct(() => vec).Get(out type, out value);
}
else if (ContextState != null && name == _var_current_time) {
LoadNum((float)ContextState.rootPrototype.Time);
type = PdtInternalType.Number;
value = _numbuf;
}
else if (ContextJudge != null && ContextJudge.TryGetScoreSrc(name, out prop)) {
else if (ContextState != null && ContextState.Handler.PropSrcs.TryGetValue(name, out prop)) {
prop.Get(out type, out value);
RevokePotentialConstant();
}
else if (ContextJudge != null && ContextJudge.TryGetScoreStringSrc(name, out prop)) {
else if (ContextJudge != null && ContextJudge.TryGetScoreSrc(name, out prop)) {
prop.Get(out type, out value);
RevokePotentialConstant();
}
@@ -172,6 +167,7 @@ namespace Cryville.Crtr {
_shortops.Add(new PdtOperatorSignature("frame_seq", 3), new func_frame_seq());
_shortops.Add(new PdtOperatorSignature("in_area", 1), new func_in_area());
_shortops.Add(new PdtOperatorSignature("interval", 3), new func_interval());
_shortops.Add(new PdtOperatorSignature("is", 2), new func_is());
}
#region Operators
@@ -355,6 +351,16 @@ namespace Cryville.Crtr {
hit.CopyTo(ret);
}
}
class func_interval : PdtOperator {
public func_interval() : base(3) { }
protected override unsafe void Execute() {
var value = GetOperand(0).AsNumber();
var min = GetOperand(1).AsNumber();
var max = GetOperand(2).AsNumber();
var ret = GetReturnFrame(PdtInternalType.Number, sizeof(float));
ret.SetNumber((value - min) * (max - value));
}
}
class func_is : PdtOperator {
public func_is() : base(2) { }
protected override unsafe void Execute() {
@@ -379,9 +385,8 @@ namespace Cryville.Crtr {
var ray = new Ray(ctx.position, ctx.rotation * Vector3.forward);
ChartPlayer.frustumPlanes[(int)GetOperand(0).AsNumber()].Raycast(ray, out dist);
var ret = GetReturnFrame(PdtInternalType.Vector, sizeof(Vector3) + sizeof(int));
var ptr = (Vector3*)ret.TrustedAsOfLength(sizeof(Vector3) + sizeof(int));
*ptr++ = ray.GetPoint(dist);
*(int*)ptr = PdtInternalType.Number;
ret.Set(ray.GetPoint(dist));
ret.SetArraySuffix(PdtInternalType.Number);
}
}
class func_int : PdtOperator {

View File

@@ -5,7 +5,10 @@ using System.Collections.Generic;
using System.Reflection;
using RBeatTime = Cryville.Crtr.BeatTime;
using RClip = Cryville.Crtr.Clip;
using RColor = UnityEngine.Color;
using RTargetString = Cryville.Common.Buffers.TargetString;
using RVector2 = UnityEngine.Vector2;
using RVector3 = UnityEngine.Vector3;
namespace Cryville.Crtr {
public abstract class PropOp : PdtOperator {
@@ -60,16 +63,14 @@ namespace Cryville.Crtr {
public class TargetString : PropOp {
readonly Func<RTargetString> _cb;
public TargetString(Func<RTargetString> cb) { _cb = cb; }
protected override unsafe void Execute() {
protected override void Execute() {
var target = _cb();
var op = GetOperand(0);
if (op.Type != PdtInternalType.String) throw new ArgumentException("Not a string");
var ptr = (byte*)op.TrustedAsOfLength(op.Length);
var len = *(int*)ptr;
int len = op.As<int>();
target.Length = len;
var cptr = (char*)(ptr + sizeof(int));
for (int i = 0; i < len; i++)
target[i] = cptr[i];
target[i] = op.As<char>(sizeof(int) + i * sizeof(char));
target.Validate();
}
}
@@ -105,22 +106,22 @@ namespace Cryville.Crtr {
public BeatTime(Action<RBeatTime> cb) { _cb = cb; }
protected override unsafe void Execute() {
var o = GetOperand(0);
_cb(*(RBeatTime*)o.TrustedAsOfLength(sizeof(RBeatTime)));
_cb(o.As<RBeatTime>());
}
}
public class Vector2 : PropOp {
readonly Action<UnityEngine.Vector2> _cb;
public Vector2(Action<UnityEngine.Vector2> cb) { _cb = cb; }
readonly Action<RVector2> _cb;
public Vector2(Action<RVector2> cb) { _cb = cb; }
protected override unsafe void Execute() {
var o = GetOperand(0);
switch ((o.Length - 4) / 4) {
case 0: // Number
case 1: // Array[1]
float num = o.AsNumber();
_cb(new UnityEngine.Vector2(num, num));
_cb(new RVector2(num, num));
break;
case 2:
_cb(*(UnityEngine.Vector2*)o.TrustedAsOfLength(sizeof(UnityEngine.Vector2)));
_cb(o.As<RVector2>());
break;
default:
throw new InvalidOperationException("Invalid array size");
@@ -128,21 +129,21 @@ namespace Cryville.Crtr {
}
}
public class Vector3 : PropOp {
readonly Action<UnityEngine.Vector3> _cb;
public Vector3(Action<UnityEngine.Vector3> cb) { _cb = cb; }
readonly Action<RVector3> _cb;
public Vector3(Action<RVector3> cb) { _cb = cb; }
protected override unsafe void Execute() {
var o = GetOperand(0);
switch ((o.Length - 4) / 4) {
case 0: // Number
case 1: // Array[1]
float num = o.AsNumber();
_cb(new UnityEngine.Vector3(num, num));
_cb(new RVector3(num, num));
break;
case 2:
_cb(*(UnityEngine.Vector2*)o.TrustedAsOfLength(sizeof(UnityEngine.Vector2)));
_cb(o.As<RVector2>());
break;
case 3:
_cb(*(UnityEngine.Vector3*)o.TrustedAsOfLength(sizeof(UnityEngine.Vector3)));
_cb(o.As<RVector3>());
break;
default:
throw new InvalidOperationException("Invalid array size");
@@ -150,17 +151,16 @@ namespace Cryville.Crtr {
}
}
public class Color : PropOp {
readonly Action<UnityEngine.Color> _cb;
public Color(Action<UnityEngine.Color> cb) { _cb = cb; }
readonly Action<RColor> _cb;
public Color(Action<RColor> cb) { _cb = cb; }
protected override unsafe void Execute() {
var o = GetOperand(0);
switch ((o.Length - 4) / 4) {
case 3:
var ptr = (float*)o.TrustedAsOfLength(sizeof(float) * 3);
_cb(new UnityEngine.Color(ptr[0], ptr[1], ptr[2]));
_cb(new RColor(o.As<float>(), o.As<float>(sizeof(float)), o.As<float>(2 * sizeof(float))));
break;
case 4:
_cb(*(UnityEngine.Color*)o.TrustedAsOfLength(sizeof(UnityEngine.Color)));
_cb(o.As<RColor>());
break;
default:
throw new InvalidOperationException("Invalid array size");

View File

@@ -61,6 +61,18 @@ namespace Cryville.Crtr {
}
}
[Category("gameplay")]
[Step(0.01f)]
[Precision(1e-3)]
public float GraphicalOffset {
get {
return PlayerPrefs.GetFloat("GraphicalOffset", 0);
}
set {
PlayerPrefs.SetFloat("GraphicalOffset", value);
}
}
[Browsable(false)]
public string LastRunVersion {
get {

View File

@@ -18,7 +18,7 @@ namespace Cryville.Crtr {
}
public override bool IsValueRequired { get { return false; } }
public override void ExecuteStatic(ContainerState state, RuntimeSkinContext ctx, PdtExpression exp) {
ctx.ReadContext.Transform.gameObject.AddComponent(Component);
ctx.WriteTransform.gameObject.AddComponent(Component);
}
public override void ExecuteDynamic(ContainerState state, RuntimeSkinContext ctx, PdtExpression exp) {
throw new InvalidOperationException("Component creation in dynamic context is not allowed");

Binary file not shown.

View File

@@ -211,7 +211,7 @@ namespace System.Text.Formatting {
remainingDigitsInGroup -= groupSize;
groupIndex++;
}
bool appendingDigitFlag = false;
bool appendingDigitFlag = false, outOfPrecisionFlag = false;
decimalFlag = false;
for (index = start; index < end; index++) {
switch (ptr[index]) {
@@ -229,13 +229,20 @@ namespace System.Text.Formatting {
case '#':
if (!appendingDigitFlag) {
if (number.Scale > integralDigits) while (currentDigitIndex < number.Scale - integralDigits)
formatter.AppendIntegralDigit(ref number, ref currentDigitIndex, culture, groupFlag, ref groupIndex, ref remainingDigitsInGroup);
formatter.AppendIntegralDigit(ref number, ref currentDigitIndex, culture, groupFlag, ref outOfPrecisionFlag, ref groupIndex, ref remainingDigitsInGroup);
appendingDigitFlag = true;
}
if (decimalFlag) {
if (currentDigitIndex < number.Precision) {
char digit = number.Digits[currentDigitIndex++];
if (digit == '\0') digit = '0';
char digit = '0';
if (!outOfPrecisionFlag) {
if (currentDigitIndex >= number.Precision) outOfPrecisionFlag = true;
else {
digit = number.Digits[currentDigitIndex++];
if (digit == '\0') {
outOfPrecisionFlag = true;
digit = '0';
}
}
formatter.Append(digit);
}
else if (decimalZeros > 0)
@@ -245,7 +252,7 @@ namespace System.Text.Formatting {
}
else {
if (integralDigits <= number.Scale)
formatter.AppendIntegralDigit(ref number, ref currentDigitIndex, culture, groupFlag, ref groupIndex, ref remainingDigitsInGroup);
formatter.AppendIntegralDigit(ref number, ref currentDigitIndex, culture, groupFlag, ref outOfPrecisionFlag, ref groupIndex, ref remainingDigitsInGroup);
else if (integralDigits <= integralZeros)
formatter.AppendIntegralDigit('0', culture, groupFlag, ref groupIndex, ref remainingDigitsInGroup);
--integralDigits;
@@ -295,11 +302,18 @@ namespace System.Text.Formatting {
}
}
}
static void AppendIntegralDigit(this StringBuffer self, ref Number number, ref int index, CachedCulture culture, bool groupFlag, ref int groupIndex, ref int remainingDigitsInGroup) {
char digit;
if (index >= number.Precision) digit = '0';
else digit = number.Digits[index];
if (digit == '\0') digit = '0';
static void AppendIntegralDigit(this StringBuffer self, ref Number number, ref int index, CachedCulture culture, bool groupFlag, ref bool outOfPrecisionFlag, ref int groupIndex, ref int remainingDigitsInGroup) {
char digit = '0';
if (!outOfPrecisionFlag) {
if (index >= number.Precision) outOfPrecisionFlag = true;
else {
digit = number.Digits[index];
if (digit == '\0') {
outOfPrecisionFlag = true;
digit = '0';
}
}
}
self.AppendIntegralDigit(digit, culture, groupFlag, ref groupIndex, ref remainingDigitsInGroup);
index++;
}

Binary file not shown.

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: d927992f95b82f740a0a95bb6d617d73
guid: 1313487c790be7545a3e1e2ca59e986e
PluginImporter:
externalObjects: {}
serializedVersion: 2

View File

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