Implement input config.

This commit is contained in:
2022-10-14 11:18:52 +08:00
parent 23ed127a1b
commit d3cac8a28d
10 changed files with 192 additions and 69 deletions

Binary file not shown.

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 2e030b9eb9f613844a4a302812e517ad
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,105 @@
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 {
[SerializeField]
GameObject m_inputDialog;
[SerializeField]
Transform m_deviceList;
[SerializeField]
GameObject m_prefabListItem;
[SerializeField]
Transform m_entryList;
[SerializeField]
GameObject m_prefabInputConfigEntry;
InputProxy _proxy;
Dictionary<string, InputConfigEntry> _entries = new Dictionary<string, InputConfigEntry>();
string _sel;
public void OpenDialog(string entry) {
_sel = entry;
m_inputDialog.SetActive(true);
Game.InputManager.Activate();
CallHelper.Purge(m_deviceList);
_recvsrcs.Clear();
AddSourceItem(null);
}
public void CloseDialog() {
m_inputDialog.SetActive(false);
Game.InputManager.Deactivate();
}
public void CloseDialog(InputSource? src) {
_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;
}
}
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));
}
readonly List<InputSource?> _recvsrcs = new List<InputSource?>();
void Update() {
if (m_inputDialog.activeSelf) {
Game.InputManager.EnumerateEvents(ev => {
AddSourceItem(ev.Id.Source);
});
}
}
void AddSourceItem(InputSource? src) {
if (_recvsrcs.Contains(src)) return;
_recvsrcs.Add(src);
var obj = Instantiate(m_prefabListItem);
obj.transform.SetParent(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);
btn.onClick.AddListener(() => {
CloseDialog(src);
});
}
}
}

View File

@@ -0,0 +1,31 @@
using UnityEngine;
using UnityEngine.UI;
namespace Cryville.Crtr.Config {
public class InputConfigEntry : MonoBehaviour {
[SerializeField]
Text m_key;
[SerializeField]
Text m_value;
[SerializeField]
Button m_button;
public void SetKey(InputConfig master, string name) {
m_key.text = name + " ";
m_value.text = "None";
m_button.onClick.AddListener(() => {
master.OpenDialog(name);
});
}
public void SetValue(string name) {
m_value.text = name;
}
public void SetEnabled(bool flag) {
m_button.interactable = flag;
}
}
}

View File

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

View File

@@ -1,49 +0,0 @@
using Cryville.Common.Unity;
using Cryville.Common.Unity.Input;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace Cryville.Crtr {
public class InputConfig : MonoBehaviour {
[SerializeField]
GameObject m_inputDialog;
[SerializeField]
Transform m_deviceList;
[SerializeField]
GameObject m_prefabListItem;
public void OpenDialog() {
m_inputDialog.SetActive(true);
Game.InputManager.Activate();
CallHelper.Purge(m_deviceList);
_recvsrcs.Clear();
}
public void CloseDialog() {
CloseDialog(null);
}
public void CloseDialog(InputSource? src) {
m_inputDialog.SetActive(false);
Game.InputManager.Deactivate();
}
List<InputSource> _recvsrcs = new List<InputSource>();
void Update() {
if (m_inputDialog.activeSelf) {
Game.InputManager.EnumerateEvents(ev => {
var src = ev.Id.Source;
if (!_recvsrcs.Contains(src)) {
_recvsrcs.Add(src);
var obj = Instantiate(m_prefabListItem);
obj.transform.SetParent(m_deviceList);
obj.transform.Find("Text").GetComponent<Text>().text = src.Handler.GetTypeName(src.Type);
}
});
}
}
}
}

View File

