Files
crtr/Assets/Cryville/Crtr/InputProxy.cs
2022-11-06 14:25:02 +08:00

162 lines
5.1 KiB
C#

using Cryville.Common;
using Cryville.Common.Pdt;
using Cryville.Common.Unity.Input;
using System;
using System.Collections.Generic;
using UnityEngine;
using Logger = Cryville.Common.Logger;
namespace Cryville.Crtr {
public class InputProxy {
readonly PdtEvaluator _etor;
readonly PdtRuleset _ruleset;
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>>();
readonly Dictionary<InputIdentifier, InputVector> _vecs = new Dictionary<InputIdentifier, InputVector>();
public event EventHandler<ProxyChangedEventArgs> ProxyChanged;
public InputProxy(PdtRuleset ruleset) {
unsafe {
fixed (byte* ptr = _vecbuf) {
*(int*)(ptr + 3 * sizeof(float)) = PdtInternalType.Number;
}
}
_etor = ChartPlayer.etor;
_ruleset = ruleset;
foreach (var i in ruleset.inputs) {
_use.Add(i.Key, 0);
_rev.Add(i.Key, new List<string>());
}
foreach (var i in ruleset.inputs) {
if (i.Value.pass != null) {
foreach (var p in i.Value.pass)
_rev[p.Key].Add(i.Key);
}
}
}
#region Settings
public void Set(InputProxyEntry proxy) {
var name = proxy.Target;
if (_tproxies.ContainsKey(name)) Remove(proxy);
if (_use[proxy.Target] > 0)
throw new InvalidOperationException("Input already assigned");
if (proxy.Source != null) {
proxy.Source.Value.Handler.OnInput += OnInput;
_tproxies.Add(proxy.Target, proxy);
_sproxies.Add(proxy.Source.Value, proxy);
IncrementUseRecursive(name);
IncrementReversedUseRecursive(name);
}
}
void Remove(InputProxyEntry proxy) {
var name = proxy.Target;
proxy.Source.Value.Handler.OnInput -= OnInput;
_sproxies.Remove(_tproxies[name].Source.Value);
_tproxies.Remove(name);
DecrementUseRecursive(name);
DecrementReversedUseRecursive(name);
}
public bool IsUsed(InputSource src) {
return _sproxies.ContainsKey(src);
}
void IncrementUseRecursive(string name) {
BroadcastProxyChanged(name);
var passes = _ruleset.inputs[name].pass;
if (passes != null) {
foreach (var p in _ruleset.inputs[name].pass) {
_use[p.Key]++;
IncrementUseRecursive(p.Key);
}
}
}
void IncrementReversedUseRecursive(string name) {
foreach (var p in _rev[name]) {
_use[p]++;
BroadcastProxyChanged(p);
IncrementReversedUseRecursive(p);
}
}
void DecrementUseRecursive(string name) {
BroadcastProxyChanged(name);
var passes = _ruleset.inputs[name].pass;
if (passes != null) {
foreach (var p in _ruleset.inputs[name].pass) {
_use[p.Key]--;
DecrementUseRecursive(p.Key);
}
}
}
void DecrementReversedUseRecursive(string name) {
foreach (var p in _rev[name]) {
_use[p]--;
BroadcastProxyChanged(p);
DecrementReversedUseRecursive(p);
}
}
void BroadcastProxyChanged(string name) {
var del = ProxyChanged;
if (del != null) del(this, new ProxyChangedEventArgs(name, _tproxies.ContainsKey(name) ? _tproxies[name].Source : null, _use[name] > 0));
}
#endregion
#region Handling
public void Activate() { foreach (var src in _sproxies.Keys) src.Handler.Activate(); }
public void Deactivate() { foreach (var src in _sproxies.Keys) src.Handler.Deactivate(); }
readonly object _lock = new object();
void OnInput(InputIdentifier id, InputVector vec) {
lock (_lock) {
InputProxyEntry proxy;
if (_sproxies.TryGetValue(id.Source, out proxy)) {
OnInput(id, vec, proxy.Target);
}
}
}
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)];
unsafe void OnInput(InputIdentifier id, InputVector vec, string target) {
_etor.ContextCascadeInsert();
fixed (byte* ptr = _vecbuf) {
*(Vector3*)ptr = vec.Vector;
}
_etor.ContextCascadeUpdate(_var_value, new PropSrc.Arbitrary(PdtInternalType.Vector, _vecbuf));
OnInput(id, target);
_etor.ContextCascadeDiscard();
}
unsafe void OnInput(InputIdentifier id, string target) {
var def = _ruleset.inputs[target];
if (def.pass != null) {
foreach (var p in def.pass) {
_etor.ContextCascadeInsert();
_arbop.Name = _var_value;
_etor.Evaluate(_arbop, p.Value);
OnInput(id, p.Key);
_etor.ContextCascadeDiscard();
}
}
else {
Logger.Log("main", 0, "Input/Proxy", "input recv {0}", target);
}
}
#endregion
}
public class ProxyChangedEventArgs : EventArgs {
public string Name { get; private set; }
public InputSource? Proxy { get; private set; }
public bool Used { get; private set; }
public ProxyChangedEventArgs(string name, InputSource? src, bool used) {
Name = name;
Proxy = src;
Used = used;
}
}
public class InputProxyEntry {
public InputSource? Source { get; set; }
public string Target { get; set; }
public byte[] Mapping { get; private set; }
}
}