@@ -1,6 +1,7 @@
using Cryville.Common.Unity.Input; using Cryville.Common.Unity.Input;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Xml.Linq;
namespace Cryville.Crtr { namespace Cryville.Crtr {
public class InputProxy { public class InputProxy {
@@ -25,61 +26,70 @@ namespace Cryville.Crtr {
} }
public void Set(InputProxyEntry proxy) { public void Set(InputProxyEntry proxy) {
var name = proxy.Target; var name = proxy.Target;
if (_use[name] > 0) if (_hash1.ContainsKey(name)) Remove(proxy);
if (_use[proxy.Target] > 0)
throw new InvalidOperationException("Input already assigned"); throw new InvalidOperationException("Input already assigned");
if (proxy.Source != null) {
_hash1.Add(proxy.Target, proxy); _hash1.Add(proxy.Target, proxy);
_hash2.Add(proxy.Source, proxy); _hash2.Add(proxy.Source.Value, proxy);
if (proxy != null) {
IncrementUseRecursive(name); IncrementUseRecursive(name);
IncrementReversedUseRecursive(name); IncrementReversedUseRecursive(name);
} }
else { }
void Remove(InputProxyEntry proxy) {
var name = proxy.Target;
_hash2.Remove(_hash1[name].Source.Value);
_hash1.Remove(name);
DecrementUseRecursive(name); DecrementUseRecursive(name);
DecrementReversedUseRecursive(name); DecrementReversedUseRecursive(name);
} }
public bool IsUsed(InputSource src) {
return _hash2.ContainsKey(src);
} }
void IncrementUseRecursive(string name) { void IncrementUseRecursive(string name) {
_use[name]++;
BroadcastProxyChanged(name); BroadcastProxyChanged(name);
var passes = _ruleset.inputs[name].pass; var passes = _ruleset.inputs[name].pass;
if (passes != null) { if (passes != null) {
foreach (var p in _ruleset.inputs[name].pass) foreach (var p in _ruleset.inputs[name].pass) {
_use[p.Key]++;
IncrementUseRecursive(p.Key); IncrementUseRecursive(p.Key);
} }
} }
}
void IncrementReversedUseRecursive(string name) { void IncrementReversedUseRecursive(string name) {
foreach (var p in _rev[name]) { foreach (var p in _rev[name]) {
_use[name]++; _use[p]++;
BroadcastProxyChanged(name); BroadcastProxyChanged(p);
IncrementReversedUseRecursive(p); IncrementReversedUseRecursive(p);
} }
} }
void DecrementUseRecursive(string name) { void DecrementUseRecursive(string name) {
_use[name]--;
BroadcastProxyChanged(name); BroadcastProxyChanged(name);
var passes = _ruleset.inputs[name].pass; var passes = _ruleset.inputs[name].pass;
if (passes != null) { if (passes != null) {
foreach (var p in _ruleset.inputs[name].pass) foreach (var p in _ruleset.inputs[name].pass) {
_use[p.Key]--;
DecrementUseRecursive(p.Key); DecrementUseRecursive(p.Key);
} }
} }
}
void DecrementReversedUseRecursive(string name) { void DecrementReversedUseRecursive(string name) {
foreach (var p in _rev[name]) { foreach (var p in _rev[name]) {
_use[name]--; _use[p]--;
BroadcastProxyChanged(name); BroadcastProxyChanged(p);
DecrementReversedUseRecursive(p); DecrementReversedUseRecursive(p);
} }
} }
void BroadcastProxyChanged(string name) { void BroadcastProxyChanged(string name) {
ProxyChanged(this, new ProxyChangedEventArgs(name, _hash1[name].Source, _use[name] > 0)); ProxyChanged(this, new ProxyChangedEventArgs(name, _hash1.ContainsKey(name) ? _hash1[name].Source : null, _use[name] > 0));
} }
} }
public class ProxyChangedEventArgs : EventArgs { public class ProxyChangedEventArgs : EventArgs {
public string Name { get; private set; } public string Name { get; private set; }
public InputSource Proxy { get; private set; } public InputSource? Proxy { get; private set; }
public bool Used { get; private set; } public bool Used { get; private set; }
public ProxyChangedEventArgs(string name, InputSource src, bool used) { public ProxyChangedEventArgs(string name, InputSource? src, bool used) {
Name = name; Name = name;
Proxy = src; Proxy = src;
Used = used; Used = used;
@@ -87,7 +97,7 @@ namespace Cryville.Crtr {
} }
public class InputProxyEntry { public class InputProxyEntry {
public InputSource Source { get; set; } public InputSource? Source { get; set; }
public string Target { get; set; } public string Target { get; set; }
public byte[] Mapping { get; private set; } public byte[] Mapping { get; private set; }
} }

Binary file not shown.

View File

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