Add project files.

This commit is contained in:
2022-09-30 17:32:21 +08:00
parent df69e65c88
commit e8e36b83bd
561 changed files with 40626 additions and 0 deletions

View File

@@ -0,0 +1,15 @@
using UnityEngine;
namespace Cryville.Crtr {
public class Anchor {
bool _opened;
public bool Opened { get { return _opened; } }
public Transform Transform { get; set; }
public void Open() {
_opened = true;
}
public void Close() {
_opened = false;
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: fe131992309d7034a89259ab7191200a
timeCreated: 1636290820
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: bf6d413b13da4fe4eab20a567d8ee795
folderAsset: yes
timeCreated: 1638415418
licenseType: Free
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,21 @@
using Cryville.Common;
using UnityEngine;
namespace Cryville.Crtr.Browsing {
internal abstract class BrowserItem : MonoBehaviour {
public int? Id { get; private set; }
protected ResourceItemMeta meta;
internal virtual void Load(int id, ResourceItemMeta item) {
Id = id;
meta = item;
}
}
public struct ResourceItemMeta {
public bool IsDirectory { get; set; }
public AsyncDelivery<Texture2D> Icon { get; set; }
public string Name { get; set; }
public string DescriptionMain { get; set; }
public string DescriptionSub { get; set; }
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: cfa7de3f6f944914d9999fcfda245f97
timeCreated: 1637552994
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,52 @@
using UnityEngine;
using UnityEngine.UI;
namespace Cryville.Crtr.Browsing {
internal class BrowserItemTile : BrowserItem {
#pragma warning disable IDE0044
[SerializeField]
private Sprite m_iconPlaceholder;
#pragma warning restore IDE0044
private bool _dir;
private Image _icon;
private Text _title;
private Text _desc;
#pragma warning disable IDE0051
void Awake() {
_icon = transform.Find("__content__/Icon").GetComponent<Image>();
_title = transform.Find("__content__/Texts/Title/__text__").GetComponent<Text>();
_desc = transform.Find("__content__/Texts/Description/__text__").GetComponent<Text>();
}
void OnDestroy() {
if (meta.Icon != null) meta.Icon.Cancel();
if (_icon.sprite != null && _icon.sprite != m_iconPlaceholder) {
Texture2D.Destroy(_icon.sprite.texture);
Sprite.Destroy(_icon.sprite);
}
}
#pragma warning restore IDE0051
internal override void Load(int id, ResourceItemMeta item) {
OnDestroy();
base.Load(id, item);
_dir = meta.IsDirectory;
_icon.sprite = m_iconPlaceholder;
if (meta.Icon != null) meta.Icon.Destination = DisplayCover;
_title.text = meta.Name;
_desc.text = string.Format("{0}\n{1}", meta.DescriptionMain, meta.DescriptionSub);
}
private void DisplayCover(bool succeeded, Texture2D tex) {
if (succeeded) {
_icon.sprite = Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), Vector2.zero);
}
}
public void OnClick() {
if (Id == null) return;
ResourceBrowser resourceBrowser = GetComponentInParent<ResourceBrowser>();
if (_dir) resourceBrowser.OnDirectoryItemClicked(Id.Value);
else resourceBrowser.OnObjectItemClicked(Id.Value);
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: b38d66b3e6e5d94438c72f855c4efff9
timeCreated: 1637554149
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,71 @@
using Cryville.Common;
using Cryville.Common.Unity.UI;
using System;
using UnityEngine;
using UnityEngine.UI;
namespace Cryville.Crtr.Browsing {
public class DetailPanel : ResourceBrowserUnit {
#pragma warning disable IDE0044
[SerializeField]
private Sprite m_coverPlaceholder;
#pragma warning restore IDE0044
int _id;
ChartDetail _data;
GameObject _placeholder;
GameObject _outerContent;
DockOccupiedRatioLayoutGroup _outerContentGroup;
Transform _content;
Image _cover;
Text _title;
Text _desc;
#pragma warning disable IDE0051
protected override void Awake() {
base.Awake();
_placeholder = transform.Find("__placeholder__").gameObject;
_outerContent = transform.Find("__content__").gameObject;
_outerContentGroup = _outerContent.GetComponent<DockOccupiedRatioLayoutGroup>();
_content = _outerContent.transform.Find("__content__");
_cover = _content.Find("Cover").GetComponent<Image>();
_title = _content.Find("Texts/Title").GetComponent<Text>();
_desc = _content.Find("Texts/Description").GetComponent<Text>();
}
void OnDestroy() {
if (_data.Cover != null) _data.Cover.Cancel();
if (_cover.sprite != null && _cover.sprite != m_coverPlaceholder) {
Texture2D.Destroy(_cover.sprite.texture);
Sprite.Destroy(_cover.sprite);
}
}
#pragma warning restore IDE0051
public void Load(int id, ChartDetail data) {
_id = id;
_placeholder.SetActive(false);
_outerContent.SetActive(true);
OnDestroy();
_data = data;
_cover.sprite = m_coverPlaceholder;
if (data.Cover != null) data.Cover.Destination = DisplayCover;
var meta = data.Meta;
_title.text = string.Format("{0}\n{1}", meta.song.name, meta.chart.name);
_desc.text = string.Format(
"Music artist: {0}\nCharter: {1}\nLength: {2}\nNote Count: {3}",
meta.song.author, meta.chart.author,
TimeSpan.FromSeconds(meta.chart.length).ToString(3), meta.note_count
);
}
private void DisplayCover(bool succeeded, Texture2D tex) {
if (succeeded) {
_cover.sprite = Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), Vector2.zero);
}
}
public void OnPlay() {
Master.Open(_id);
}
public void OnConfig() {
Master.OpenConfig(_id);
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 477e04b1ed5b60e48886fb76081245c5
timeCreated: 1637722157
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,14 @@
namespace Cryville.Crtr.Browsing {
public interface IResourceManager<T> {
string[] CurrentDirectory { get; }
int ChangeDirectory(string[] dir);
int OpenDirectory(int id);
int ReturnToDirectory(int id);
ResourceItemMeta GetItemMeta(int id);
T GetItemDetail(int id);
string GetItemPath(int id);
bool ImportItemFrom(string path);
string[] GetSupportedFormats();
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 453013bb1af4e344198e688c515d0e13
timeCreated: 1637234367
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,155 @@
using Cryville.Common;
using Cryville.Common.Unity;
using System;
using System.IO;
using UnityEngine;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Linq;
namespace Cryville.Crtr.Browsing {
internal class LegacyResourceManager : IResourceManager<ChartDetail> {
private readonly string _rootPath;
private DirectoryInfo cd;
private DirectoryInfo[] items = new DirectoryInfo[0];
public string[] CurrentDirectory { get; private set; }
static readonly Dictionary<string, List<ResourceConverter>> converters
= new Dictionary<string, List<ResourceConverter>>();
public LegacyResourceManager(string rootPath) {
_rootPath = rootPath;
}
static LegacyResourceManager() {
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) {
foreach (var type in asm.GetTypes()) {
if (type.IsSubclassOf(typeof(ResourceConverter))) {
var converter = (ResourceConverter)Activator.CreateInstance(type);
foreach (var f in converter.GetSupportedFormats()) {
if (!converters.ContainsKey(f))
converters.Add(f, new List<ResourceConverter> { converter });
else converters[f].Add(converter);
}
}
}
}
}
public int ChangeDirectory(string[] dir) {
CurrentDirectory = dir;
cd = new DirectoryInfo(_rootPath + "/charts/" + string.Join("/", dir));
items = cd.GetDirectories();
return items.Length;
}
public int OpenDirectory(int id) {
string[] nd = new string[CurrentDirectory.Length + 1];
Array.Copy(CurrentDirectory, nd, CurrentDirectory.Length);
nd[CurrentDirectory.Length] = items[id].Name;
return ChangeDirectory(nd);
}
public int ReturnToDirectory(int id) {
string[] nd = new string[id + 1];
Array.Copy(CurrentDirectory, nd, id + 1);
return ChangeDirectory(nd);
}
public ResourceItemMeta GetItemMeta(int id) {
var item = items[id];
AsyncDelivery<Texture2D> cover = null;
var coverFile = item.GetFiles("cover.*");
if (coverFile.Length > 0) {
cover = new AsyncDelivery<Texture2D>();
var task = new LoadTextureTask(Game.FileProtocolPrefix + coverFile[0].FullName, cover.Deliver);
cover.CancelSource = task.Cancel;
Game.NetworkTaskWorker.SubmitNetworkTask(task);
}
string name = item.Name;
string desc = "(Unknown)";
var metaFile = new FileInfo(item.FullName + "/meta.json");
if (metaFile.Exists) {
using (var reader = new StreamReader(metaFile.FullName)) {
var meta = JsonConvert.DeserializeObject<ChartMeta>(reader.ReadToEnd());
name = meta.song.name;
desc = meta.chart.name;
}
}
return new ResourceItemMeta {
IsDirectory = false,
Icon = cover,
Name = name,
DescriptionMain = desc,
};
}
public ChartDetail GetItemDetail(int id) {
var item = items[id];
AsyncDelivery<Texture2D> cover = null;
var coverFile = item.GetFiles("cover.*");
if (coverFile.Length > 0) {
cover = new AsyncDelivery<Texture2D>();
var task = new LoadTextureTask(Game.FileProtocolPrefix + coverFile[0].FullName, cover.Deliver);
cover.CancelSource = task.Cancel;
Game.NetworkTaskWorker.SubmitNetworkTask(task);
}
ChartMeta meta = new ChartMeta();
var metaFile = new FileInfo(item.FullName + "/meta.json");
if (metaFile.Exists) {
using (var reader = new StreamReader(metaFile.FullName)) {
meta = JsonConvert.DeserializeObject<ChartMeta>(reader.ReadToEnd());
}
}
return new ChartDetail {
Cover = cover,
Meta = meta,
};
}
public string GetItemPath(int id) {
return items[id].Name + "/.umgc";
}
public bool ImportItemFrom(string path) {
var file = new FileInfo(path);
if (!converters.ContainsKey(file.Extension)) return false;
foreach (var converter in converters[file.Extension]) {
var resources = converter.ConvertFrom(file);
foreach (var res in resources) {
if (res is ChartResource) {
var tres = (ChartResource)res;
var dir = new DirectoryInfo(_rootPath + "/charts/" + res.Name);
if (!dir.Exists) dir.Create();
using (var writer = new StreamWriter(dir.FullName + "/.umgc")) {
writer.Write(JsonConvert.SerializeObject(tres.Main, Game.GlobalJsonSerializerSettings));
}
using (var writer = new StreamWriter(dir.FullName + "/meta.json")) {
writer.Write(JsonConvert.SerializeObject(tres.Meta, Game.GlobalJsonSerializerSettings));
}
}
else if (res is CoverResource) {
var tres = (CoverResource)res;
var dir = new DirectoryInfo(_rootPath + "/charts/" + res.Name);
if (!dir.Exists) dir.Create();
var dest = new FileInfo(_rootPath + "/charts/" + res.Name + "/cover" + tres.Source.Extension);
if (!dest.Exists) tres.Source.CopyTo(dest.FullName);
}
else if (res is SongResource) {
var tres = (SongResource)res;
var dir = new DirectoryInfo(_rootPath + "/songs/" + res.Name);
if (!dir.Exists) dir.Create();
var dest = new FileInfo(_rootPath + "/songs/" + res.Name + "/.ogg");
if (!dest.Exists) tres.Source.CopyTo(dest.FullName);
}
}
return true;
}
return false;
}
public string[] GetSupportedFormats() {
return converters.Keys.ToArray();
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: aac40491bc6619e47a5b81e6d9f1a5d3
timeCreated: 1637975898
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,55 @@
using UnityEngine;
using UnityEngine.EventSystems;
namespace Cryville.Crtr.Browsing {
public class PVPBool : PropertyValuePanel, IPointerClickHandler {
bool _value;
public override object Value {
get { return _value; }
set { _value = (bool)value; }
}
[SerializeField]
RectTransform m_on;
[SerializeField]
RectTransform m_handleArea;
[SerializeField]
RectTransform m_handle;
public void Toggle() {
_value = !_value;
Callback(Value);
}
const float SPEED = 8;
float _ratio;
#pragma warning disable IDE0051
void Start() {
m_handleArea.sizeDelta = new Vector2(m_handle.rect.height - m_handle.rect.width, 0);
}
void Update() {
if (_value && _ratio != 1) {
_ratio += SPEED * Time.deltaTime;
if (_ratio > 1) _ratio = 1;
UpdateGraphics();
}
else if (!_value && _ratio != 0) {
_ratio -= SPEED * Time.deltaTime;
if (_ratio < 0) _ratio = 0;
UpdateGraphics();
}
}
#pragma warning restore IDE0051
void UpdateGraphics() {
m_on.anchorMax = new Vector2(_ratio, m_on.anchorMax.y);
m_handle.anchorMin = new Vector2(_ratio, m_handle.anchorMin.y);
m_handle.anchorMax = new Vector2(_ratio, m_handle.anchorMax.y);
}
public void OnPointerClick(PointerEventData eventData) {
Toggle();
}
}
}

View File

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

View File

@@ -0,0 +1,147 @@
using System;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
namespace Cryville.Crtr.Browsing {
public class PVPNumber : PropertyValuePanel {
double m_value;
public override object Value {
get {
float s_value = GetDisplayValue();
return IntegerMode ? (object)(int)s_value : (object)s_value;
}
set {
if (value is double) m_value = (double)value;
else m_value = IntegerMode ? (double)(int)value : (double)(float)value;
float s_value = GetDisplayValue();
m_text.text = s_value.ToString();
if (Range != null && MaxStep == 0) {
SetRatio((float)(m_value - Range.Value.x) / (Range.Value.y - Range.Value.x));
}
}
}
float GetDisplayValue() {
double s_value = m_value;
if (Precision > 0)
s_value = Math.Round(s_value / Precision) * Precision;
if (IntegerMode)
s_value = Math.Round(s_value);
return (float)s_value;
}
public bool IntegerMode { get; set; }
public bool LogarithmicMode { get; set; }
public float MaxStep { get; set; }
public double Precision { get; set; }
public Vector2? Range { get; set; }
[SerializeField]
EventTrigger m_ctn;
[SerializeField]
RectTransform m_handleArea;
[SerializeField]
RectTransform m_handle;
[SerializeField]
Text m_text;
#pragma warning disable IDE0051
void Start() {
var ev = new EventTrigger.Entry { eventID = EventTriggerType.InitializePotentialDrag };
ev.callback.AddListener(e => OnInitializePotentialDrag((PointerEventData)e));
m_ctn.triggers.Add(ev);
ev = new EventTrigger.Entry { eventID = EventTriggerType.Drag };
ev.callback.AddListener(e => OnDrag((PointerEventData)e));
m_ctn.triggers.Add(ev);
ev = new EventTrigger.Entry { eventID = EventTriggerType.EndDrag };
ev.callback.AddListener(e => OnEndDrag((PointerEventData)e));
m_ctn.triggers.Add(ev);
ev = new EventTrigger.Entry { eventID = EventTriggerType.PointerClick };
ev.callback.AddListener(e => OnPointerClick((PointerEventData)e));
m_ctn.triggers.Add(ev);
m_handleArea.sizeDelta = new Vector2(m_handle.rect.height - m_handle.rect.width, 0);
if (MaxStep != 0) SetRatio(0.5f);
}
void Update() {
if (use && MaxStep != 0) {
SetRatio(GetRatioFromPos(pp));
SetValueFromPos(pp);
}
}
#pragma warning restore IDE0051
Vector2 pp;
bool use, nouse;
public void OnInitializePotentialDrag(PointerEventData eventData) {
eventData.useDragThreshold = false;
pp = eventData.position;
}
public void OnDrag(PointerEventData eventData) {
if (nouse) return;
if (!use) {
var delta = eventData.position - pp;
float dx = Mathf.Abs(delta.x), dy = Mathf.Abs(delta.y);
if (dx > dy) use = true;
else if (dx < dy) nouse = true;
}
if (use) {
pp = eventData.position;
if (MaxStep == 0) SetValueFromPos(eventData.position);
eventData.Use();
}
}
public void OnEndDrag(PointerEventData eventData) {
if (!nouse) {
SetValueFromPos(eventData.position);
Callback(Value);
if (MaxStep != 0) SetRatio(0.5f);
eventData.Use();
use = false;
}
nouse = false;
}
public void OnPointerClick(PointerEventData eventData) {
SetValueFromPos(eventData.position);
Callback(Value);
eventData.Use();
}
float GetRatioFromPos(Vector2 pos) {
Vector2 lp;
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(m_handleArea, pos, null, out lp)) {
lp -= m_handleArea.rect.position;
return Mathf.Clamp01(lp.x / m_handleArea.rect.width);
}
return float.NegativeInfinity;
}
void SetValueFromPos(Vector2 pos) {
double ratio = GetRatioFromPos(pos);
double result;
if (MaxStep == 0) {
if (LogarithmicMode) throw new NotImplementedException();
else result = (1 - ratio) * Range.Value.x + ratio * Range.Value.y;
}
else {
double delta = (ratio - 0.5f) * 2 * MaxStep * Time.deltaTime;
if (LogarithmicMode) result = Math.Pow(Math.E, Math.Log(m_value) + delta);
else result = m_value + delta;
}
if (Range != null) {
if (result < Range.Value.x) result = Range.Value.x;
else if (result > Range.Value.y) result = Range.Value.y;
}
Value = result;
}
void SetRatio(float ratio) {
m_handle.anchorMin = new Vector2(ratio, m_handle.anchorMin.y);
m_handle.anchorMax = new Vector2(ratio, m_handle.anchorMax.y);
}
}
}

View File

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

View File

@@ -0,0 +1,27 @@
using UnityEngine;
using UnityEngine.UI;
namespace Cryville.Crtr.Browsing {
internal class PathPart : MonoBehaviour {
private int _id;
private Text _exp;
#pragma warning disable IDE0051
void Awake() {
_exp = transform.Find("__text__").GetComponent<Text>();
}
#pragma warning restore IDE0051
internal void Load(int id, string exp) {
_id = id;
_exp.text = Parse(exp);
}
string Parse(string exp) {
if (exp == "") return "(root)";
else return exp;
}
public void OnClick() {
GetComponentInParent<ResourceBrowser>().OnPathClicked(_id);
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 5d443a346e9a19d4eabbb0fa9ec7016f
timeCreated: 1637566071
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,55 @@
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
using UnityEngine.UI;
using Cryville.Common.Unity.UI;
using System;
namespace Cryville.Crtr.Browsing {
public class PropertyCategoryPanel : MonoBehaviour {
[SerializeField]
private GameObject m_propertyPrefab;
Text _nameLabel = null;
string _name;
public string Name {
get { return _name; }
set { _name = value; UpdateName(); }
}
bool _collapsed = false;
public bool Collapsed {
get { return _collapsed; }
set { _collapsed = value; UpdateName(); }
}
#pragma warning disable IDE0051
void Awake() {
_nameLabel = transform.Find("Name/__text__").GetComponent<Text>();
transform.Find("Name").GetComponent<Button>().onClick.AddListener(ToggleCollapsed);
}
#pragma warning restore IDE0051
public void Load(string name, IEnumerable<PropertyInfo> props, object target) {
Name = name.ToUpper();
foreach (var prop in props) {
var obj = GameObject.Instantiate<GameObject>(m_propertyPrefab);
obj.transform.SetParent(transform, false);
obj.GetComponent<PropertyPanel>().Load(prop, target);
obj.GetComponent<AspectRatioLayoutElement>().ContainerTransform = (RectTransform)transform;
}
}
void ToggleCollapsed() {
Collapsed = !Collapsed;
for (int i = 1; i < transform.childCount; i++) {
transform.GetChild(i).gameObject.SetActive(!Collapsed);
}
}
private void UpdateName() {
_nameLabel.text = (Collapsed ? "+ " : "- ") + Name;
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 3a13b7ea14b96e54ea8a7e6ba1275281
timeCreated: 1638435211
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,73 @@
using Cryville.Common.ComponentModel;
using System.Reflection;
using UnityEngine;
using UnityEngine.UI;
using RangeAttribute = Cryville.Common.ComponentModel.RangeAttribute;
namespace Cryville.Crtr.Browsing {
public class PropertyPanel : MonoBehaviour {
[SerializeField]
GameObject m_bool;
[SerializeField]
GameObject m_number;
PropertyInfo _property;
object _target;
Text _key;
Transform _valueContainer;
PropertyValuePanel _value;
#pragma warning disable IDE0051
void Awake() {
_key = transform.Find("Key").GetComponent<Text>();
_valueContainer = transform.Find("Value");
}
#pragma warning restore IDE0051
public void Load(PropertyInfo prop, object target) {
_target = target;
_property = prop;
_key.text = prop.Name;
GameObject vp;
if (prop.PropertyType == typeof(bool)) vp = m_bool;
else if (prop.PropertyType == typeof(float) || prop.PropertyType == typeof(int)) vp = m_number;
else return;
_value = GameObject.Instantiate(vp, _valueContainer).GetComponent<PropertyValuePanel>();
if (_value is PVPNumber) {
var t = (PVPNumber)_value;
t.IntegerMode = prop.PropertyType == typeof(int);
var attr = prop.GetCustomAttributes(typeof(RangeAttribute), true);
if (attr.Length > 0) {
var u = (RangeAttribute)attr[0];
t.Range = new Vector2(u.Min, u.Max);
}
attr = prop.GetCustomAttributes(typeof(PrecisionAttribute), true);
if (attr.Length > 0) {
var u = (PrecisionAttribute)attr[0];
t.Precision = u.Precision;
}
attr = prop.GetCustomAttributes(typeof(StepAttribute), true);
if (attr.Length > 0) {
var u = (StepAttribute)attr[0];
t.MaxStep = u.Step;
}
attr = prop.GetCustomAttributes(typeof(LogarithmicScaleAttribute), true);
if (attr.Length > 0) {
t.LogarithmicMode = true;
}
}
_value.Callback = SetValueToObject;
GetValueFromObject();
}
void GetValueFromObject() {
_value.Value = _property.GetValue(_target, null);
}
void SetValueToObject(object value) {
_property.SetValue(_target, value, null);
GetValueFromObject();
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: bcca29fea992ac24698a213f0e2baedc
timeCreated: 1638435590
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
using System;
using UnityEngine;
namespace Cryville.Crtr.Browsing {
public abstract class PropertyValuePanel : MonoBehaviour {
public Action<object> Callback { protected get; set; }
public abstract object Value { get; set; }
}
}

View File

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

View File

@@ -0,0 +1,73 @@
using Cryville.Common.Unity;
using Cryville.Common.Unity.UI;
using UnityEngine;
using UnityEngine.UI;
namespace Cryville.Crtr.Browsing {
public class ResourceBrowser : ResourceBrowserUnit {
public IResourceManager<ChartDetail> ResourceManager;
public ScrollableItemGrid PathContainer;
public ScrollableItemGrid ItemContainer;
FileDialog _dialog;
#pragma warning disable IDE0051
protected void Start() {
PathContainer.LoadItem = LoadPathPart;
ItemContainer.LoadItem = LoadItem;
ItemContainer.ItemCount = ResourceManager.ChangeDirectory(new string[] { "" });
PathContainer.ItemCount = ResourceManager.CurrentDirectory.Length;
_dialog = GameObject.Instantiate(Resources.Load<GameObject>("Common/FileDialog")).GetComponent<FileDialog>();
_dialog.gameObject.SetActive(false);
}
#pragma warning restore IDE0051
private bool LoadPathPart(int id, GameObject obj) {
var item = ResourceManager.CurrentDirectory[id];
obj.GetComponent<PathPart>().Load(id, item);
return true;
}
private bool LoadItem(int id, GameObject obj) {
var bi = obj.GetComponent<BrowserItem>();
if (bi.Id == id) return true;
var item = ResourceManager.GetItemMeta(id);
bi.Load(id, item);
return true;
}
public void OnDirectoryItemClicked(int id) {
ItemContainer.ItemCount = ResourceManager.OpenDirectory(id);
PathContainer.ItemCount = ResourceManager.CurrentDirectory.Length;
if (PathContainer.ItemCount >= PathContainer.VisibleLines - 1)
PathContainer.GetComponentInParent<ScrollRect>().velocity = new Vector2(-Screen.width, 0);
}
public void OnObjectItemClicked(int id) {
Master.ShowDetail(id, ResourceManager.GetItemDetail(id));
}
public void OnPathClicked(int id) {
ItemContainer.ItemCount = ResourceManager.ReturnToDirectory(id);
PathContainer.ItemCount = ResourceManager.CurrentDirectory.Length;
}
public void OnAddButtonClicked() {
_dialog.Callback = OnAddDialogClosed;
_dialog.Filter = ResourceManager.GetSupportedFormats();
_dialog.Show();
}
private void OnAddDialogClosed() {
if (_dialog.FileName == null) return;
if (ResourceManager.ImportItemFrom(_dialog.FileName)) {
Debug.Log("Import succeeded"); // TODO
OnPathClicked(ResourceManager.CurrentDirectory.Length - 1);
}
else {
Debug.Log("Import failed"); // TODO
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: c6b4df13dea0e4a469d7e54e7e8fb428
timeCreated: 1637234060
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,113 @@
using Cryville.Common;
using Cryville.Common.Unity.UI;
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
namespace Cryville.Crtr.Browsing {
public class ResourceBrowserMaster : MonoBehaviour {
[SerializeField]
private Button m_playButton;
[SerializeField]
private Button m_configButton;
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
void Awake() {
_group = GetComponent<DockLayoutGroup>();
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);
}
int _slideDest = 0;
void Update() {
var cv = _group.SlideIndex;
_group.SlideIndex = (cv - _slideDest) * 0.86f + _slideDest;
}
#pragma warning restore IDE0051
public void ShowDetail(int id, ChartDetail detail) {
SlideIntoView(1);
_detailPanel.Load(id, detail);
m_playButton.gameObject.SetActive(true);
m_configButton.gameObject.SetActive(true);
}
/*[Obsolete]
public void ShowSettings(int id, ChartDetail detail) {
SlideIntoView(2);
_settingsPanel.Load(id, detail);
}*/
public bool Back() {
if (_slideDest == 0) return false;
SlideIntoView(_slideDest - 1);
return true;
}
private void SlideIntoView(int v) {
v = Mathf.Clamp(v, 0, _units.Count - 1);
var cv = _group.SlideIndex;
if (cv < v) _slideDest = v - 1;
else _slideDest = v;
_units[_slideDest].SlideToLeft();
_units[_slideDest + 1].SlideToRight();
}
public void Open(int id) {
SetDataSettings(id);
#if UNITY_5_3_OR_NEWER
SceneManager.LoadScene("Play", LoadSceneMode.Additive);
#else
Application.LoadLevelAdditive("Play");
#endif
GameObject.Find("/Master").GetComponent<Master>().HideMenu();
}
public void OpenConfig(int id) {
SetDataSettings(id);
#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) {
Settings.Default.LoadRuleset = "key/.umgr";
Settings.Default.LoadSkin = "key/0/.umgs";
Settings.Default.LoadChart = MainBrowser.ResourceManager.GetItemPath(id);
}
}
public struct ChartDetail {
public AsyncDelivery<Texture2D> Cover { get; set; }
public ChartMeta Meta { get; set; }
}
#pragma warning disable IDE1006
public struct ChartMeta {
public MetaInfo song { get; set; }
public MetaInfo chart { get; set; }
public struct MetaInfo {
public string name { get; set; }
public string author { get; set; }
public float length { get; set; }
}
public string ruleset { get; set; }
public int note_count { get; set; }
}
#pragma warning restore IDE1006
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 256d7d3efda1f9b4c882eb42e608cc8e
timeCreated: 1638414803
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,14 @@
using UnityEngine;
namespace Cryville.Crtr.Browsing {
public abstract class ResourceBrowserUnit : MonoBehaviour {
protected ResourceBrowserMaster Master { get; private set; }
#pragma warning disable IDE0051
protected virtual void Awake() {
Master = GetComponentInParent<ResourceBrowserMaster>();
}
#pragma warning restore IDE0051
public virtual void SlideToLeft() { }
public virtual void SlideToRight() { }
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: a69c80e5f3e7bd04485bc3afc5826584
timeCreated: 1638415083
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,33 @@
using System.Collections.Generic;
using System.IO;
namespace Cryville.Crtr.Browsing {
public abstract class ResourceConverter {
public abstract string[] GetSupportedFormats();
public abstract IEnumerable<Resource> ConvertFrom(FileInfo file);
}
public abstract class Resource {
protected Resource(string name) {
Name = name;
}
public string Name { get; private set; }
}
public class ChartResource : Resource {
public ChartResource(string name, Chart main, ChartMeta meta) : base(name) {
Main = main; Meta = meta;
}
public Chart Main { get; private set; }
public ChartMeta Meta { get; private set; }
}
public class CoverResource : Resource {
public CoverResource(string name, FileInfo src) : base(name) {
Source = src;
}
public FileInfo Source { get; private set; }
}
public class SongResource : Resource {
public SongResource(string name, FileInfo src) : base(name) {
Source = src;
}
public FileInfo Source { get; private set; }
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 2546fb1d514348842a14a03531be192d
timeCreated: 1637982768
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,91 @@
using System;
using System.Collections;
using System.Collections.Generic;
namespace Cryville.Crtr {
public class CastedList<T> : IList<T>, IList, IReadOnlyList<T> {
IList _list;
public CastedList(IList list) {
_list = list;
}
public T this[int index] {
get { return (T)_list[index]; }
set { _list[index] = value; }
}
object IList.this[int index] {
get { return _list[index]; }
set { _list[index] = value; }
}
public int Count { get { return _list.Count; } }
public bool IsReadOnly { get { return _list.IsReadOnly; } }
public bool IsFixedSize { get { return _list.IsFixedSize; } }
public bool IsSynchronized { get { return _list.IsSynchronized; } }
public object SyncRoot { get { return _list.SyncRoot; } }
public void Add(T item) { _list.Add(item); }
public int Add(object value) { return _list.Add(value); }
public void Clear() { _list.Clear(); }
public bool Contains(T item) { return _list.Contains(item); }
public bool Contains(object value) { return _list.Contains(value); }
public void CopyTo(T[] array, int arrayIndex) { _list.CopyTo(array, arrayIndex); }
public void CopyTo(Array array, int index) { _list.CopyTo(array, index); }
public IEnumerator<T> GetEnumerator() { return new Enumerator(this); }
class Enumerator : IEnumerator<T> {
readonly CastedList<T> _list;
int _index;
public T Current { get; private set; }
object IEnumerator.Current { get { return Current; } }
public Enumerator(CastedList<T> list) {
_list = list;
}
public void Dispose() { }
public bool MoveNext() {
if (_index >= _list.Count) return false;
Current = _list[_index];
_index++;
return true;
}
public void Reset() { _index = 0; }
}
public int IndexOf(T item) { return _list.IndexOf(item); }
public int IndexOf(object value) { return _list.IndexOf(value); }
public void Insert(int index, T item) { _list.Insert(index, item); }
public void Insert(int index, object value) { _list.Insert(index, value); }
public bool Remove(T item) {
if (!_list.Contains(item)) return false;
_list.Remove(item);
return true;
}
public void Remove(object value) { _list.Remove(value); }
public void RemoveAt(int index) { _list.RemoveAt(index); }
IEnumerator IEnumerable.GetEnumerator() { return _list.GetEnumerator(); }
}
}

View File

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

View File

@@ -0,0 +1,477 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text.RegularExpressions;
namespace Cryville.Crtr {
[JsonConverter(typeof(BeatTimeConverter))]
public struct BeatTime {
[JsonConstructor()]
public BeatTime(int _b, int _n, int _d) {
b = _b;
n = _n;
d = _d;
}
[JsonIgnore]
public int b;
[JsonIgnore]
public int n;
[JsonIgnore]
public int d;
}
public class BeatTimeConverter : JsonConverter {
public override bool CanConvert(Type objectType) {
return objectType == typeof(int[]);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
int b = (int)reader.ReadAsInt32();
int n = (int)reader.ReadAsInt32();
int d = (int)reader.ReadAsInt32();
reader.Read();
return new BeatTime(b, n, d);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) {
BeatTime obj = (BeatTime)value;
writer.WriteStartArray();
writer.WriteValue(obj.b);
writer.WriteValue(obj.n);
writer.WriteValue(obj.d);
writer.WriteEndArray();
}
}
public abstract class ChartEvent {
public BeatTime? time;
[JsonIgnore]
public float BeatPosition {
get {
return time.Value.b + time.Value.n / (float)time.Value.d + BeatOffset;
}
}
public BeatTime? endtime;
[JsonIgnore]
public float EndBeatPosition {
get {
if (endtime == null) return BeatPosition;
return endtime.Value.b + endtime.Value.n / (float)endtime.Value.d + BeatOffset;
}
}
[JsonIgnore]
public float BeatOffset;
[JsonIgnore]
public abstract int Priority {
get;
}
public ChartEvent Clone() {
return (ChartEvent)MemberwiseClone();
}
/*[DefaultValue(0.0f)][Obsolete]
public float duration = 0.0f;*/
[JsonIgnore]
public float Duration {
get {
if (endtime == null) return 0;
return EndBeatPosition - BeatPosition;
}
}
[JsonIgnore]
public bool IsLong {
get { return Duration > 0; }
}
/*[JsonIgnore]
public float EndBeatPosition {
get {
return BeatPosition + duration;
}
}*/
private InstantEvent attev = null;
[JsonIgnore]
public InstantEvent AttackEvent {
get {
if (attev == null) attev = new InstantEvent(this);
return attev;
}
}
private InstantEvent relev = null;
[JsonIgnore]
public InstantEvent ReleaseEvent {
get {
if (relev == null) relev = new InstantEvent(this, true);
return relev;
}
}
/*[JsonIgnore]
[Obsolete]
public Dictionary<string, Func<object>> Properties { get; private set; }
[Obsolete]
protected void SubmitProperty(string name, Func<object> property) {
Properties.Add(name, property);
}*/
[JsonIgnore]
public Dictionary<string, PropSrc> PropSrcs { get; private set; }
protected void SubmitPropSrc(string name, PropSrc property) {
PropSrcs.Add(name, property);
}
[JsonIgnore]
public Dictionary<string, PropOp> PropOps { get; private set; }
protected void SubmitPropOp(string name, PropOp property) {
PropOps.Add(name, property);
}
protected ChartEvent() {
/*
Properties = new Dictionary<string, Func<object>>();
SubmitProperty("long", () => @long);
*/
PropSrcs = new Dictionary<string, PropSrc>();
SubmitPropSrc("long", new PropSrc.Boolean(() => IsLong));
PropOps = new Dictionary<string, PropOp>();
}
}
public class InstantEvent : ChartEvent {
public readonly ChartEvent Original;
public bool IsRelease;
public InstantEvent(ChartEvent orig, bool release = false) {
IsRelease = release;
if (orig != null) {
Original = orig;
time = orig.time;
if (IsRelease)
BeatOffset = orig.Duration;
}
}
public override int Priority {
get {
return Original.Priority + 1;
}
}
}
public abstract class EventContainer : ChartEvent {
public List<Chart.Motion> motions = new List<Chart.Motion>();
[JsonIgnore]
public virtual IEnumerable<ChartEvent> Events {
get {
return motions.Cast<ChartEvent>();
}
}
public virtual EventList GetEventsOfType(string type) {
switch (type) {
case "motions": return new EventList<Chart.Motion>(motions);
default: throw new ArgumentException("Unknown type");
}
}
}
public abstract class EventList : ChartEvent {
public IList<ChartEvent> Events { get; private set; }
protected EventList(IList<ChartEvent> events) {
Events = events;
SubmitPropSrc("count", new PropSrc.Float(() => Events.Count));
SubmitPropOp("count", new ListCountOp(() => Events));
}
public abstract ChartEvent Create();
public override int Priority {
get { throw new NotSupportedException("Fake event"); }
}
class ListCountOp : PropOp {
readonly Func<IList<ChartEvent>> _cb;
public ListCountOp(Func<IList<ChartEvent>> cb) {
_cb = cb;
}
protected override void Execute() {
int ac = _cb().Count;
int ec = (int)Math.Round(GetOperand(0).AsNumber());
if (ac != ec) {
throw new RulesetViolationException(string.Format(
"Event count not matched, expected {0}, got {1}", ec, ac
));
}
}
}
}
public class EventList<T> : EventList where T : ChartEvent, new() {
public EventList(List<T> events) : base(new CastedList<ChartEvent>(events)) { }
public override ChartEvent Create() {
return new T();
}
}
public class Chart : EventContainer {
[JsonRequired]
public long format; // Format Version
public string ruleset;
public List<Group> groups = new List<Group>();
public override IEnumerable<ChartEvent> Events {
get {
return base.Events
.Concat(groups.Cast<ChartEvent>())
.Concat(sigs.Cast<ChartEvent>())
.Concat(sounds.Cast<ChartEvent>());
}
}
public override EventList GetEventsOfType(string type) {
switch (type) {
case "groups": return new EventList<Group>(groups);
default: return base.GetEventsOfType(type);
}
}
public override int Priority {
get { return 0; }
}
public class Group : EventContainer {
public List<Track> tracks = new List<Track>();
public List<Note> notes = new List<Note>();
public override IEnumerable<ChartEvent> Events {
get {
return tracks.Cast<ChartEvent>()
.Concat(notes.Cast<ChartEvent>()
.Concat(motions.Cast<ChartEvent>()
));
}
}
public override EventList GetEventsOfType(string type) {
switch (type) {
case "tracks": return new EventList<Track>(tracks);
case "notes": return new EventList<Note>(notes);
default: return base.GetEventsOfType(type);
}
}
public override int Priority {
get { return 0; }
}
}
public class Track : EventContainer {
public override int Priority {
get { return 0; }
}
}
public class Motion : ChartEvent {
#pragma warning disable IDE1006
[JsonRequired]
public string motion {
get { return ToString(); }
set { LoadFromString(value); }
}
#pragma warning restore IDE1006
private void LoadFromString(string s) {
Match m = Regex.Match(s, @"^(.+?)(#(\d+))?(@(.+?))?(\^(.+?))?(\*(.+?))?(:(.+))?$");
if (!m.Success) throw new ArgumentException(); // TODO
name = new MotionName(m.Groups[1].Value);
var registry = ChartPlayer.motionRegistry[name.MainName];
if (m.Groups[3].Success) {
ushort id = ushort.Parse(m.Groups[3].Value);
Vec1 time = m.Groups[5].Success ? new Vec1(m.Groups[5].Value) : null;
byte? trs = m.Groups[7].Success ? byte.Parse(m.Groups[7].Value) : (byte?)null;
Vec1 rate = m.Groups[9].Success ? new Vec1(m.Groups[9].Value) : null;
Vector value = m.Groups[11].Success ? Vector.Construct(registry.Type, m.Groups[11].Value) : null;
RelativeNode = new MotionNode() {
Id = id,
Time = time,
Transition = (TransitionType?)trs,
Rate = rate,
Value = value
};
}
else {
AbsoluteValue = Vector.Construct(registry.Type, m.Groups[11].Value);
}
}
public override string ToString() {
string result = Name.ToString();
if (RelativeNode != null) {
var node = RelativeNode;
result += "#" + node.Id;
if (node.Time != null) result += "@" + node.Time.ToString();
if (node.Transition != null) result = "^" + node.Transition.ToString();
if (node.Rate != null) result += "*" + node.Rate.ToString();
if (node.Value != null) result += ":" + node.Value.ToString();
}
else {
result += ":" + AbsoluteValue.ToString();
}
return result;
}
private MotionName name;
[JsonIgnore]
public MotionName Name {
get {
return name;
}
private set {
MotionRegistry reg;
if (!ChartPlayer.motionRegistry.TryGetValue(value.MainName, out reg))
throw new ArgumentException("Invalid motion name");
if (RelativeNode != null) RelativeNode.Value = reg.InitValue;
else AbsoluteValue = reg.InitValue;
name = value;
}
}
[JsonIgnore]
public Vector AbsoluteValue;
[JsonIgnore]
public MotionNode RelativeNode;
/*public struct Node {
public ushort Id;
public Vec1 Time;
public TransitionType? Transition;
public Vec1 Rate;
public Vector Value;
public Node LerpWith(MotionNode start, float lerpedTime) {
Vec1 time = Time == null ? null : (Vec1)Time.LerpWith(start.Time, lerpedTime);
Vec1 rate = Rate == null ? null : (Vec1)Rate.LerpWith(start.Rate, lerpedTime);
Vector value = Value == null ? null : Value.LerpWith(start.Value, lerpedTime);
return new Node() {
Id = Id,
Time = time,
Transition = Transition,
Rate = rate,
Value = value
};
}
}*/
[DefaultValue(TransitionType.Ease)]
public TransitionType transition = TransitionType.Ease;
[DefaultValue(1.0f)]
public float rate = 1.0f;
[DefaultValue(0.0f)]
public float sumfix = 0.0f;
public override int Priority {
get { return -2; }
}
public Motion() {
SubmitPropSrc("value", new VectorSrc(() => {
if (RelativeNode != null) return RelativeNode.Value;
else return AbsoluteValue;
}));
SubmitPropOp("motion", new PropOp.String(v => motion = v));
SubmitPropOp("name", new PropOp.String(v => {
var n = new MotionName(v);
if (Name.Equals(n)) { }
else if (Name.Equals(default(MotionName))) Name = n;
else throw new RulesetViolationException(string.Format(
"Motion name not matched, expected {0}, got {1}", n, Name
));
}));
SubmitPropOp("value", new VectorOp(v => {
var vec = Vector.Construct(ChartPlayer.motionRegistry[Name.MainName].Type, v);
if (RelativeNode != null) RelativeNode.Value = vec;
else AbsoluteValue = vec;
}));
}
}
public class Note : EventContainer {
public Note() : base() {
/*
SubmitProperty("judge", () => judge);
SubmitProperty("endjudge", () => endjudge);
SubmitProperty("track", () => {
if (_track == null) {
var i = motions.FirstOrDefault(m => m.RelativeNode == null && m.Name.MainName == "track");
if (i == null) _track = ((Vec1)ChartPlayer.motionRegistry["track"].InitValue).Value;
else _track = ((Vec1)i.AbsoluteValue).Value;
}
return _track.Value;
});
*/
SubmitPropSrc("judge", new PropSrc.String(() => judge));
SubmitPropSrc("endjudge", new PropSrc.String(() => endjudge));
SubmitPropSrc("track", new PropSrc.Float(() => {
var i = motions.FirstOrDefault(m => m.RelativeNode == null && m.Name.MainName == "track");
if (i == null) return ((Vec1)ChartPlayer.motionRegistry["track"].InitValue).Value;
else return ((Vec1)i.AbsoluteValue).Value;
}));
SubmitPropOp("judge", new PropOp.String(v => judge = v));
SubmitPropOp("endjudge", new PropOp.String(v => endjudge = v));
}
/*[DefaultValue(false)][Obsolete]
public bool wipe = false;*/
public string judge;
public string endjudge;
public override int Priority {
get { return 2; }
}
}
/*
public class InternalJudgement : ChartEvent {
public Note Parent;
public override int Priority {
get { return 0; }
}
}*/
// TODO will likely be deprecated in the future
public List<Signature> sigs; // Signatures
// TODO [Obsolete]
public class Signature : ChartEvent {
public float? tempo;
public override int Priority {
get { return -4; }
}
}
public List<Sound> sounds;
public class Sound : ChartEvent {
[JsonRequired]
public string id;
// TODO [Obsolete]
public float offset;
public override int Priority {
get { return 0; }
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: dd30e195a83a9cd47ba89121475b89fa
timeCreated: 1591683606
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,164 @@
//#define NO_SOUND
using Cryville.Audio.Source;
using Cryville.Crtr.Event;
using System;
using System.Collections.Generic;
using System.IO;
namespace Cryville.Crtr {
public class ChartHandler : ContainerHandler {
//private StampedState cs;
public Chart chart;
//readonly Dictionary<string, Sound> sounds = new Dictionary<string, Sound>();
readonly List<LibavFileAudioSource> sounds = new List<LibavFileAudioSource>();
public ChartHandler(Chart _chart, DirectoryInfo dir) : base() {
if (dir == null) throw new ArgumentNullException("dir");
chart = _chart;
/*foreach (Chart.Group g in chart.groups) {
var gh = new GroupHandler(g, this);
// cs.AddChild(new StampedState(new StampedState(chart, sevs)));
}*/
//PrehandleEvents();
}
public override string TypeName {
get {
return "chart";
}
}
public override void PreInit() {
base.PreInit();
}
public override void Init() {
base.Init();
#if !NO_SOUND
/*foreach (Chart.Sound ev in chart.sounds) {
sounds.Add(ev, new LibavFileAudioSource(
Game.GameDataPath + "/songs/" + ev.id + "/.ogg"
));
Logger.Log("main", 0, "Load", "Loading song: {0}", ev.id);
}*/
#endif
}
public override void Dispose() {
if (Disposed) return;
base.Dispose();
// foreach (var h in handlers) h.Dispose();
foreach (var s in sounds) s.Dispose();
}
/*List<StampedEvent> sevs = new List<StampedEvent>();
public void PrehandleEvents() {
EventPrehandler ph = new EventPrehandler(
chart,
chart.motions.Cast<Chart.Event>()
.Concat<Chart.Event>(chart.signs.Cast<Chart.Event>())
.Concat<Chart.Event>(chart.sounds.Cast<Chart.Event>())
);
// foreach (var h in handlers) h.StartPrehandler(ph);
ph.Forward(ev => {
if (ev is Chart.Sound) {
Chart.Sound tev = (Chart.Sound)ev;
sevs.Add(new StampedEvent.PlaySound() {
Time = ph.Time - tev.offset + Settings.Default.SoundOffset,
Event = tev
});
}
// foreach (var h in handlers) h.PrehandleToTime(ph.Time);
});
sevs = sevs.Concat(ph.Result).ToList();
cs = new StampedState(chart, sevs);
// foreach (var h in handlers) h.EndPrehandler(cs);
}*/
public override void Update(ContainerState s, StampedEvent ev) {
base.Update(s, ev);
if (s.CloneType == 16) {
if (ev == null) { }
else if (ev.Unstamped == null) { }
else if (ev.Unstamped is Chart.Sound) {
Chart.Sound tev = (Chart.Sound)ev.Unstamped;
var source = new LibavFileAudioSource(
Game.GameDataPath + "/songs/" + tev.id + "/.ogg"
);
source.SelectStream();
sounds.Add(source);
Game.AudioSession.Sequence(
s.Time - tev.offset + ChartPlayer.soundOffset,
source
);
/*var l = new List<StampedEvent> {
new StampedEvent.PlaySound() {
Time = s.Time - tev.offset + ChartPlayer.soundOffset,
Container = chart,
Unstamped = tev
}
};
cs.Bus.IssuePatch(l);*/
}
}
}
public override void ExUpdate(ContainerState s, StampedEvent ev) {
base.ExUpdate(s, ev);
if (s.CloneType == 0) {
/*#if !NO_SOUND
if (ev is StampedEvent.PlaySound) {
StampedEvent.PlaySound tev = (StampedEvent.PlaySound)ev;
// sounds[tev.Event.file.ToLower()].audioSource.time = toTime - cs.Time;
sounds[tev.Unstamped.id].audioSource.Play();
}
#endif*/
}
}
public override void EndUpdate(ContainerState s) {
base.EndUpdate(s);
// TODO End of chart
}
/*public void SendInput(int id, TouchPhase phase, Vector2 pos) {
// Vector2 jpos = Camera.main.ScreenToWorldPoint(new Vector3(pos.x, pos.y, -cameraZ));
/*foreach (var h in handlers) {
h.SendInput(id, phase, jpos);
}*
}
int hits = 0;
int misses = 0;
public void ReportJudge(bool hit) {
if (hit) hits++;
else misses++;
GameObject.Find("Status").GetComponent<Text>().text = string.Format("Hits: {0}\nMisses: {1}", hits, misses);
}*/
}
/*public class ChartState : ChartEventStateBase {
public ChartState(Chart c) : base(
c,
c.motions.Cast<Chart.Event>()
.Concat<Chart.Event>(c.signs.Cast<Chart.Event>())
.Concat<Chart.Event>(c.sounds.Cast<Chart.Event>())
) { }
protected override void Handle(Chart.Event ev) {
/*if (ev is Chart.Signature) {
Chart.Signature tev = (Chart.Signature)ev;
float tempo = tev.tempo;
if (tempo != 0)
Tempo = tempo;
}*
base.Handle(ev);
}
}*/
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: d8339b62359a4eb428e5d7939a0e8fe4
timeCreated: 1593870951
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,630 @@
//#define NO_THREAD
#define BUILD
using Cryville.Common;
using Cryville.Common.Plist;
using Cryville.Crtr.Event;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.SceneManagement;
using UnityEngine.Scripting;
using UnityEngine.UI;
using diag = System.Diagnostics;
using Logger = Cryville.Common.Logger;
namespace Cryville.Crtr {
public class ChartPlayer : MonoBehaviour, IDisposable {
Chart chart;
Skin skin;
PdtSkin pskin;
Ruleset ruleset;
public static PdtRuleset pruleset;
public static Dictionary<string, Texture2D> texs;
public static Dictionary<string, Cocos2dFrames.Frame> frames;
List<Cocos2dFrames> plists;
readonly Queue<string> texLoadQueue = new Queue<string>();
#if UNITY_5_4_OR_NEWER
DownloadHandlerTexture texHandler;
UnityWebRequest texLoader = null;
#else
WWW texLoader = null;
#endif
// ChartHandler handler;
// StampedState cs;
EventBus cbus;
EventBus bbus;
EventBus tbus;
EventBus nbus;
Judge judge;
bool started = false;
static bool initialized;
static Text logs;
Text status;
// static EventSystem eventSystem;
// static MetaDatabase metadb;
public static Rect hitRect;
public static Vector2 screenSize;
public static Plane[] frustumPlanes;
public static bool disableGC = true;
public static float clippingDist = 1f;
public static float judgeTolerance = 0.1f;
public static float renderDist = 6f;
public static float renderStep = 0.05f;
public static float actualRenderStep = 0f;
public static bool autoRenderStep = false;
public static float soundOffset = 0;
public static float startOffset = 0;
public static float sv = 16f;
public static Dictionary<string, MotionRegistry> motionRegistry = new Dictionary<string, MotionRegistry>();
// public static AudioMixerGroup mixer;
public static PdtEvaluator etor;
~ChartPlayer() {
Dispose();
}
public void Dispose() {
#if !NO_THREAD
if (loadThread != null) loadThread.Abort();
#endif
if (texLoader != null) texLoader.Dispose();
}
void Start() {
var logobj = GameObject.Find("Logs");
if (logobj != null)
logs = logobj.GetComponent<Text>();
if (!initialized) {
Game.Init();
// mixer = Resources.Load<AudioMixerGroup>("GameAudioMixer");
GenericResources.LoadDefault();
// eventSystem = GameObject.Find("EventSystem").GetComponent<EventSystem>();
// metadb = new MetaDatabase(new DirectoryInfo(persistentDataPath + "/db/cryville.github.io"));
initialized = true;
}
OnSettingsUpdate();
status = GameObject.Find("Status").GetComponent<Text>();
texHandler = new DownloadHandlerTexture();
Game.NetworkTaskWorker.SuspendBackgroundTasks();
#if BUILD
Play();
#endif
// metadb.GetObject(new Guid(""));
// Camera.main.RenderToCubemap();
}
void Update() {
if (Input.GetKeyDown(KeyCode.Return)) TogglePlay();
// if (Input.GetKeyDown(KeyCode.Escape)) ReturnToConsole();
if (started) {
try {
if (Screen.width != screenSize.x || Screen.height != screenSize.y)
throw new InvalidOperationException("Window resized while playing");
//cs.ForwardByTime(Time.deltaTime);
float dt = firstFrame
? 1f / Application.targetFrameRate
: Time.deltaTime;
firstFrame = false;
cbus.ForwardByTime(dt);
bbus.ForwardByTime(dt);
UnityEngine.Profiling.Profiler.BeginSample("ChartPlayer.FeedJudge");
judge.StartFrame();
Game.InputManager.EnumerateEvents(ev => {
// Logger.Log("main", 0, "Input", ev.ToString());
judge.Feed(ev);
});
judge.EndFrame();
UnityEngine.Profiling.Profiler.EndSample();
/*StampedState ts = (StampedState)cs.Clone();
ts.ForwardStepToTime(cs.Time + fogDist, renderStep);
ts.BroadcastEndUpdate();*/
UnityEngine.Profiling.Profiler.BeginSample("ChartPlayer.Forward");
UnityEngine.Profiling.Profiler.BeginSample("EventBus.Copy");
bbus.CopyTo(2, tbus);
bbus.CopyTo(3, nbus);
UnityEngine.Profiling.Profiler.EndSample();
float step = autoRenderStep ? ( firstFrame
? 1f / Application.targetFrameRate
: Time.smoothDeltaTime
) : renderStep;
actualRenderStep = step;
nbus.ForwardStepByTime(clippingDist, step);
nbus.BroadcastEndUpdate();
nbus.Anchor();
tbus.ForwardStepByTime(clippingDist, step);
tbus.ForwardStepByTime(renderDist, step);
tbus.BroadcastEndUpdate();
UnityEngine.Profiling.Profiler.EndSample();
}
catch (Exception ex) {
Game.LogException("Game", "An error occured while playing", ex);
Stop();
}
}
#if !NO_THREAD
else if (loadThread != null) {
if (texLoader != null) {
string url = texLoader.url;
string name = StringUtils.TrimExt(url.Substring(url.LastIndexOfAny(new char[] {'/', '\\'}) + 1));
#if UNITY_5_4_OR_NEWER
if (texHandler.isDone) {
var tex = texHandler.texture;
texs.Add(name, tex);
Logger.Log("main", 0, "Load/MainThread", "Loaded texture {0} ({1} bytes)", name, texLoader.downloadedBytes);
texLoader.Dispose();
texHandler.Dispose();
texLoader = null;
}
else if (texLoader.downloadProgress != 0) {
Logger.Log("main", 0, "Load/MainThread", "Loading texture {0} {1:P0}", name, texLoader.downloadProgress);
}
#else
if (texLoader.isDone) {
var tex = texLoader.texture;
texs.Add(name, tex);
Logger.Log("main", 0, "Load/MainThread", "Loaded texture {0} ({1} bytes)", name, texLoader.bytesDownloaded);
texLoader.Dispose();
texLoader = null;
}
else if (texLoader.progress != 0) {
Logger.Log("main", 0, "Load/MainThread", "Loading texture {0} {1:P0}", name, texLoader.progress);
}
#endif
}
if (texLoader == null)
if (texLoadQueue.Count > 0) {
#if UNITY_5_4_OR_NEWER
texHandler = new DownloadHandlerTexture();
texLoader = new UnityWebRequest(Game.FileProtocolPrefix + texLoadQueue.Dequeue(), "GET", texHandler, null);
texLoader.SendWebRequest();
#else
texLoader = new WWW(Game.FileProtocolPrefix + texLoadQueue.Dequeue());
#endif
}
else if (!texloaddone) {
texloaddone = true;
texloadtimer.Stop();
Logger.Log("main", 1, "Load/MainThread", "Main thread done ({0}ms)", texloadtimer.Elapsed.TotalMilliseconds);
}
if (!loadThread.IsAlive) {
if (cbus == null) {
Logger.Log("main", 4, "Load/MainThread", "Load failed");
loadThread = null;
#if BUILD
ReturnToMenu();
#endif
}
else if (texLoader == null) {
Prehandle();
loadThread = null;
}
}
}
#endif
if (logEnabled) {
string _logs = logs.text;
Game.MainLogger.Enumerate((level, module, msg) => {
string color;
switch (level) {
case 0: color = "#888888"; break;
case 1: color = "#bbbbbb"; break;
case 2: color = "#0088ff"; break;
case 3: color = "#ffff00"; break;
case 4: color = "#ff0000"; break;
case 5: color = "#bb0000"; break;
default: color = "#ff00ff"; break;
}
_logs += string.Format(
"\r\n<color={1}bb><{2}> {3}</color>",
DateTime.UtcNow.ToString("s"), color, module, msg
);
});
logs.text = _logs.Substring(Mathf.Max(0, _logs.IndexOf('\n', Mathf.Max(0, _logs.Length - 4096))));
var sttext = string.Format(
"FPS: i{0:0} / s{1:0}\nSMem: {2:N0} / {3:N0}\nIMem: {4:N0} / {5:N0}",
1 / Time.deltaTime,
1 / Time.smoothDeltaTime,
#if UNITY_5_6_OR_NEWER
UnityEngine.Profiling.Profiler.GetMonoUsedSizeLong(),
UnityEngine.Profiling.Profiler.GetMonoHeapSizeLong(),
UnityEngine.Profiling.Profiler.GetTotalAllocatedMemoryLong(),
UnityEngine.Profiling.Profiler.GetTotalReservedMemoryLong()
#else
UnityEngine.Profiling.Profiler.GetMonoUsedSize(),
UnityEngine.Profiling.Profiler.GetMonoHeapSize(),
UnityEngine.Profiling.Profiler.GetTotalAllocatedMemory(),
UnityEngine.Profiling.Profiler.GetTotalReservedMemory()
#endif
);
if (judge != null) sttext += "\n== Scores ==\n" + judge.GetFullFormattedScoreString();
status.text = sttext;
}
else {
Game.MainLogger.Enumerate((level, module, msg) => { });
}
}
/*public void ReturnToConsole() {
Application.LoadLevel("Console");
}*/
private void ReturnToMenu() {
#if UNITY_EDITOR
Invoke(nameof(_returnToMenu), 4);
#else
_returnToMenu();
#endif
}
private void _returnToMenu() {
GameObject.Find("Master").GetComponent<Master>().ShowMenu();
GameObject.Destroy(gameObject);
#if UNITY_5_5_OR_NEWER
SceneManager.UnloadSceneAsync("Play");
#elif UNITY_5_3_OR_NEWER
SceneManager.UnloadScene("Play");
#endif
}
bool logEnabled = true;
public void ToggleLogs() {
logs.text = "";
status.text = "";
logEnabled = !logEnabled;
}
public void TogglePlay() {
if (started) Stop();
else {
if (loadThread == null) Play();
else Logger.Log("main", 2, "Load/MainThread", "The chart is currently loading");
}
}
void Play() {
disableGC = Settings.Default.DisableGC;
clippingDist = Settings.Default.BackwardClippingDistance;
renderDist = Settings.Default.RenderDistance;
renderStep = Settings.Default.RenderStep;
actualRenderStep = renderStep;
autoRenderStep = renderStep == 0;
soundOffset = Settings.Default.SoundOffset;
startOffset = Settings.Default.StartOffset;
sv = Settings.Default.ScrollVelocity;
firstFrame = true;
#if !NO_THREAD
texloaddone = false;
#endif
Game.AudioSession = Game.AudioSequencer.NewSession();
var hitPlane = new Plane(Vector3.forward, Vector3.zero);
var r0 = Camera.main.ViewportPointToRay(new Vector3(0, 0, 1));
float dist;
hitPlane.Raycast(r0, out dist);
var p0 = r0.GetPoint(dist);
var r1 = Camera.main.ViewportPointToRay(new Vector3(1, 1, 1));
hitPlane.Raycast(r1, out dist);
var p1 = r1.GetPoint(dist);
hitRect = new Rect(p0, p1 - p0);
screenSize = new Vector2(Screen.width, Screen.height);
frustumPlanes = GeometryUtility.CalculateFrustumPlanes(Camera.main);
FileInfo chartFile = new FileInfo(
Game.GameDataPath + "/charts/" + Settings.Default.LoadChart
);
FileInfo rulesetFile = new FileInfo(
Game.GameDataPath + "/rulesets/" + Settings.Default.LoadRuleset
);
FileInfo skinFile = new FileInfo(
Game.GameDataPath + "/skins/" + Settings.Default.LoadSkin
);
Logger.Log("main", 0, "Load/MainThread", "Loading textures...");
texloadtimer = new diag::Stopwatch();
texloadtimer.Start();
texs = new Dictionary<string, Texture2D>();
var flist = skinFile.Directory.GetFiles("*.png");
foreach (FileInfo f in flist) {
#if NO_THREAD
using (WWW w = new WWW("file:///" + f.FullName)) {
string name = StringUtils.TrimExt(f.Name);
while (!w.isDone);
texs.Add(name, w.texture);
}
#else
texLoadQueue.Enqueue(f.FullName);
#endif
}
#if NO_THREAD
texloadtimer.Stop();
Logger.LogFormat("main", 0, "Load/MainThread", "Textures loaded successfully ({0}ms)", texloadtimer.Elapsed.TotalMilliseconds);
Load(new LoadInfo(){
chartFile = chartFile,
rulesetFile = rulesetFile,
skinFile = skinFile,
});
Prehandle();
#else
loadThread = new Thread(new ParameterizedThreadStart(Load));
loadThread.Start(new LoadInfo(){
chartFile = chartFile,
rulesetFile = rulesetFile,
skinFile = skinFile,
});
#endif
}
void Prehandle() {
try {
diag::Stopwatch timer = new diag::Stopwatch();
timer.Reset(); timer.Start();
Logger.Log("main", 0, "Load/Prehandle", "Prehandling (iteration 3)");
foreach (var i in plists) i.Init(texs);
foreach (var t in texs) {
if (frames.ContainsKey(t.Key)) {
Logger.Log("main", 3, "Load/Prehandle", "Duplicated texture name: {0}", t.Key);
continue;
}
var f = new Cocos2dFrames.Frame(t.Value);
f.Init();
frames.Add(t.Key, f);
}
// etor.Context = new EvaluatorContext() { Reservations = cruleset.scores.Keys.ToList() };
// pskin.PreEval(etor);
//cs.BroadcastInit();
Logger.Log("main", 0, "Load/Prehandle", "Initializing states");
cbus.BroadcastInit();
Game.InputManager.Activate();
if (logEnabled) ToggleLogs();
Logger.Log("main", 0, "Load/Prehandle", "Cleaning up");
GC.Collect();
if (disableGC) GarbageCollector.GCMode = GarbageCollector.Mode.Disabled;
timer.Stop();
Logger.Log("main", 1, "Load/Prehandle", "Prehandling done ({0}ms)", timer.Elapsed.TotalMilliseconds);
Game.AudioSequencer.Playing = true;
Thread.Sleep((int)(Game.AudioClient.BufferPosition - Game.AudioClient.Position));
Game.InputManager.SyncTime(cbus.Time);
started = true;
// cs.ForwardByTime(startOffset);
// bus.ForwardByTime(startOffset);
}
catch (Exception ex) {
Game.LogException("Load/Prehandle", "An error occured while prehandling the data", ex);
Stop();
}
}
struct LoadInfo {
public FileInfo chartFile;
public FileInfo rulesetFile;
public FileInfo skinFile;
}
diag::Stopwatch texloadtimer = new diag::Stopwatch();
bool firstFrame;
#if !NO_THREAD
Thread loadThread = null;
diag::Stopwatch workerTimer;
bool texloaddone;
#endif
void Load(object _info) {
var info = (LoadInfo)_info;
try {
workerTimer = new diag::Stopwatch();
workerTimer.Start();
RMVPool.Prepare();
LoadChart(info);
workerTimer.Stop();
Logger.Log("main", 1, "Load/WorkerThread", "Worker thread done ({0}ms)", workerTimer.Elapsed.TotalMilliseconds);
}
catch (Exception ex) {
Game.LogException("Load/WorkerThread", "An error occured while loading the data", ex);
}
}
void LoadChart(LoadInfo info) {
DirectoryInfo dir = info.chartFile.Directory;
Logger.Log("main", 0, "Load/WorkerThread", "Loading chart: {0}", info.chartFile);
using (StreamReader reader = new StreamReader(info.chartFile.FullName, Encoding.UTF8)) {
chart = JsonConvert.DeserializeObject<Chart>(reader.ReadToEnd(), new JsonSerializerSettings() {
MissingMemberHandling = MissingMemberHandling.Error
});
if (chart.format != 1) throw new FormatException("Invalid chart file format version");
etor = new PdtEvaluator();
LoadRuleset(info.rulesetFile);
Logger.Log("main", 0, "Load/WorkerThread", "Applying ruleset (iteration 1)");
pruleset.PrePatch(chart);
Logger.Log("main", 0, "Load/WorkerThread", "Batching events");
var batcher = new EventBatcher(chart);
batcher.Forward();
// cruleset.PatchChart(batcher);
cbus = batcher.Batch();
Logger.Log("main", 0, "Load/WorkerThread", "Batched {0} event batches", cbus.events.Count);
judge = new Judge();
etor.ContextJudge = judge;
LoadSkin(info.skinFile);
cbus.AttachSystems(pskin, judge);
// handler = new ChartHandler(chart, dir);
// cs = new StampedState(chart);
/*var cph = new EventPrehandler(chart, chart, chart.Events);
foreach (var g in chart.groups) {
var gph = new EventPrehandler(chart, g, g.Events, cph);
foreach (var i in g.Children) {
new EventPrehandler(chart, i, i.Events, gph);
}
}
cph.Forward(ev => {
if (ev is Chart.Sound) {
Chart.Sound tev = (Chart.Sound)ev;
cph.Result.Add(new StampedEvent.PlaySound() {
Time = cph.Time/* - tev.offset* + soundOffset,
Event = tev
});
}
});*/
/*var ch = new ChartHandler(chart, dir);
cs = new StampedState(chart, cph.Result, cskin, cph.StampedEvent);
cs.AttachHandler(ch);
foreach (var gph in cph.Children) {
var gh = new GroupHandler((Chart.Group)gph.Container, ch);
var gs = new StampedState(chart, gph.Result, cskin, gph.StampedEvent, cs);
gs.AttachHandler(gh);
foreach (var tph in gph.Children) {
StampedEventHandler th;
if (tph.Container is Chart.Note) {
th = new NoteHandler(gh, tph.StampedEvent);
}
else {
th = new TrackHandler(gh, (Chart.Track)tph.Container);
}
StampedState ts;
ts = new StampedState(chart, tph.Result, cskin, tph.StampedEvent, gs);
ts.AttachHandler(th);
}
}*/
Logger.Log("main", 0, "Load/WorkerThread", "Attaching handlers");
var ch = new ChartHandler(chart, dir);
cbus.RootState.AttachHandler(ch);
foreach (var gs in cbus.RootState.Children) {
var gh = new GroupHandler((Chart.Group)gs.Key, ch);
gs.Value.AttachHandler(gh);
foreach (var ts in gs.Value.Children) {
ContainerHandler th;
if (ts.Key is Chart.Note) {
th = new NoteHandler(gh, (Chart.Note)ts.Key, judge);
}
else {
th = new TrackHandler(gh, (Chart.Track)ts.Key);
}
ts.Value.AttachHandler(th);
}
}
Logger.Log("main", 0, "Load/WorkerThread", "Prehandling (iteration 1)");
cbus.Clone(16).Forward();
Logger.Log("main", 0, "Load/WorkerThread", "Patching events");
cbus.DoPatch();
Logger.Log("main", 0, "Load/WorkerThread", "Prehandling (iteration 2)");
cbus.Clone(17).Forward();
Logger.Log("main", 0, "Load/WorkerThread", "Cloning states (type 1)");
bbus = cbus.Clone(1, -clippingDist);
Logger.Log("main", 0, "Load/WorkerThread", "Cloning states (type 2)");
tbus = bbus.Clone(2);
Logger.Log("main", 0, "Load/WorkerThread", "Cloning states (type 3)");
nbus = bbus.Clone(3);
}
}
void LoadRuleset(FileInfo file) {
DirectoryInfo dir = file.Directory;
Logger.Log("main", 0, "Load/WorkerThread", "Loading ruleset: {0}", file);
using (StreamReader reader = new StreamReader(file.FullName, Encoding.UTF8)) {
ruleset = JsonConvert.DeserializeObject<Ruleset>(reader.ReadToEnd(), new JsonSerializerSettings() {
MissingMemberHandling = MissingMemberHandling.Error
});
if (ruleset.format != 1) throw new FormatException("Invalid ruleset file version");
ruleset.LoadPdt(dir);
pruleset = ruleset.Root;
}
}
void LoadSkin(FileInfo file) {
DirectoryInfo dir = file.Directory;
Logger.Log("main", 0, "Load/WorkerThread", "Loading skin: {0}", file);
using (StreamReader reader = new StreamReader(file.FullName, Encoding.UTF8)) {
skin = JsonConvert.DeserializeObject<Skin>(reader.ReadToEnd(), new JsonSerializerSettings() {
MissingMemberHandling = MissingMemberHandling.Error
});
if (skin.format != 1) throw new FormatException("Invalid skin file version");
skin.LoadPdt(dir);
pskin = skin.Root;
pskin.Optimize(etor);
}
plists = new List<Cocos2dFrames>();
frames = new Dictionary<string, Cocos2dFrames.Frame>();
foreach (FileInfo f in file.Directory.GetFiles("*.plist")) {
var pobj = PlistConvert.Deserialize<Cocos2dFrames>(f.FullName);
plists.Add(pobj);
foreach (var i in pobj.frames)
frames.Add(StringUtils.TrimExt(i.Key), i.Value);
}
}
public void Stop() {
try {
Logger.Log("main", 1, "Game", "Stopping");
chart = null;
Game.AudioSession = Game.AudioSequencer.NewSession();
if (cbus != null) cbus.Dispose();
if (bbus != null) bbus.Dispose();
if (tbus != null) tbus.Dispose();
if (nbus != null) nbus.Dispose();
//cs.Dispose();
Game.InputManager.Deactivate();
foreach (var t in texs) Texture.Destroy(t.Value);
Logger.Log("main", 1, "Game", "Stopped");
}
catch (Exception ex) {
if (!logEnabled) ToggleLogs();
Game.LogException("Game", "An error occured while stopping", ex);
}
finally {
if (started) {
if (disableGC) GarbageCollector.GCMode = GarbageCollector.Mode.Enabled;
GC.Collect();
started = false;
}
}
Game.NetworkTaskWorker.ResumeBackgroundTasks();
#if BUILD
ReturnToMenu();
#endif
}
/*public void ShowSettings() {
var editor = GameObject.Instantiate<GameObject>(UnityEngine.Resources.Load<GameObject>("Common/PropertyEditor")).GetComponent<PropertyEditor>();
editor.Callback = () => {
Settings.Default.Save();
OnSettingsUpdate();
};
editor.TargetObject = Settings.Default;
}*/
void OnSettingsUpdate() {
Application.targetFrameRate = Settings.Default.TargetFrameRate;
QualitySettings.vSyncCount = Settings.Default.VSync ? 1 : 0;
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 6c42a45f576ad8249b2ed00675127e76
timeCreated: 1617585799
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,188 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Reflection;
using System.Text.RegularExpressions;
using UnityEngine;
using Cryville.Common;
using Cryville.Common.Plist;
namespace Cryville.Crtr {
[BinderAttribute(typeof(Cocos2dFramesBinder))]
public class Cocos2dFrames {
public Metadata metadata;
public class Metadata {
public int format;
public Vector2 size;
public string textureFileName;
}
public Dictionary<string, Frame> frames;
public class Frame {
Rect _frame;
public Rect frame {
get { return _frame; }
set { _frame = value; }
}
public Rect textureRect {
get { return _frame; }
set { _frame = value; }
}
public Vector2 offset;
bool _rotated = false;
public bool rotated {
get { return _rotated; }
set { _rotated = value; }
}
public bool textureRotated {
get { return _rotated; }
set { _rotated = value; }
}
public Rect sourceColorRect;
public Vector2 sourceSize;
private Rect _uv;
private Vector2[] cuv;
public Rect UV {
get {
return _uv;
}
private set {
_uv = value;
float x0 = Mathf.Min(_uv.xMin, _uv.xMax);
float x1 = Mathf.Max(_uv.xMin, _uv.xMax);
float y0 = Mathf.Min(_uv.yMin, _uv.yMax);
float y1 = Mathf.Max(_uv.yMin, _uv.yMax);
if (_rotated) cuv = new Vector2[]{
new Vector2(x0, y1),
new Vector2(x1, y0),
new Vector2(x0, y0),
new Vector2(x1, y1),
};
else cuv = new Vector2[]{
new Vector2(x0, y0),
new Vector2(x1, y1),
new Vector2(x1, y0),
new Vector2(x0, y1),
};
}
}
public Vector2 GetUV(Vector2 uv) {
return GetUV(uv.x, uv.y);
}
public Vector2 GetUV(float u, float v) {
Vector2 uv00 = cuv[0], uv11 = cuv[1],
uv10 = cuv[2], uv01 = cuv[3];
return (1 - u - v) * uv00
+ u * uv10
+ v * uv01
+ u * v * (uv00 + uv11 - uv10 - uv01);
}
public Texture2D Texture {
get;
private set;
}
public Vector2 Size {
get {
return new Vector2(Texture.width, Texture.height);
}
}
public void Init() {
if (Texture == null)
throw new InvalidOperationException(); // TODO
_frame = new Rect(Vector2.zero, Size);
var w = _frame.width;
var h = _frame.height;
float x = _frame.x / w;
float y = 1 - _frame.y / h;
float tw = (_rotated ? _frame.height : _frame.width) / w;
float th = (_rotated ? _frame.width : _frame.height) / h;
if (_rotated) UV = new Rect(x, y, tw, -th);
else UV = new Rect(x, y, tw, -th);
}
public void Init(int w, int h, Texture2D _base) {
if (Texture != null)
throw new InvalidOperationException(); // TODO
Texture = _base;
float x = _frame.x / w;
float y = 1 - _frame.y / h;
float tw = (_rotated ? _frame.height : _frame.width) / w;
float th = (_rotated ? _frame.width : _frame.height) / h;
if (_rotated) UV = new Rect(x, y, tw, -th);
else UV = new Rect(x, y, tw, -th);
}
public Frame() { }
public Frame(Texture2D tex) {
Texture = tex;
}
}
Texture2D _base;
public void Init(Dictionary<string, Texture2D> texs) {
_base = texs[StringUtils.TrimExt(metadata.textureFileName)];
var w = (int)metadata.size.x;
var h = (int)metadata.size.y;
if (w == 0 || h == 0) {
w = _base.width;
h = _base.height;
}
foreach (var f in frames) {
f.Value.Init(w, h, _base);
}
}
}
/*public class RectConverter : TypeConverter {
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) {
if (sourceType == typeof(string))
return true;
return base.CanConvertFrom(context, sourceType);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) {
return base.ConvertFrom(context, culture, value);
}
}*/
public class Cocos2dFramesBinder : EmptyBinder {
public override object ChangeType(object value, Type type, CultureInfo culture) {
if (value is string) {
var str = (string)value;
if (type == typeof(Rect)) {
var m = Regex.Match(str, @"^{({.*?}),({.*?})}$");
var p = (Vector2)ChangeType(m.Groups[1].Value, typeof(Vector2), culture);
var s = (Vector2)ChangeType(m.Groups[2].Value, typeof(Vector2), culture);
return new Rect(p, s);
}
else if (type == typeof(Vector2)) {
var m = Regex.Match(str, @"^{(.*?),(.*?)}$");
var w = float.Parse(m.Groups[1].Value);
var h = float.Parse(m.Groups[2].Value);
return new Vector2(w, h);
}
}
else if (typeof(IDictionary).IsAssignableFrom(value.GetType())) {
var dict = (IDictionary)value;
if (type == typeof(Rect)) {
var x = float.Parse((string)dict["x"]);
var y = float.Parse((string)dict["y"]);
var w = float.Parse((string)dict["w"]);
var h = float.Parse((string)dict["h"]);
return new Rect(x, y, w, h);
}
else if (type == typeof(Vector2)) {
var w = float.Parse((string)dict["w"]);
var h = float.Parse((string)dict["h"]);
return new Vector2(w, h);
}
}
return base.ChangeType(value, type, culture);
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 2dede1bb66852cb4a911916107d6581f
timeCreated: 1608801352
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 7ccb6283af616de43881e90749df8f19
folderAsset: yes
timeCreated: 1609142378
licenseType: Free
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,291 @@
using Cryville.Common.Buffers;
using Cryville.Common.Pdt;
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Cryville.Crtr.Components {
public abstract class SectionalGameObject : SkinComponent {
protected bool headGenerated;
protected Vector3 prevpt;
protected int vertCount = 0;
protected MeshWrapper mesh = new MeshWrapper();
protected override void OnDestroy() {
mesh.Destroy();
}
public override void Init() {
Reset();
}
public void AppendPoint(Vector3 p) {
AppendPoint(p, Quaternion.identity);
}
public void AppendPoint(Vector3 p, Quaternion r) {
AppendPointInternal(p, r);
// if (!headGenerated) Logger.Log("main", 0, "Skin/Polysec", "{0}", r);
headGenerated = true;
prevpt = p;
vertCount++;
}
protected abstract void AppendPointInternal(Vector3 wp, Quaternion r);
public abstract void Seal();
public virtual void Reset() {
vertCount = 0;
headGenerated = false;
}
}
public class PolygonSGO : SectionalGameObject {
static readonly SimpleObjectPool<List<Vector3>> _ptPool = new SimpleObjectPool<List<Vector3>>(1024);
static readonly SimpleObjectPool<List<float>> _lPool = new SimpleObjectPool<List<float>>(1024);
static readonly ListPool<int> _indexPool = new ListPool<int>();
static readonly ListPool<Vector3> _vertPool = new ListPool<Vector3>();
static readonly ListPool<Vector2> _uvPool = new ListPool<Vector2>();
static readonly ArrayPool<Vector2> _shapePool = new ArrayPool<Vector2>(0x100, 0x10000);
public PolygonSGO()
: base() {
/*
SubmitProperty("head", new Property(typeof(string), () => head.frame, v => head.frame = (string)v));
SubmitProperty("body", new Property(typeof(string), () => body.frame, v => body.frame = (string)v));
SubmitProperty("tail", new Property(typeof(string), () => tail.frame, v => tail.frame = (string)v));
SubmitProperty("transparent", new Property(typeof(bool), () => transparent, v => transparent = (bool)v));
SubmitProperty("shape", new Property(typeof(Vector2[]), () => _shape, v => _shape = (Vector2[])v));
*/
SubmitProperty("head", new PropOp.String(v => head.FrameName = v));
SubmitProperty("body", new PropOp.String(v => body.FrameName = v));
SubmitProperty("tail", new PropOp.String(v => tail.FrameName = v));
SubmitProperty("transparent", new PropOp.Boolean(v => transparent = v));
SubmitProperty("shape", new op_set_shape(this));
}
#pragma warning disable IDE1006
public class op_set_shape : PdtOperator {
readonly PolygonSGO _self;
public op_set_shape(PolygonSGO self) : base(1) {
_self = self;
}
protected unsafe override void Execute() {
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];
}
}
}
#pragma warning restore IDE1006
int _shapeLength = 0;
Vector2[] _shape = null;
float GetWidth() {
float r = 0;
for (int i = 1; i < _shapeLength; i++) {
r += (_shape[i] - _shape[i-1]).magnitude;
}
return r;
}
public SpriteInfo head = new SpriteInfo();
public SpriteInfo body = new SpriteInfo();
public SpriteInfo tail = new SpriteInfo();
public bool transparent;
List<Vector3> vertices;
List<float> lengths;
float sumLength = 0;
public override void Init() {
base.Init();
head.Load();
body.Load();
tail.Load();
mesh.Init(transform, transparent);
List<Material> materials = new List<Material>();
if (head.FrameName != null) AddMat(materials, head.FrameName);
if (body.FrameName != null) AddMat(materials, body.FrameName);
if (tail.FrameName != null) AddMat(materials, tail.FrameName);
mesh.Renderer.materials = materials.ToArray();
}
void AddMat(List<Material> list, string frame) {
var mat = mesh.NewMaterial;
mat.mainTexture = ChartPlayer.frames[frame].Texture;
list.Add(mat);
}
protected override void OnDestroy() {
base.OnDestroy();
Reset();
foreach (var m in mesh.Renderer.materials) Material.Destroy(m);
if (_shape != null) _shapePool.Return(_shape);
if (vertices != null) {
_ptPool.Return(vertices);
_lPool.Return(lengths);
}
}
// Vector3 prevp = Vector3.zero;
protected override void AppendPointInternal(Vector3 p, Quaternion r) {
if (vertices == null) {
vertices = _ptPool.Rent();
lengths = _lPool.Rent();
}
/*
r = new Vector3(0, 0, 0);
Quaternion rotq = Quaternion.Euler(r);
p = prevp + rotq * (p - prevpt);
prevp = p;*/
for (int i = 0; i < _shapeLength; i++) {
Vector2 sp = r * _shape[i];
vertices.Add(p + (Vector3)sp);
// uv.Add(new Vector2(i / (shape.Length - 1), vertCount));
}
if (headGenerated) {
float len = (p - prevpt).magnitude;
lengths.Add(len);
sumLength += len;
}
}
List<Vector3> verts;
List<Vector2> uvs;
List<int> trih = null, trib = null, trit = null;
public override void Seal() {
if (vertCount <= 1 || sumLength == 0) return;
int vcpsec = _shapeLength; // Vertex Count Per Section
float width = GetWidth();
float headLength = 0;
if (head.FrameName != null) headLength = width / head.Ratio;
float tailLength = 0;
if (tail.FrameName != null) tailLength = width / tail.Ratio;
float endLength = headLength + tailLength;
if (sumLength <= endLength) {
// The total length of the two ends is longer than the whole mesh, squeeze the two ends
float ratio = sumLength / endLength;
headLength *= ratio;
tailLength *= ratio;
}
// Find the vertex counts needed for the three parts from the head
float l0 = 0;
int hvc = 0;
for (; l0 < headLength && hvc < lengths.Count; hvc++)
l0 += lengths[hvc];
int bvc = 0;
for (; l0 < sumLength - tailLength && hvc + bvc < lengths.Count; bvc++)
l0 += lengths[hvc + bvc];
int tvc = lengths.Count - hvc - bvc + 1;
if (hvc > 0) {
hvc++;
bvc++;
}
bvc++;
int vc = hvc + bvc + tvc;
verts = _vertPool.Rent(vc * vcpsec);
uvs = _uvPool.Rent(vc * vcpsec);
int i = 0; int t = 0; float l = 0; int m = 0;
if (head.FrameName != null) { m++; GenerateMeshTo(verts, uvs, out trih, head, ref i, ref t, ref l, 0, headLength, vcpsec, hvc); }
if (body.FrameName != null) { m++; GenerateMeshTo(verts, uvs, out trib, body, ref i, ref t, ref l, headLength, sumLength - tailLength, vcpsec, hvc + bvc); }
if (tail.FrameName != null) { m++; GenerateMeshTo(verts, uvs, out trit, tail, ref i, ref t, ref l, sumLength - tailLength, sumLength, vcpsec, vc); }
mesh.Mesh.subMeshCount = m;
m = 0;
mesh.Mesh.SetVertices(verts);
mesh.Mesh.SetUVs(0, uvs);
if (head.FrameName != null) mesh.Mesh.SetTriangles(trih, m++);
if (body.FrameName != null) mesh.Mesh.SetTriangles(trib, m++);
if (tail.FrameName != null) mesh.Mesh.SetTriangles(trit, m++);
mesh.Mesh.RecalculateNormals();
_vertPool.Return(verts); verts = null;
_uvPool.Return(uvs); uvs = null;
if (trih != null) { _indexPool.Return(trih); trih = null; }
if (trib != null) { _indexPool.Return(trib); trib = null; }
if (trit != null) { _indexPool.Return(trit); trit = null; }
}
void GenerateMeshTo(List<Vector3> verts, List<Vector2> uvs, out List<int> tris, SpriteInfo info, ref int i, ref int t, ref float l, float startl, float endl, int vcpsec, int vend) {
if (i >= lengths.Count) {
tris = _indexPool.Rent(0);
return;
}
int t0 = t;
var frame = info.Frame;
if (startl != 0) {
float pl2 = l - lengths[i - 1];
float fr2 = (startl - pl2) / (l - pl2);
for (int j = 0; j < vcpsec; j++, t++) {
verts[t] =
vertices[vcpsec*(i-1)+j] * (1-fr2)
+ vertices[vcpsec*i+j] * fr2;
var u = j / (vcpsec - 1);
if (frame != null) uvs[t] = frame.GetUV(u, 0);
}
}
for (; t / vcpsec < vend - 1; i++) {
var v = (l - startl) / (endl - startl);
for (int j = 0; j < vcpsec; j++, t++) {
verts[t] = vertices[vcpsec*i+j];
var u = j / (vcpsec - 1);
if (frame != null) uvs[t] = frame.GetUV(u, v);
}
l += lengths[i];
}
float pl = l - lengths[i - 1];
float fr = (endl - pl) / (l - pl);
for (int j = 0; j < vcpsec; j++, t++) {
verts[t] =
vertices[vcpsec*(i-1)+j] * (1-fr)
+ vertices[vcpsec*i+j] * fr;
var u = j / (vcpsec - 1);
if (frame != null) uvs[t] = frame.GetUV(u, 1);
}
tris = _indexPool.Rent((vend - t0 / vcpsec - 1) * (vcpsec - 1) * 6);
int i3 = 0;
for (int i1 = t0 + vcpsec + 1; i1 < t; i1++) {
if (i1 % vcpsec == 0) continue;
int i2 = i1 - vcpsec;
tris[i3++] = i1 - 1;
tris[i3++] = i2;
tris[i3++] = i2 - 1;
tris[i3++] = i1 - 1;
tris[i3++] = i1;
tris[i3++] = i2;
}
}
public override void Reset() {
base.Reset();
if (mesh.Initialized) mesh.Mesh.Clear();
if (vertices != null) {
vertices.Clear();
lengths.Clear();
}
sumLength = 0;
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 5f2666d577419bd43aec55ad614a43f4
timeCreated: 1596633346
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,76 @@
using Cryville.Common.Pdt;
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Cryville.Crtr.Components {
public abstract class SkinComponent : MonoBehaviour {
#if false
/// <summary>
/// The properties of the component.
/// </summary>
[Obsolete]
public Dictionary<string, Property> Properties { get; private set; }
/// <summary>
/// Submits a property.
/// </summary>
/// <param name="name">The name of the property.</param>
/// <param name="property">The property itself.</param>
[Obsolete]
protected void SubmitProperty(string name, Property property) {
Properties.Add(name, property);
}
/// <summary>
/// The property of a skin component.
/// </summary>
[Obsolete]
public struct Property {
/// <summary>
/// The type of the property.
/// </summary>
public readonly Type Type;
/// <summary>
/// The callback that gets the property value.
/// </summary>
public readonly Func<object> Get;
/// <summary>
/// The callback that sets the property value.
/// </summary>
public readonly Action<object> Set;
/// <summary>
/// Creates a property.
/// </summary>
/// <param name="type">The type of the property.</param>
/// <param name="get">The callback that gets the property value.</param>
/// <param name="set">The callback that sets the property value.</param>
public Property(Type type, Func<object> get, Action<object> set) {
Type = type; Get = get; Set = set;
}
}
#endif
/// <summary>
/// The property operators of the component.
/// </summary>
public Dictionary<string, PdtOperator> PropOps { get; private set; }
/// <summary>
/// Submits a property.
/// </summary>
/// <param name="name">The name of the property.</param>
/// <param name="property">The property operator.</param>
protected void SubmitProperty(string name, PdtOperator property) {
PropOps.Add(name, property);
}
/// <summary>
/// Create a skin component
/// </summary>
protected SkinComponent() {
// Properties = new Dictionary<string, Property>();
PropOps = new Dictionary<string, PdtOperator>();
}
public virtual void Init() { }
protected abstract void OnDestroy();
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: a54d8e3558a89f8499fc049afd84e959
timeCreated: 1623576806
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,155 @@
using Cryville.Common.Pdt;
using System;
using System.Collections;
using UnityEngine;
namespace Cryville.Crtr.Components {
public abstract class SpriteBase : SkinComponent {
public SpriteBase()
: base() {
/*
SubmitProperty("bound", new Property(typeof(BoundInfo), null, v => Bound = (BoundInfo)v));
SubmitProperty("transparent", new Property(typeof(bool), () => transparent, v => transparent = (bool)v));
SubmitProperty("pivot", new Property(typeof(Vector2), () => Pivot, v => Pivot = (Vector2)v));
SubmitProperty("scale", new Property(typeof(Vector2), () => Scale, v => Scale = (Vector2)v));
SubmitProperty("ui", new Property(typeof(bool), () => UI, v => UI = (bool)v));
SubmitProperty("zindex", new Property(typeof(short), () => ZIndex, v => ZIndex = (short)v));
*/
SubmitProperty("bound", new op_set_bound(this));
SubmitProperty("transparent", new PropOp.Boolean(v => transparent = v));
SubmitProperty("pivot", new PropOp.Vector2(v => Pivot = v));
SubmitProperty("scale", new PropOp.Vector2(v => Scale = v));
SubmitProperty("ui", new PropOp.Boolean(v => UI = v));
SubmitProperty("zindex", new PropOp.Integer(v => ZIndex = (short)v));
}
#pragma warning disable IDE1006
class op_set_bound : PdtOperator {
readonly SpriteBase _self;
public op_set_bound(SpriteBase self) : base(2) {
_self = self;
}
protected unsafe override void Execute() {
_self.SetBound(
*(Vector2*)GetOperand(0).TrustedAsOfLength(sizeof(Vector2)),
*(Vector3*)GetOperand(1).TrustedAsOfLength(sizeof(Vector3))
);
}
}
#pragma warning restore IDE1006
protected MeshWrapper mesh = new MeshWrapper();
protected override void OnDestroy() {
mesh.Destroy();
}
Vector2 _scale = Vector2.one;
public Vector2 Scale {
get { return _scale; }
set {
_scale = value;
UpdateScale();
}
}
protected virtual void UpdateScale() {
if (!mesh.Initialized) return;
var s = BaseScale;
var ss = new Vector3(_scale.x, 1, _scale.y);
s.Scale(ss);
mesh.MeshTransform.localScale = s;
OnPivotUpdate();
}
protected abstract Vector3 BaseScale {
get;
}
protected virtual Vector3 BaseSize {
get { return Vector3.one; }
}
Vector2 _pivot;
public Vector2 Pivot {
get { return _pivot; }
set {
_pivot = value;
OnPivotUpdate();
}
}
protected void OnPivotUpdate() {
if (!mesh.Initialized) return;
var r = new Vector3(_pivot.x - BasePivot.x, 0, _pivot.y - BasePivot.y);
r.Scale(mesh.MeshTransform.localScale);
r.Scale(BaseSize);
mesh.MeshTransform.localPosition = -r;
}
protected virtual Vector2 BasePivot {
get { return Vector2.zero; }
}
#if false
[Obsolete]
public struct BoundInfo : IConstructable {
public Vector2 Pivot;
public Vector3 Position;
public void Load(object data, IEvaluator etor) {
var d = (IList)data;
Pivot = (Vector2)etor.Cast(typeof(Vector2), d[0]);
Position = (Vector3)etor.Cast(typeof(Vector3), d[1]);
}
}
[Obsolete]
public BoundInfo Bound {
set {
var r = Quaternion.Inverse(transform.rotation);
var da = value.Pivot - Pivot;
var dp = r * (value.Position - transform.localPosition);
if (da.x != 0) _scale.x = dp.x / da.x;
if (da.y != 0) _scale.y = dp.z / da.y;
}
}
#endif
public void SetBound(Vector2 piv, Vector3 pos) {
var r = Quaternion.Inverse(transform.rotation);
var da = piv - Pivot;
var dp = r * (pos - transform.localPosition);
if (da.x != 0) _scale.x = dp.x / da.x;
if (da.y != 0) _scale.y = dp.z / da.y;
}
short _zindex;
public short ZIndex {
get {
return _zindex;
}
set {
_zindex = value;
UpdateZIndex();
}
}
protected void UpdateZIndex() {
if (!mesh.Initialized) return;
mesh.Renderer.sortingOrder = _zindex;
}
static readonly Quaternion uirot
= Quaternion.Euler(new Vector3(-90, 0, 0));
bool _ui;
public bool UI {
get { return _ui; }
set {
_ui = value;
if (_ui) transform.localRotation = uirot;
}
}
public bool transparent = false;
protected void InternalInit(string meshName = "quad") {
mesh.Init(transform, transparent);
mesh.Mesh = GenericResources.Meshes[meshName];
UpdateScale();
UpdateZIndex();
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 248ab93b20a0ac9439afaee32357ed5c
timeCreated: 1614907140
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,156 @@
using System;
using UnityEngine;
using Logger = Cryville.Common.Logger;
namespace Cryville.Crtr.Components {
public class SpriteInfo {
public string FrameName;
public Cocos2dFrames.Frame Frame {
get;
private set;
}
public Rect Rect {
get { return Frame.frame; }
}
/// <summary>
/// The ratio of width divided by height.
/// </summary>
public float Ratio {
get {
return Rect.width / Rect.height;
}
}
public void Load() {
if (FrameName != null) {
if (ChartPlayer.frames.ContainsKey(FrameName)) {
Frame = ChartPlayer.frames[FrameName];
}
else {
Logger.Log("main", 4, "Skin", "Texture {0} not found", FrameName);
}
}
}
}
public class SpritePlane : SpriteBase {
public SpritePlane()
: base() {
/*
SubmitProperty("frame", new Property(typeof(string), () => Frame, v => Frame = (string)v));
SubmitProperty("fit", new Property(typeof(FitMode), () => Fit, v => Fit = (FitMode)v));
SubmitProperty("opacity", new Property(typeof(float), () => Opacity, v => Opacity = (float)v));
*/
SubmitProperty("frame", new PropOp.String(v => Frame = v));
SubmitProperty("fit", new PropOp.Enum<FitMode>(v => Fit = v));
SubmitProperty("opacity", new PropOp.Float(v => Opacity = v));
}
static Vector2[] _origuv;
protected static Vector2[] OriginalUV {
get {
if (_origuv == null) {
var m = GenericResources.Meshes["quad"];
Vector2[] uv = new Vector2[m.vertices.Length];
for (int i = 0; i < uv.Length; i++) {
uv[i] = new Vector2(
m.vertices[i].x == 0.5 ? 1 : 0,
m.vertices[i].z == 0.5 ? 1 : 0
);
}
_origuv = uv;
}
return _origuv;
}
}
protected SpriteInfo frameInfo = new SpriteInfo();
public string Frame {
get { return frameInfo.FrameName; }
set {
frameInfo.FrameName = value;
OnFrameUpdate();
}
}
protected void OnFrameUpdate() {
if (!mesh.Initialized) return;
if (frameInfo.FrameName == null) {
mesh.Renderer.enabled = false;
return;
}
mesh.Renderer.enabled = true;
frameInfo.Load();
if (frameInfo.Frame != null)
mesh.Renderer.material.mainTexture = frameInfo.Frame.Texture;
else
Logger.Log("main", 4, "Skin", "Unable to load texture {0}", frameInfo.FrameName);
UpdateUV();
UpdateScale();
UpdateZIndex();
}
protected virtual void UpdateUV() {
if (frameInfo.Frame == null) {
Logger.Log("main", 4, "Skin", "Unable to load texture {0}", frameInfo.FrameName);
return;
}
Vector2[] muv = OriginalUV;
Vector2[] uv = new Vector2[muv.Length];
for (int i = 0; i < uv.Length; i++) {
uv[i] = frameInfo.Frame.GetUV(muv[i]);
}
mesh.Mesh.uv = uv;
}
float _opacity = 1;
public float Opacity {
get { return _opacity; }
set {
_opacity = value;
UpdateOpacity();
}
}
void UpdateOpacity() {
if (!mesh.Initialized) return;
var c = mesh.Renderer.material.color;
c.a = _opacity;
mesh.Renderer.material.color = c;
}
private FitMode m_fit = FitMode.height;
public FitMode Fit {
get { return m_fit; }
set {
m_fit = value;
if (m_fit != FitMode.none && Scale.x != Scale.y) m_fit = FitMode.none;
}
}
public enum FitMode {
none, width, height
}
protected override void UpdateScale() {
if (frameInfo.Frame == null) return;
base.UpdateScale();
if (m_fit != FitMode.none && Scale.x != Scale.y) m_fit = FitMode.none;
}
protected override Vector3 BaseScale {
get {
switch (m_fit) {
case FitMode.none: return Vector3.one;
case FitMode.width: return new Vector3(1, 1, 1 / frameInfo.Ratio);
case FitMode.height: return new Vector3(frameInfo.Ratio, 1, 1);
default: throw new NotSupportedException("Unsupported fit mode");
}
}
}
public override void Init() {
frameInfo.Load();
InternalInit();
OnFrameUpdate();
UpdateOpacity();
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 76053cf6896b7304fb0ec26546de1ace
timeCreated: 1609142271
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,39 @@
using System.Collections.Generic;
using UnityEngine;
namespace Cryville.Crtr.Components {
public class SpriteRect : SpriteBase {
public SpriteRect()
: base() {
/*
SubmitProperty("color", new Property(typeof(Color), () => Color, v => Color = (Color)v));
*/
SubmitProperty("color", new PropOp.Color(v => Color = v));
transparent = true;
}
Color _color;
public Color Color {
get { return _color; }
set {
_color = value;
OnColorUpdate();
}
}
void OnColorUpdate() {
if (!mesh.Initialized) return;
mesh.Renderer.material.SetColor("_Color", _color);
}
protected override Vector3 BaseScale {
get { return Vector3.one; }
}
public override void Init() {
InternalInit();
OnColorUpdate();
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: a902fb77646e6eb4eb96d8ac86b3ee0e
timeCreated: 1614821846
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,93 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Cryville.Crtr.Components {
public class SpriteScale3 : SpritePlane {
public SpriteScale3()
: base() {
/*
SubmitProperty("border", new Property(typeof(Vector2), () => Border, v => Border = (Vector2)v));
*/
SubmitProperty("border", new PropOp.Vector2(v => Border = v));
}
readonly static Dictionary<float, int> uvrefl
= new Dictionary<float, int>() {
{-0.5f, 0}, {-0.4f, 1}, {0.4f, 2}, {0.5f, 3},
};
static Vector2[] _origuv;
protected new static Vector2[] OriginalUV {
get {
if (_origuv == null) {
var m = GenericResources.Meshes["quad_scale3h"];
Vector2[] uv = new Vector2[m.vertices.Length];
for (int i = 0; i < uv.Length; i++) {
uv[i] = new Vector2(
uvrefl[m.vertices[i].x],
uvrefl[m.vertices[i].z]
);
}
_origuv = uv;
}
return _origuv;
}
}
Vector2 _border = new Vector2(0, 1);
public Vector2 Border {
get { return _border; }
set {
_border = value;
UpdateScale();
}
}
protected override void UpdateScale() {
base.UpdateScale();
if (!mesh.Initialized) return;
UpdateUV();
}
protected override void UpdateUV() {
Vector2[] muv = OriginalUV;
Vector2[] uv = new Vector2[muv.Length];
var or = frameInfo.Ratio;
var sr = Scale.x / Scale.y;
var b = new Vector2(
(or / sr) * _border.x,
1 - (or / sr) * (1 - _border.y)
);
Vector3[] vert = mesh.Mesh.vertices;
for (int i = 0; i < muv.Length; i++) {
float x; float bx;
switch ((int)muv[i].x) {
case 0: x = 0; bx = 0; break;
case 1: x = _border.x; bx = b.x; break;
case 2: x = _border.y; bx = b.y; break;
case 3: x = 1; bx = 1; break;
default: throw new Exception();
}
float y;
switch ((int)muv[i].y) {
case 0: y = 0; break;
case 3: y = 1; break;
default: throw new Exception();
}
uv[i] = frameInfo.Frame.GetUV(x, y);
bx -= 0.5f; y -= 0.5f;
vert[i] = new Vector3(bx, 0, y);
}
mesh.Mesh.uv = uv;
mesh.Mesh.vertices = vert;
}
public override void Init() {
frameInfo.Load();
InternalInit("quad_scale3h");
OnFrameUpdate();
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 31dc4a947b5c7c645aa8fc2b82b4fba7
timeCreated: 1615333501
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,201 @@
using Cryville.Common.Pdt;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
namespace Cryville.Crtr.Components {
public class SpriteText : SpriteBase {
public SpriteText() {
/*
SubmitProperty("frames", new Property(typeof(TextFrames), () => Frames, v => Frames = (TextFrames)v));
SubmitProperty("value", new Property(typeof(string), () => Value, v => Value = (string)v));
SubmitProperty("size", new Property(typeof(float), () => Size, v => Size = (float)v));
SubmitProperty("spacing", new Property(typeof(float), () => Spacing, v => Spacing = (float)v));
SubmitProperty("opacity", new Property(typeof(float), () => Opacity, v => Opacity = (float)v));
*/
SubmitProperty("frames", new op_set_frames(this));
SubmitProperty("value", new PropOp.String(v => Value = v));
SubmitProperty("size", new PropOp.Float(v => Size = v));
SubmitProperty("spacing", new PropOp.Float(v => Spacing = v));
SubmitProperty("opacity", new PropOp.Float(v => Opacity = v));
}
#pragma warning disable IDE1006
class op_set_frames : PdtOperator {
readonly SpriteText _self;
public op_set_frames(SpriteText self) : base(2) {
_self = self;
}
protected unsafe override void Execute() {
var keys = GetOperand(0).AsString();
var values = GetOperand(1);
int arrtype; int len;
values.GetArraySuffix(out arrtype, out len);
var result = new Dictionary<char, SpriteInfo>(len);
int o = 0;
for (int i = 0; i < len; i++) {
string v = values.AsString(o);
o += v.Length * sizeof(char) + sizeof(int);
result.Add(keys[i], new SpriteInfo { FrameName = v });
}
_self.Frames = new TextFrames { Frames = result };
}
}
#pragma warning restore IDE1006
protected override void OnDestroy() {
base.OnDestroy();
foreach (var m in meshes) m.Value.Destroy();
}
readonly Dictionary<Texture2D, MeshWrapper> meshes = new Dictionary<Texture2D, MeshWrapper>();
public struct TextFrames /*: IConstructable*/ {
public Dictionary<char, SpriteInfo> Frames;
/*public void Load(object data, IEvaluator etor) {
var d = (IList)data;
var keys = (string)d[0];
var values = (List<object>)d[1];
Frames = new Dictionary<char, SpriteInfo>(keys.Length);
for (int i = 0; i < keys.Length; i++)
Frames.Add(keys[i], new SpriteInfo() { FrameName = (string)values[i] });
}*/
}
TextFrames m_frames;
public TextFrames Frames {
get { return m_frames; }
set { m_frames = value; UpdateFrames(); UpdateScale(); }
}
public string m_value;
public string Value {
get { return m_value; }
set {
if (m_value == value) return;
m_value = value; UpdateScale();
}
}
public float m_size;
public float Size {
get { return m_size; }
set { m_size = value; UpdateScale(); }
}
public float m_spacing;
public float Spacing {
get { return m_spacing; }
set { m_spacing = value; UpdateScale(); }
}
protected override void UpdateScale() {
if (!mesh.Initialized) return;
UpdateMeshes();
base.UpdateScale();
}
void UpdateFrames() {
if (!mesh.Initialized) return;
float frameHeight = 0;
foreach (var m in meshes) m.Value.Destroy();
meshes.Clear();
foreach (var f in m_frames.Frames) {
f.Value.Load();
if (frameHeight == 0) frameHeight = f.Value.Rect.height;
else if (frameHeight != f.Value.Rect.height) throw new Exception("Inconsistent frame height");
if (!meshes.ContainsKey(f.Value.Frame.Texture)) {
var m = new MeshWrapper();
m.Init(mesh.MeshTransform, transparent);
m.Mesh = new Mesh();
m.Renderer.material.mainTexture = f.Value.Frame.Texture;
meshes.Add(f.Value.Frame.Texture, m);
}
}
}
float sum_x;
void UpdateMeshes() {
if (meshes.Count == 0) return;
sum_x = 0;
int vc = m_value.Length * 4;
Dictionary<Texture2D, List<Vector3>> verts = new Dictionary<Texture2D, List<Vector3>>();
Dictionary<Texture2D, List<Vector2>> uvs = new Dictionary<Texture2D, List<Vector2>>();
foreach (var t in meshes.Keys) {
verts.Add(t, new List<Vector3>(vc));
uvs.Add(t, new List<Vector2>(vc));
}
foreach (var c in m_value) {
var f = m_frames.Frames[c];
var t = f.Frame.Texture;
float w = f.Ratio * m_size;
verts[t].Add(new Vector3(sum_x , 0, 0));
verts[t].Add(new Vector3(sum_x + w, 0, 0));
verts[t].Add(new Vector3(sum_x + w, 0, m_size));
verts[t].Add(new Vector3(sum_x , 0, m_size));
uvs[t].Add(f.Frame.GetUV(new Vector2(0, 0)));
uvs[t].Add(f.Frame.GetUV(new Vector2(1, 0)));
uvs[t].Add(f.Frame.GetUV(new Vector2(1, 1)));
uvs[t].Add(f.Frame.GetUV(new Vector2(0, 1)));
sum_x += w + m_spacing;
}
foreach (var t in meshes.Keys) {
var m = meshes[t].Mesh;
m.Clear();
int cc = verts[t].Count / 4;
int[] tris = new int[cc * 6];
for (int i = 0; i < cc; i++) {
tris[i * 6 ] = i * 4 ;
tris[i * 6 + 1] = i * 4 + 3;
tris[i * 6 + 2] = i * 4 + 1;
tris[i * 6 + 3] = i * 4 + 1;
tris[i * 6 + 4] = i * 4 + 3;
tris[i * 6 + 5] = i * 4 + 2;
}
m.vertices = verts[t].ToArray();
m.uv = uvs[t].ToArray();
m.triangles = tris;
m.RecalculateNormals();
}
sum_x -= m_spacing;
}
protected override Vector3 BaseSize {
get { return new Vector3(sum_x, 1, m_size); }
}
protected override Vector3 BaseScale {
get {
return Vector3.one;
}
}
protected override Vector2 BasePivot {
get { return new Vector2(-0.5f, -0.5f); }
}
float _opacity = 1;
public float Opacity {
get { return _opacity; }
set {
_opacity = value;
UpdateOpacity();
}
}
void UpdateOpacity() {
if (!mesh.Initialized) return;
foreach (var m in meshes.Values) {
var c = m.Renderer.material.color;
c.a = _opacity;
m.Renderer.material.color = c;
}
}
public override void Init() {
InternalInit();
UpdateFrames();
mesh.Mesh.Clear();
UpdateScale();
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 6c3781c012a298849b9276df00b6f59c
timeCreated: 1636509150
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,31 @@
using System.Collections.Generic;
using UnityEngine;
namespace Cryville.Crtr.Components {
public class TrackLine : SectionalGameObject {
readonly List<Vector3> vertices = new List<Vector3>();
public override void Init() {
base.Init();
}
protected override void AppendPointInternal(Vector3 p, Quaternion r) {
vertices.Add(p);
}
public override void Seal() {
var r = GetComponent<LineRenderer>();
#if UNITY_5_6_OR_NEWER
r.positionCount = vertices.Count;
#else
r.SetVertexCount(vertices.Count);
#endif
for (int i = 0; i < vertices.Count; i++) r.SetPosition(i, vertices[i]);
}
public override void Reset() {
base.Reset();
vertices.Clear();
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 7806feaea6d6c2540b2cb950286d379c
timeCreated: 1596635435
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,12 @@
using UnityEngine;
namespace Cryville.Crtr.Components {
public class TransformInterface : SkinComponent {
public TransformInterface() {
SubmitProperty("pos", new PropOp.Vector3(v => transform.localPosition = v));
SubmitProperty("rot", new PropOp.Vector3(v => transform.localRotation = Quaternion.Euler(v)));
SubmitProperty("scale", new PropOp.Vector3(v => transform.localScale = v));
}
protected override void OnDestroy() { }
}
}

View File

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

View File

@@ -0,0 +1,170 @@
using Cryville.Common.Network;
using System;
using System.Collections.Generic;
using System.Threading;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using Logger = Cryville.Common.Logger;
namespace Cryville.Crtr {
public class Console : MonoBehaviour {
public Text Logs;
public InputField InputBox;
CommandWorker worker;
readonly Queue<string> _fallbackQueue = new Queue<string>();
~Console() {
worker.Deactivate();
}
void Start() {
Game.Init();
InputBox.Select();
worker = new CommandWorker(MainThreadFallback);
worker.Activate();
}
public void Submit() {
worker.Issue(InputBox.text);
}
void Update() {
if (
Input.GetKeyDown(KeyCode.Return)
|| Input.GetKeyDown(KeyCode.KeypadEnter)
) {
Submit();
InputBox.text = "";
InputBox.Select();
InputBox.ActivateInputField();
}
if (_fallbackQueue.Count > 0) {
switch (_fallbackQueue.Dequeue()) {
case "play":
SceneManager.LoadScene("Play");
break;
case "quit":
Application.Quit();
break;
default:
Logger.Log("main", 4, "Console", "Unknown command. Type \"help\" for help");
break;
}
}
string _logs = Logs.text;
Game.MainLogger.Enumerate((level, module, msg) => {
string color;
switch (level) {
case 0: color = "#888888"; break;
case 1: color = "#bbbbbb"; break;
case 2: color = "#0088ff"; break;
case 3: color = "#ffff00"; break;
case 4: color = "#ff0000"; break;
case 5: color = "#bb0000"; break;
default: color = "#ff00ff"; break;
}
_logs += string.Format(
"\r\n\x02<color={1}ff>[{0}] <{2}> {3}</color>",
DateTime.UtcNow.ToString("s"), color, module, msg
);
});
Logs.text = _logs.Substring(Mathf.Max(0, _logs.IndexOf('\x02', Mathf.Max(0, _logs.Length - 8192))));
}
void MainThreadFallback(string cmd) {
_fallbackQueue.Enqueue(cmd);
}
class CommandWorker {
readonly Action<string> _fallback;
Thread _thread;
readonly Queue<string> _queue = new Queue<string>();
public CommandWorker(Action<string> fallback) {
_fallback = fallback;
}
public void Activate() {
_thread = new Thread(ThreadLoop);
_thread.Start();
}
public void Deactivate() {
_thread.Abort();
}
public void Issue(string cmd) {
lock (_queue) {
_queue.Enqueue(cmd);
}
}
void ThreadLoop() {
while (true) {
string cmd = null;
lock (_queue) {
if (_queue.Count > 0) cmd = _queue.Dequeue();
}
if (cmd != null) ProcessCommand(cmd);
else Thread.Sleep(20);
}
}
void ProcessCommand(string cmd) {
Logger.Log("main", 2, "Console", "Command processing: {0}", cmd);
var p = cmd.Split(' ');
try {
switch (p[0]) {
case "!http":
var httpcl = new HttpClient(new Uri(p[1]));
httpcl.Connect();
httpcl.Request("GET", new Uri(p[1])).MessageBody.ReadToEnd();
httpcl.Close();
break;
case "!https":
var httpscl = new HttpsClient(new Uri(p[1]));
httpscl.Connect();
httpscl.Request("GET", new Uri(p[1])).MessageBody.ReadToEnd();
httpscl.Close();
break;
/*case "!lua":
Logger.Log("main", 1, "Console", "{0}", Script.RunString(p[1]));
break;*/
/*case "!tls":
var tlscl = new TlsTcpClient(p[1]);
tlscl.Close();
break;*/
case "connect":
Game.ConnectDatabase(p[1]);
break;
case "help": case "?":
Logger.Log(
"main", 1, "Console",
"\n\tconnect <i>name</i>" +
"\n\thelp" +
"\n\tlist" +
"\n\tplay" +
"\n\tquit"
);
break;
case "list":
Logger.Log("main", 1, "Console", "Database list:");
foreach (var i in Game.GetDatabaseList()) {
Logger.Log("main", 1, "Console", "{0}", i.Name);
}
break;
default:
_fallback.Invoke(cmd);
break;
}
}
catch (Exception ex) {
Logger.Log("main", 4, "Console", "{0}", ex);
}
Logger.Log("main", 2, "Console", "Command done: {0}", cmd);
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 069c1a41e65819549b4dfcda4e619b76
timeCreated: 1620726427
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,331 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Cryville.Common;
using Cryville.Common.Pdt;
using Cryville.Crtr.Components;
using Cryville.Crtr.Event;
using UnityEngine;
namespace Cryville.Crtr {
#if false
[Obsolete]
public struct Evaluator : IEvaluator {
public object ParseNumber(string exp) {
return float.Parse(exp);
}
public object ParseString(string exp) {
return exp;
}
public object EvalIdentifier(string exp) {
if (exp[0] == '$') {
var r = Context.State.GetRawValue<Vector>(new MotionName(exp.Substring(1)));
if (r is Vec1) return ((Vec1)r).Value;
if (r is Vec1m) return ((Vec1m)r).Value;
if (r is Vec3) return ((Vec3)r).ToVector3();
if (r is VecI1) return ((VecI1)r).Value;
if (r is VecPt) return ((VecPt)r).ToVector2(ChartPlayer.hitRect);
if (r is VecPtComp) return ((VecPtComp)r).ToFloat(ChartPlayer.hitRect);
throw new NotImplementedException();
}
switch (exp) {
case "w": return ChartPlayer.hitRect.width;
case "h": return ChartPlayer.hitRect.height;
case "true": return true;
case "false": return false;
case "pos":
return Context.State.Handler.Position;
// return ctx.Transform.position;
default:
if (Context.Extra != null && Context.Extra.ContainsKey(exp))
return Context.Extra[exp];
if (Context.Reservations != null && Context.Reservations.Contains(exp))
throw new Exception();
if (Context.State == null && !Context.DisableLiteralString)
return exp;
return Context.State.Container.Properties[exp]();
}
}
public object OperateUnary(Operand op, object q) {
switch (op.exp) {
case "-":
if (q is float) return -(float)q;
else throw new NotImplementedException();
default:
throw new NotImplementedException();
}
}
public object OperateBinary(Operand op, object q, object r) {
switch (op.exp) {
case "+":
if (!(q is float && r is float))
throw new ArgumentException(); // TODO
return (float)q + (float)r;
case "-":
if (!(q is float && r is float))
throw new ArgumentException(); // TODO
return (float)q - (float)r;
case "*":
if (!(q is float && r is float))
throw new ArgumentException(); // TODO
return (float)q * (float)r;
case "/":
if (!(q is float && r is float))
throw new ArgumentException(); // TODO
return (float)q / (float)r;
case " ":
if (typeof(List<object>).IsAssignableFrom(q.GetType())) {
((List<object>)q).Add(r);
return q;
}
else {
return new List<object>(){q, r};
}
case ",":
if (q is Stack) {
((Stack)q).Push(r);
return q;
}
else {
var s = new Stack();
s.Push(q); s.Push(r);
return s;
}
default:
throw new NotImplementedException();
}
}
public object OperateFunction(Operand op, object q) {
switch (op.exp) {
case "circle":
var lcirc = (Stack)q;
var radius = (float)Cast(typeof(float), lcirc.Pop());
var circcenter = (Vector2)Cast(typeof(Vector2), lcirc.Pop());
return ((Vector2)Context.Extra["-hitpos"] - circcenter).sqrMagnitude - radius * radius;
case "dist":
var ldist = (Stack)q;
var rhs = (Vector3)Cast(typeof(Vector3), ldist.Pop());
var lhs = (Vector3)Cast(typeof(Vector3), ldist.Pop());
return (lhs - rhs).magnitude;
case "frame_seq":
var lframeseq = (Stack)q;
var ub = (int)(float)Cast(typeof(float), lframeseq.Pop());
var lb = (int)(float)Cast(typeof(float), lframeseq.Pop());
var prefix = (string)lframeseq.Pop();
var frames = new List<object>();
for (int i = lb; i <= ub; i++) {
frames.Add(prefix + i.ToString());
}
return frames;
case "rect":
var lrect = (Stack)q;
var recth = (float)Cast(typeof(float), lrect.Pop()) / 2;
var rectw = (float)Cast(typeof(float), lrect.Pop()) / 2;
var rectcenter = (Vector2)Cast(typeof(Vector2), lrect.Pop());
var recthit = (Vector2)Context.Extra["-hitpos"] - rectcenter;
return (Mathf.Abs(recthit.x) <= Mathf.Abs(rectw) && Mathf.Abs(recthit.y) <= Mathf.Abs(recth)) ? -1f : 1f;
case "screen_edge":
float dist;
var ray = new Ray(Context.Transform.position, Context.Transform.rotation * Vector3.forward);
ChartPlayer.frustumPlanes[(int)(float)q].Raycast(ray, out dist);
return ray.GetPoint(dist);
default:
throw new NotImplementedException(
string.Format("Unknown function: {0}", op.exp)
);
}
}
// TODO [Obsolete]
public object Cast(Type type, object obj) {
if (type.IsAssignableFrom(obj.GetType()))
return obj;
if (typeof(ICollection).IsAssignableFrom(obj.GetType())) {
var o = ((ICollection)obj).Cast<object>().ToList();
if (obj is Stack) o.Reverse();
if (type == typeof(Color)) {
return new Color(
(float)o[0],
(float)o[1],
(float)o[2],
o.Count >= 4 ? (float)o[3] : 1
);
}
else if (type == typeof(Vector3)) {
float z = o.Count >= 3 ? (float)o[2] : 0;
return new Vector3((float)o[0], (float)o[1], z);
}
else if (type == typeof(Vector2)) {
return new Vector2((float)o[0], (float)o[1]);
}
else if (type == typeof(string)) {
return string.Join(",", o.Cast<string>().ToArray());
}
else if (type.BaseType == typeof(Array)) {
var etype = type.GetElementType();
IList r = (IList)ReflectionHelper.InvokeEmptyConstructor(typeof(List<>).MakeGenericType(etype));
foreach (var i in o) {
r.Add(Cast(etype, i));
}
return typeof(Enumerable).GetMethod("ToArray")
.MakeGenericMethod(etype).Invoke(
null, new object[]{r}
);
}
else if (typeof(IList).IsAssignableFrom(type)) {
var etype = type.GetGenericArguments()[0];
IList r = (IList)ReflectionHelper.InvokeEmptyConstructor(typeof(List<>).MakeGenericType(etype));
foreach (var i in o) {
r.Add(Cast(etype, i));
}
return r;
}
}
else if (obj is float) {
float g = (float)obj;
if (type == typeof(Vector3)) {
return new Vector3(g, g, g);
}
else if (type == typeof(Vector2)) {
return new Vector2(g, g);
}
else if (typeof(IConvertible).IsAssignableFrom(type)) {
return ((IConvertible)g).ToInt16(null);
}
}
if (type.IsEnum) {
return Enum.Parse(type, (string)Cast(typeof(string), obj), true);
}
else if (typeof(IConstructable).IsAssignableFrom(type)) {
var r = (IConstructable)Activator.CreateInstance(type);
r.Load(obj, this);
return r;
}
else if (typeof(IList).IsAssignableFrom(type)) {
IList r = (IList)ReflectionHelper.InvokeEmptyConstructor(typeof(List<>).MakeGenericType(obj.GetType()));
r.Add(obj);
return r;
}
throw new InvalidCastException(String.Format("Cannot cast {0} to {1}", obj.GetType(), type));
}
public EvaluatorContext Context { get; set; }
/*object CastBypass(object obj) { return obj; }
object CastListColor(object obj) {
var o = (IList)obj;
float a = o.Count >= 4 ? (float)o[3] : 1;
return new Color(
(float)o[0],
(float)o[1],
(float)o[2],
a
);
}
object CastListVector3(object obj) {
var o = (IList)obj;
float z = o.Count >= 3 ? (float)o[2] : 0;
return new Vector3((float)o[0], (float)o[1], z);
}
object CastListVector2(object obj) {
var o = (IList)obj;
return new Vector2((float)o[0], (float)o[1]);
}
object CastListString(object obj) {
var o = (IList)obj;
return String.Join(",", o.Cast<string>().ToArray());
}
object CastListArray(object obj) {
var o = (IList)obj;
var etype = dest.GetElementType();
IList r = (IList)ReflectionHelper.InvokeEmptyConstructor(typeof(List<>).MakeGenericType(etype));
foreach (var i in o) {
r.Add(Cast(etype, i));
}
return typeof(Enumerable).GetMethod("ToArray")
.MakeGenericMethod(etype).Invoke(
null, new object[] { r }
);
}
object CastNumberVector3(object obj) {
var o = (float)obj;
return new Vector3(o, o, o);
}
object CastNumberVector2(object obj) {
var o = (float)obj;
return new Vector2(o, o);
}
object CastNumberBypass(object obj) {
var o = (float)obj;
return ((IConvertible)o).ToInt16(null);
}
object CastListEnum(object obj) {
var o = (float)obj;
return ((IConvertible)o).ToInt16(null);
}
public override CastCallback GetCastCallback(Type dest, Type source) {
if (dest.IsAssignableFrom(source)) return new CastCallback(CastBypass);
if (typeof(IList).IsAssignableFrom(source)) {
if (dest == typeof(Color)) return new CastCallback(CastListColor);
if (dest == typeof(Vector3)) return new CastCallback(CastListVector3);
if (dest == typeof(Vector2)) return new CastCallback(CastListVector2);
if (dest == typeof(string)) return new CastCallback(CastListString);
if (dest.BaseType == typeof(Array)) {
var etype = type.GetElementType();
IList r = (IList)ReflectionHelper.InvokeEmptyConstructor(typeof(List<>).MakeGenericType(etype));
foreach (var i in o) {
r.Add(Cast(etype, i));
}
return typeof(Enumerable).GetMethod("ToArray")
.MakeGenericMethod(etype).Invoke(
null, new object[] { r }
);
}
else if (typeof(IList).IsAssignableFrom(type)) {
var etype = type.GetGenericArguments()[0];
IList r = (IList)ReflectionHelper.InvokeEmptyConstructor(typeof(List<>).MakeGenericType(etype));
foreach (var i in o) {
r.Add(Cast(etype, i));
}
return r;
}
}
else if (source == typeof(float)) {
if (dest == typeof(Vector3)) return new CastCallback(CastNumberVector3);
if (dest == typeof(Vector2)) return new CastCallback(CastNumberVector2);
if (typeof(IConvertible).IsAssignableFrom(dest)) return new CastCallback(CastNumberBypass);
}
if (type.IsEnum) {
return Enum.Parse(type, (string)Cast(typeof(string), obj), true);
}
else if (typeof(IConstructable).IsAssignableFrom(type)) {
var r = (IConstructable)Activator.CreateInstance(type);
r.Load(obj, this);
return r;
}
else if (typeof(IList).IsAssignableFrom(type)) {
IList r = (IList)ReflectionHelper.InvokeEmptyConstructor(typeof(List<>).MakeGenericType(obj.GetType()));
r.Add(obj);
return r;
}
throw new NotImplementedException();
}*/
}
/*class CastCallback {
public Func<object, object> Callback { get; set; }
public CastCallback Nested { get; set; }
public CastCallback(Func<object, object> cb, CastCallback ncc = null) {
Callback = cb;
Nested = ncc;
}
}*/
[Obsolete]
public struct EvaluatorContext {
public ContainerState State;
public Transform Transform;
public Dictionary<string, object> Extra;
public List<string> Reservations;
public bool DisableLiteralString;
}
#endif
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 1d956cad385858849a2681bed8031a77
timeCreated: 1617844741
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: a65cec040b88e9b43b6e2058eb13562f
folderAsset: yes
timeCreated: 1617701650
licenseType: Free
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,137 @@
using Cryville.Crtr.Components;
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Cryville.Crtr.Event {
public abstract class ContainerHandler : IDisposable {
/// <summary>
/// Prehandling <see cref="ContainerState"/>, prehandling the events.
/// </summary>
public ContainerState ps;
/// <summary>
/// Backward <see cref="ContainerState"/>, disposing events at the backward clipping plane, firing anchor state and temporary state.
/// </summary>
public ContainerState bs;
/// <summary>
/// Current <see cref="ContainerState"/>, handling events occuring at the current time.
/// </summary>
public ContainerState cs;
/// <summary>
/// Anchor <see cref="ContainerState"/>, computing the start position of the temporary state.
/// </summary>
public ContainerState ns;
/// <summary>
/// Temporary <see cref="ContainerState"/>, rendering events between the clipping planes.
/// </summary>
public ContainerState ts;
/// <summary>
/// <see cref="GameObject"/> group, the <see cref="Transform"/> containing all the generated elements in the <see cref="ContainerHandler"/>.
/// </summary>
public Transform gogroup;
public readonly Dictionary<string, Anchor> Anchors = new Dictionary<string, Anchor>();
public Transform a_head;
public Transform a_tail;
public Vector3 Position {
get;
protected set;
}
public Quaternion Rotation {
get;
protected set;
}
public bool Alive {
get;
private set;
}
public bool Awoken {
get;
private set;
}
public bool Disposed {
get;
private set;
}
public EventContainer Container {
get { return cs.Container; }
}
public ContainerHandler() { }
public abstract string TypeName {
get;
}
public virtual void PreInit() {
gogroup = new GameObject(TypeName + ":" + Container.GetHashCode().ToString()).transform;
if (cs.Parent != null)
gogroup.SetParent(cs.Parent.Handler.gogroup, false);
a_head = new GameObject("::head").transform;
a_head.SetParent(gogroup, false);
Anchors.Add("head", new Anchor() { Transform = a_head });
a_tail = new GameObject("::tail").transform;
a_tail.SetParent(gogroup, false);
Anchors.Add("tail", new Anchor() { Transform = a_tail });
}
/// <summary>
/// Called upon initialization of <see cref="cs" />.
/// </summary>
public virtual void Init() {
cs.skinContainer.MatchStatic(cs);
foreach (var i in gogroup.GetComponentsInChildren<SkinComponent>())
i.Init();
}
public virtual void PostInit() {
gogroup.gameObject.SetActive(false);
}
public virtual void Dispose() {
if (Disposed) return;
Disposed = true;
if (gogroup)
GameObject.Destroy(gogroup.gameObject);
// gogroup.gameObject.SetActive(false);
Alive = false;
}
protected virtual void PreAwake(ContainerState s) {
if (gogroup) gogroup.gameObject.SetActive(true);
Awoken = true; Alive = true;
OpenAnchor("head");
}
protected virtual void Awake(ContainerState s) {
CloseAnchor("head");
}
protected virtual void GetPosition(ContainerState s) { }
public virtual void StartUpdate(ContainerState s) {
if (s.CloneType >= 2 && s.CloneType < 16) {
PreAwake(s);
Awake(s);
}
}
public virtual void Update(ContainerState s, StampedEvent ev) {
bool flag = !Awoken && s.CloneType >= 2 && s.CloneType < 16;
if (flag) PreAwake(s);
if (Awoken && s.CloneType <= 2) if (gogroup) cs.skinContainer.MatchDynamic(s);
if (flag) Awake(s);
}
public virtual void ExUpdate(ContainerState s, StampedEvent ev) { }
public virtual void MotionUpdate(byte ct, Chart.Motion ev) { }
public virtual void EndUpdate(ContainerState s) {
if (s.CloneType < 16) {
Awoken = false;
if (gogroup && s.CloneType <= 2) cs.skinContainer.MatchDynamic(s);
}
}
public virtual void Anchor() { }
protected void OpenAnchor(string name) {
if (Anchors.ContainsKey(name)) Anchors[name].Open();
}
protected void CloseAnchor(string name) {
if (Anchors.ContainsKey(name)) Anchors[name].Close();
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: da65ca35eb403a94ab9a1e07f7b3100c
timeCreated: 1617788981
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,485 @@
//#define DISABLE_CACHE
using Cryville.Common;
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Cryville.Crtr.Event {
public class ContainerState {
public EventBus Bus;
public EventContainer Container;
public ContainerState Parent = null;
public ushort Depth;
public Dictionary<EventContainer, ContainerState> Children
= new Dictionary<EventContainer, ContainerState>();
HashSet<EventContainer> WorkingChildren
= new HashSet<EventContainer>();
HashSet<EventContainer> InvalidatedChildren
= new HashSet<EventContainer>();
public Dictionary<Type, List<ContainerState>> TypedChildren
= new Dictionary<Type, List<ContainerState>>();
public ContainerState GetChild(int index, Type handlerType) {
return TypedChildren[handlerType][index];
}
public ContainerState GetChild(EventContainer ev) {
/*if (!Children.ContainsKey(ev)) {
Children[ev] = prototype.FetchChildClone(ev, CloneType);
}*/
return Children[ev];
}
/*ContainerState FetchChildClone(EventContainer ev, byte ct) {
return Children[ev].Clone(ct);
}*/
void NotifyWorkingChanged(EventContainer key) {
InvalidatedChildren.Add(key);
}
void ValidateChildren() {
foreach (var cev in InvalidatedChildren)
if (Children[cev].Working && !WorkingChildren.Contains(cev)) WorkingChildren.Add(cev);
else if (!Children[cev].Working && WorkingChildren.Contains(cev)) WorkingChildren.Remove(cev);
InvalidatedChildren.Clear();
}
private bool m_Working;
public bool Working {
get { return m_Working; }
set {
m_Working = value;
if (Parent != null) Parent.NotifyWorkingChanged(Container);
Bus.NotifyWorkingChanged(this);
}
}
public byte CloneType;
private ContainerState rootPrototype = null;
private ContainerState prototype = null;
// public SkinManager skinManager;
public SkinContainer skinContainer;
public Judge judge;
public ContainerHandler Handler {
get;
private set;
}
public float Time {
get {
return Bus.Time;
}
}
readonly RMVPool RMVPool = new RMVPool();
protected Dictionary<StampedEvent, RealtimeMotionValue> PlayingMotions = new Dictionary<StampedEvent, RealtimeMotionValue>();
protected Dictionary<MotionName, RealtimeMotionValue> Values = new Dictionary<MotionName, RealtimeMotionValue>();
protected Dictionary<MotionName, Vector> CachedValues = new Dictionary<MotionName, Vector>();
protected Dictionary<MotionName, bool> CachedValueStates = new Dictionary<MotionName, bool>();
/// <summary>
/// Gets a motion value.
/// </summary>
/// <param name="name">The motion name.</param>
/// <param name="clone">Returns a cloned motion value instead.</param>
/// <returns>A motion value.</returns>
RealtimeMotionValue GetMotionValue(MotionName name, bool clone = false) {
RealtimeMotionValue value;
if (!Values.TryGetValue(name, out value)) {
value = new RealtimeMotionValue().Init(Parent == null
? ChartPlayer.motionRegistry[name.MainName].GlobalInitValue
: ChartPlayer.motionRegistry[name.MainName].InitValue
);
Values.Add(name, value);
}
if (clone) return value.Clone();
return value;
}
void InvalidateMotion(MotionName name) {
// if (CachedValues.ContainsKey(name))
CachedValueStates[name] = false;
foreach (var c in Children)
c.Value.InvalidateMotion(name);
}
public ContainerState(Chart c, EventContainer _ev, ContainerState parent = null) {
Container = _ev;
if (parent != null) {
AddChild(_ev, this, parent);
Parent = parent;
}
foreach (var m in ChartPlayer.motionRegistry)
Values.Add(new MotionName(m.Key), new RealtimeMotionValue().Init(Parent == null ? m.Value.GlobalInitValue : m.Value.InitValue));
//skinManager = new SkinManager(skin, this);
//events.Sort((a, b) => a.Time.CompareTo(b.Time));
}
static void AddChild(EventContainer c, ContainerState s, ContainerState target) {
target.Children.Add(c, s);
Type t = c.GetType();
if (!target.TypedChildren.ContainsKey(t)) target.TypedChildren.Add(t, new List<ContainerState>());
target.TypedChildren[t].Add(s);
}
public ContainerState Clone(byte ct) {
/*if (prototype != null)
throw new InvalidOperationException();*/
var r = (ContainerState)MemberwiseClone();
var mvs = new Dictionary<MotionName, RealtimeMotionValue>(Values.Count);
foreach (var mv in Values) {
mvs.Add(mv.Key, mv.Value.Clone());
}
r.Values = mvs;
var cvs = new Dictionary<MotionName, Vector>(CachedValues.Count);
foreach (var cv in CachedValues) {
cvs.Add(cv.Key, cv.Value.Clone());
}
r.CachedValues = cvs;
var cvss = new Dictionary<MotionName, bool>(CachedValueStates.Count);
foreach (var cv in CachedValueStates) {
cvss.Add(cv.Key, cv.Value);
}
r.CachedValueStates = cvss;
r.Children = new Dictionary<EventContainer, ContainerState>();
foreach (var child in Children) {
// if (!child.Value.Working && ct != 1) continue;
var cc = child.Value.Clone(ct);
cc.Parent = r;
AddChild(child.Key, cc, r);
}
var pms = new Dictionary<StampedEvent, RealtimeMotionValue>(PlayingMotions.Count);
foreach (var m in PlayingMotions)
pms.Add(m.Key, m.Value);
r.PlayingMotions = pms;
if (ct == 1) Handler.bs = r;
else if (ct == 2) Handler.ts = r;
else if (ct == 3) Handler.ns = r;
else if (ct >= 16) Handler.ps = r;
else throw new InvalidOperationException("Invalid clone type");
r.prototype = this;
if (prototype == null) r.rootPrototype = this;
else r.rootPrototype = rootPrototype;
r.CloneType = ct;
return r;
}
public void CopyTo(byte ct, ContainerState dest) {
dest.Working = Working;
foreach (var mv in Values) {
RealtimeMotionValue dv;
if (dest.Values.TryGetValue(mv.Key, out dv)) mv.Value.CopyTo(dv);
else dest.Values.Add(mv.Key, mv.Value.Clone());
}
// dest.CachedValues.Clear();
foreach (var cv in CachedValues) {
Vector dv;
if(dest.CachedValues.TryGetValue(cv.Key, out dv)) cv.Value.CopyTo(dv);
else dest.CachedValues.Add(cv.Key, cv.Value.Clone());
}
foreach (var cvs in CachedValueStates) dest.CachedValueStates[cvs.Key] = cvs.Value;
if (ct != 1) foreach (var cev in WorkingChildren)
Children[cev].CopyTo(ct, dest.Children[cev]);
else foreach (var child in Children)
child.Value.CopyTo(ct, dest.Children[child.Key]);
ValidateChildren();
RMVPool.ReturnAll();
dest.PlayingMotions.Clear();
foreach (var m in PlayingMotions) dest.PlayingMotions.Add(m.Key, m.Value);
}
public bool Disposed {
get;
private set;
}
public void Dispose() {
if (Disposed) return;
Disposed = true;
if (Handler != null) Handler.Dispose();
foreach (var s in Children)
s.Value.Dispose();
RMVPool.ReturnAll();
}
public void AttachHandler(ContainerHandler h) {
if (Handler != null)
throw new InvalidOperationException();
Handler = h;
h.cs = this;
}
public void AttachSystems(PdtSkin skin, Judge judge) {
// skinManager = new SkinManager(skin);
skinContainer = new SkinContainer(skin);
this.judge = judge;
}
public T GetRawValue<T>(MotionName key) where T : Vector {
Vector tr;
if (!CachedValues.TryGetValue(key, out tr)) {
tr = (Vector)ReflectionHelper.InvokeEmptyConstructor(typeof(T));
CachedValues.Add(key, tr);
CachedValueStates[key] = false;
}
T r = (T)tr;
#if !DISABLE_CACHE
if (CachedValueStates[key]) return r;
#endif
float reltime = 0;
if (rootPrototype != null) reltime = Time - rootPrototype.Time;
GetMotionValue(key).GetValue(reltime, ref r);
if (Parent != null) r.ApplyFrom(Parent.GetRawValue<T>(key));
#if !DISABLE_CACHE
CachedValueStates[key] = true;
#endif
return r;
}
static readonly MotionName n_dir = new MotionName("dir");
public Vector3 Direction {
get {
Vec3 r = GetRawValue<Vec3>(n_dir);
return r.ToVector3();
}
}
static readonly MotionName n_normal = new MotionName("normal");
public Vector3 Normal {
get {
Vec3 r = GetRawValue<Vec3>(n_normal);
return r.ToVector3();
}
}
public Quaternion QuatDir {
get {
return Quaternion.LookRotation(Quaternion.Euler(Direction) * Vector3.forward, Normal);
}
}
static readonly MotionName n_pt = new MotionName("pt");
public Vector2 ScreenPoint {
get {
var mv = GetRawValue<VecPt>(n_pt);
return mv.ToVector2(ChartPlayer.hitRect);
}
}
static readonly MotionName n_visible = new MotionName("visible");
public bool Visible {
get {
return GetRawValue<VecI1>(n_visible).Value % 2 >= 1;
}
}
static readonly MotionName n_sv = new MotionName("sv");
static readonly MotionName n_svm = new MotionName("svm");
public float ScrollVelocity {
get {
return GetRawValue<VecPtComp>(n_sv).ToFloat(ChartPlayer.hitRect)
* GetRawValue<Vec1m>(n_svm).Value;
}
}
static readonly MotionName n_dist = new MotionName("dist");
public float Distance {
get {
var mv = GetRawValue<VecPtComp>(n_dist);
return mv.ToFloat(ChartPlayer.hitRect);
}
}
static readonly MotionName n_corner = new MotionName("corner");
public bool Corner {
get {
return GetRawValue<VecI1>(n_corner).Value % 2 >= 1;
}
}
static readonly MotionName n_ctrl0 = new MotionName("ctrl0");
static readonly MotionName n_ctrl1 = new MotionName("ctrl1");
public Vector3 GetControlPoint(bool alt1, float deltaz) {
var mv = GetRawValue<VecCtrl>(alt1 ? n_ctrl1 : n_ctrl0);
if (alt1 && mv.IsZero()) {
mv = GetRawValue<VecCtrl>(n_ctrl0);
}
return mv.ToVector3(ChartPlayer.hitRect, deltaz);
}
static readonly MotionName n_track = new MotionName("track");
public float Track {
get {
return GetRawValue<Vec1>(n_track).Value;
}
}
bool breakflag = false;
public void Break() {
Handler.EndUpdate(this);
breakflag = true;
Working = false;
}
public void Handle(StampedEvent ev, Action<StampedEvent> callback = null) {
if (breakflag) {
// Time = toTime;
return;
}
if (ev != null) {
bool flag = false;
if (ev.Unstamped is Chart.Motion) {
var tev = (Chart.Motion)ev.Unstamped;
// tev._apply(Values);
var mv = RMVPool.Rent(tev.Name);
GetMotionValue(tev.Name).CopyTo(mv);
PlayingMotions.Add(ev, mv);
Callback(ev, callback);
// UpdateMotions();
if (!ev.Unstamped.IsLong)
PlayingMotions.Remove(ev);
}
else if (ev.Unstamped is EventContainer) {
var cev = (EventContainer)ev.Unstamped;
var ccs = GetChild(cev);
ccs.Working = true;
ccs.StartUpdate();
UpdateMotions();
if (!ev.Unstamped.IsLong) {
ccs.Working = false;
ccs.BroadcastEndUpdate();
if (CloneType == 1) ccs.Dispose();
}
}
else if (ev.Unstamped is InstantEvent) {
var tev = (InstantEvent)ev.Unstamped;
if (tev.IsRelease) {
var nev = tev.Original;
if (nev is Chart.Motion) {
// var tnev = (Chart.Motion)nev;
Callback(ev, callback);
// UpdateMotions();
PlayingMotions.Remove(ev.Origin);
}
else if (nev is EventContainer) {
var cev = (EventContainer)ev.Origin.Unstamped;
var ccs = GetChild(cev);
UpdateMotions();
ccs.Working = false;
ccs.BroadcastEndUpdate();
if (CloneType == 1) ccs.Dispose();
}
}
}
if (ev.Unstamped == null) {
Callback(ev, callback);
flag = true;
}
else if (ev.Unstamped.Priority >= 0) {
Callback(ev, callback);
flag = true;
}
if (!flag) Callback(null, callback);
return;
}
// Time = toTime;
Callback(null, callback);
}
void Callback(StampedEvent ev, Action<StampedEvent> callback) {
UpdateMotions();
if (callback != null)
callback(ev);
if (ev == null || ev.Unstamped != null) Handler.Update(this, ev);
else Handler.ExUpdate(this, ev);
/*if (CloneType == 1) {
if (ev == null || ev.Event != null) Handler.Forward(ev);
else Handler.ExUpdate(CloneType, ev);
}
else if (CloneType == 0) {
if (ev == null || ev.Event != null) Handler.Update(ev);
else Handler.ExUpdate(CloneType, ev);
}
else if (CloneType == 2) {
// TODO Do nothing atm
}
else if (CloneType >= 16) {
if (ev == null || ev.Event != null) Handler.PreUpdate(CloneType, ev);
else Handler.ExUpdate(CloneType, ev);
}*/
foreach (var m in PlayingMotions)
Handler.MotionUpdate(CloneType, (Chart.Motion)m.Key.Unstamped);
}
private void UpdateMotions() {
foreach (var m in PlayingMotions) {
var tev = (Chart.Motion)m.Key.Unstamped;
if (tev.RelativeNode != null && CloneType == 2) continue;
var value = GetMotionValue(tev.Name/*, true*/);
InvalidateMotion(tev.Name);
if (m.Key.Duration == 0) {
if (tev.RelativeNode != null) {
value.SetRelativeNode(tev.RelativeNode);
}
else {
value.AbsoluteValue.ReplaceFrom(tev.AbsoluteValue);
}
}
else {
var scaledTime = (Time - m.Key.Time - ChartPlayer.actualRenderStep * tev.sumfix) / m.Key.Duration;
var lerpedTime = MotionLerper.GetEaseTime(scaledTime, tev.transition, tev.rate);
if (tev.RelativeNode != null) {
var target = value.QueryRelativeNode(tev.RelativeNode.Id);
tev.RelativeNode.LerpWith(m.Value.GetRelativeNode(tev.RelativeNode.Id), lerpedTime, ref target);
}
else {
tev.AbsoluteValue.LerpWith(m.Value.AbsoluteValue, lerpedTime, ref value.AbsoluteValue);
}
}
Values[tev.Name] = value;
}
}
public void BroadcastInit() {
Handler.PreInit();
Handler.Init();
foreach (var s in Children) {
s.Value.BroadcastInit();
}
Handler.PostInit();
}
public void StartUpdate() {
Handler.StartUpdate(this);
}
public void BroadcastEndUpdate() {
Handler.EndUpdate(this);
foreach (var ls in Children.Values) {
if (ls.Working) ls.BroadcastEndUpdate();
}
}
public void Anchor() {
Handler.Anchor();
foreach (var ls in Children.Values) {
if (ls.Handler.Alive) ls.Anchor();
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: a2ebe22dbedf60c4b96dd6ae834a740f
timeCreated: 1617701716
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,47 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Cryville.Crtr.Event {
public class EventBatch : IComparable<EventBatch>, IEnumerable<StampedEvent> {
public float Time {
get;
private set;
}
readonly List<StampedEvent> queue = new List<StampedEvent>();
public int Count {
get { return queue.Count; }
}
public EventBatch(float time) {
Time = time;
}
public StampedEvent this[int index] {
get { return queue[index]; }
}
public void Add(StampedEvent ev) {
Enqueue(ev);
}
public void Enqueue(StampedEvent ev) {
int i = queue.BinarySearch(ev);
if (i < 0) queue.Insert(~i, ev);
}
public int CompareTo(EventBatch other) {
return this.Time.CompareTo(other.Time);
}
public IEnumerator<StampedEvent> GetEnumerator() {
return queue.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() {
return GetEnumerator();
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 532772ba68ebf6d49a83a49e9e13cbdd
timeCreated: 1617673011
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,147 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace Cryville.Crtr.Event {
public class EventBatcher : StateBase<ChartEvent> {
public EventBus Bus {
get;
private set;
}
ContainerState RootState;
/// <summary>
/// event => the container state that handles the event
/// </summary>
readonly Dictionary<ChartEvent, ContainerState> table
= new Dictionary<ChartEvent, ContainerState>();
public List<StampedEvent> stampedEvents = new List<StampedEvent>();
readonly List<EventBatch> batches = new List<EventBatch>();
float beat;
float tempo;
public EventBatcher(Chart c) : base(c, new List<ChartEvent>()) {
beat = chart.BeatPosition;
tempo = (float)c.sigs[0].tempo;
events.Add(c);
events.Add(c.ReleaseEvent);
AddEventContainer(c);
events.Sort((a, b) => a.BeatPosition.CompareTo(b.BeatPosition));
}
void AddEventContainer(EventContainer c, ContainerState parent = null) {
var cs = new ContainerState(chart, c, parent);
if (parent == null) {
cs.Depth = 0;
RootState = cs;
}
else {
cs.Depth = (ushort)(parent.Depth + 1);
}
foreach (var ev in c.Events) {
if (ev.time == null) {
ev.time = c.time;
if (ev is EventContainer)
ev.endtime = c.endtime;
}
if (ev.IsLong) {
events.Add(ev.ReleaseEvent);
table.Add(ev.ReleaseEvent, cs);
/*if (ev is Chart.Note) {
events.Add(ev.AttackEvent);
}*/
}
events.Add(ev);
table.Add(ev, cs);
if (ev is EventContainer)
AddEventContainer((EventContainer)ev, cs);
}
}
public override void ForwardOnceToTime(float toTime, Action<ChartEvent> callback) {
float toBeat = (float)Math.Round(beat + (toTime - Time) * tempo / 60f, 6);
if (EventId >= events.Count)
goto return_ahead;
float ebeat = events[EventId].BeatPosition;
float etime = (float)Math.Round((ebeat - beat) / tempo * 60f + Time, 6);
if (etime > toTime)
goto return_ahead;
var batch = GetEventBatch();
Time = etime;
beat = ebeat;
bool flag = false;
foreach (var ev in batch) {
EventContainer con = null;
if (table.ContainsKey(ev)) con = table[ev].Container;
var sev = new StampedEvent() {
Time = etime,
Unstamped = ev,
Container = con
};
if (ev is InstantEvent) {
var tev = (InstantEvent)ev;
var pev = stampedEvents.First(tpev => tpev.Unstamped == tev.Original);
pev.Subevents.Add(sev);
sev.Origin = pev;
}
stampedEvents.Add(sev);
if (ev.Priority >= 0) {
if (callback != null) callback(ev);
flag = true;
}
if (ev is Chart.Signature) {
var tev = (Chart.Signature)ev;
if (tev.tempo != null) tempo = (float)tev.tempo;
}
EventId++;
}
if (callback != null && !flag) callback(batch.First());
return;
return_ahead:
Time = toTime;
beat = toBeat;
// foreach (var c in Children) c.ForwardToTime(Time);
if (callback != null) callback(null);
}
IOrderedEnumerable<ChartEvent> GetEventBatch() {
float cbeat = events[EventId].BeatPosition;
int b = EventId;
while (Mathf.Approximately(events[b].BeatPosition, cbeat)) {
b--;
if (b == -1) break;
}
int a = EventId;
while (Mathf.Approximately(events[a].BeatPosition, cbeat)) {
a++;
if (a == events.Count) break;
}
return from ev in events.GetRange(b + 1, a - b - 1) orderby ev.Priority select ev;
}
public EventBus Batch() {
stampedEvents.Sort((a, b) => {
int u = a.CompareTo(b);
if (u != 0) return u;
if (a.Unstamped != null && b.Unstamped != null)
if (table.ContainsKey(a.Unstamped) && table.ContainsKey(b.Unstamped)) {
u = table[a.Unstamped].Depth.CompareTo(table[b.Unstamped].Depth);
if (u != 0) return u;
}
return a.GetHashCode().CompareTo(b.GetHashCode());
});
var cb = new EventBatch(stampedEvents[0].Time);
foreach (var ev in stampedEvents) {
if (ev.Time != cb.Time) {
batches.Add(cb);
cb = new EventBatch(ev.Time);
}
cb.Enqueue(ev);
}
batches.Add(cb);
Bus = new EventBus(chart, RootState, batches);
return Bus;
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 494728f9d5dcbd443b5e109420c02d2a
timeCreated: 1617663907
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,177 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Cryville.Crtr.Event {
public class EventBus : StateBase<EventBatch>, IDisposable {
EventBus prototype = null;
public ContainerState RootState {
get;
private set;
}
Dictionary<EventContainer, ContainerState> states
= new Dictionary<EventContainer, ContainerState>();
List<EventContainer> activeContainers
= new List<EventContainer>();
HashSet<ContainerState> workingStates
= new HashSet<ContainerState>();
HashSet<ContainerState> invalidatedStates
= new HashSet<ContainerState>();
public EventBus(Chart c, ContainerState root, List<EventBatch> b)
: base(c, b) {
RootState = root;
Expand();
AttachBus();
RootState.Working = true;
}
public EventBus Clone(byte ct, float offsetTime = 0) {
var r = (EventBus)MemberwiseClone();
r.prototype = this;
r.states = new Dictionary<EventContainer, ContainerState>();
r.activeContainers = new List<EventContainer>();
r.workingStates = new HashSet<ContainerState>();
r.invalidatedStates = new HashSet<ContainerState>();
r.Time += offsetTime;
r.RootState = RootState.Clone(ct);
r.Expand();
r.AttachBus();
foreach (var s in r.states) r.invalidatedStates.Add(s.Value);
r.ValidateStates();
return r;
}
public void CopyTo(byte ct, EventBus dest) {
base.CopyTo(dest);
// dest.states.Clear();
dest.workingStates.Clear();
dest.invalidatedStates.Clear();
RootState.CopyTo(ct, dest.RootState);
// foreach (var s in dest.states) dest.invalidatedStates.Add(s.Value);
dest.ValidateStates();
if (ct >= 2) {
dest.activeContainers.Clear();
foreach (var c in activeContainers) {
if (states[c].Working) {
states[c].CopyTo(ct, dest.states[c]);
dest.activeContainers.Add(c);
}
}
}
}
public void Dispose() {
RootState.Dispose();
}
public void NotifyWorkingChanged(ContainerState state) {
invalidatedStates.Add(state);
}
void Expand(ContainerState s = null) {
if (s == null) {
states.Clear();
s = RootState;
}
AddState(s);
foreach (var c in s.Children.Values)
Expand(c);
}
public void AddState(ContainerState s) {
states[s.Container] = s;
s.Bus = this;
}
/*
public void AddChildState(EventContainer p, EventContainer c) {
if (!states.ContainsKey(p)) AddChildState(prototype.states[p].Parent.Container, p);
if (!states.ContainsKey(c)) AddState(states[p].GetChild(c));
// if (prototype != null) prototype.states[c].CopyTo(RootState.CloneType, states[c]);
}*/
void EnsureActivity(EventContainer c) {
if (activeContainers.Contains(c)) return;
if (RootState.CloneType >= 2) prototype.states[c].CopyTo(RootState.CloneType, states[c]);
activeContainers.Add(c);
}
void AttachBus() {
foreach (var s in states.Values)
s.Bus = this;
}
public void AttachSystems(PdtSkin skin, Judge judge) {
foreach (var s in states.Values)
s.AttachSystems(skin, judge);
}
readonly List<StampedEvent> patch = new List<StampedEvent>();
public void IssuePatch(IEnumerable<StampedEvent> l) {
patch.AddRange(l);
}
public void DoPatch() {
foreach (var ev in patch) {
var batch = new EventBatch(ev.Time);
var batchIndex = events.BinarySearch(batch);
if (batchIndex >= 0) batch = events[batchIndex];
else events.Insert(~batchIndex, batch);
batch.Add(ev);
}
patch.Clear();
}
public override void ForwardOnceToTime(float toTime, Action<EventBatch> callback = null) {
if (EventId < events.Count && events[EventId].Time <= toTime) {
Time = events[EventId].Time;
var batch = events[EventId];
foreach (var s in workingStates) s.Handle(null);
ValidateStates();
for (var i = 0; i < batch.Count; i++) {
var ev = batch[i];
if (ev.Container != null) {
/* if (prototype != null && !states.ContainsKey(ev.Container))
AddChildState(prototype.states[ev.Container].Parent.Container, ev.Container); */
// TODO
// if (prototype != null) prototype.states[ev.Container].CopyTo(RootState.CloneType, states[ev.Container]);
EnsureActivity(ev.Container);
states[ev.Container].Handle(ev);
}
if (ev.Unstamped is EventContainer) {
if (ev.Container != null) EnsureActivity((EventContainer)ev.Unstamped);
// AddChildState(ev.Container, (EventContainer)ev.Unstamped);
}
}
ValidateStates();
EventId++;
}
else {
Time = toTime;
foreach (var s in workingStates) s.Handle(null);
ValidateStates();
}
}
private void ValidateStates() {
foreach (var s in invalidatedStates)
if (s.Working && !workingStates.Contains(s)) workingStates.Add(s);
else if (!s.Working && workingStates.Contains(s)) workingStates.Remove(s);
invalidatedStates.Clear();
}
public void BroadcastInit() {
RootState.BroadcastInit();
}
public void BroadcastEndUpdate() {
RootState.BroadcastEndUpdate();
}
public void Anchor() {
RootState.Anchor();
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 61741923e2c1d9c43b2d1b457a54ed4c
timeCreated: 1617701716
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,39 @@
using Cryville.Common.Buffers;
using System.Collections.Generic;
namespace Cryville.Crtr.Event {
internal class RMVPool {
private class Bucket : ObjectPool<RealtimeMotionValue> {
MotionRegistry _reg;
public Bucket(string name, int capacity) : base(capacity) {
_reg = ChartPlayer.motionRegistry[name];
}
protected override RealtimeMotionValue Construct() {
return new RealtimeMotionValue().Init(_reg.InitValue);
}
}
static Dictionary<string, Bucket> _buckets;
public static void Prepare() {
_buckets = new Dictionary<string, Bucket>(ChartPlayer.motionRegistry.Count);
foreach (var reg in ChartPlayer.motionRegistry)
_buckets.Add(reg.Key, new Bucket(reg.Key, 4096));
}
Dictionary<RealtimeMotionValue, string> _rented = new Dictionary<RealtimeMotionValue, string>();
public RealtimeMotionValue Rent(MotionName name) {
var n = name.MainName;
var obj = _buckets[n].Rent();
_rented.Add(obj, n);
return obj;
}
public void Return(RealtimeMotionValue obj) {
_buckets[_rented[obj]].Return(obj);
_rented.Remove(obj);
}
public void ReturnAll() {
foreach (var obj in _rented)
_buckets[obj.Value].Return(obj.Key);
_rented.Clear();
}
}
}

View File

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

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 8e2ddc61234cc7a46918e4ae935dc314
folderAsset: yes
timeCreated: 1637936544
licenseType: Free
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: dfd44d1c0681e4842a1f031556519042
folderAsset: yes
timeCreated: 1637936550
licenseType: Free
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,243 @@
using Cryville.Crtr.Browsing;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace Cryville.Crtr.Extensions.Malody {
public class MalodyChartConverter : ResourceConverter {
static readonly string[] SUPPORTED_FORMATS = { ".mc", ".mcz" };
static readonly string[] MODES = { "key", "step", "dj", "catch", "pad", "taiko", "ring", "slide", "live" };
public override string[] GetSupportedFormats() {
return SUPPORTED_FORMATS;
}
public override IEnumerable<Resource> ConvertFrom(FileInfo file) {
List<Resource> result = new List<Resource>();
MalodyChart src;
using (var reader = new StreamReader(file.FullName)) {
src = JsonConvert.DeserializeObject<MalodyChart>(reader.ReadToEnd());
}
if (src.meta.mode != 0) throw new NotImplementedException("The chart mode is not supported");
ChartMeta meta = new ChartMeta() {
song = new ChartMeta.MetaInfo() {
name = src.meta.song.titleorg != null ? src.meta.song.titleorg : src.meta.song.title,
author = src.meta.song.artistorg != null ? src.meta.song.artistorg : src.meta.song.artist,
},
ruleset = "malody!" + MODES[src.meta.mode],
};
Chart chart = new Chart {
format = 1,
time = new BeatTime(-4, 0, 1),
ruleset = "malody!" + MODES[src.meta.mode],
sigs = new List<Chart.Signature>(),
sounds = new List<Chart.Sound>(),
motions = new List<Chart.Motion>(),
groups = new List<Chart.Group>(),
};
var group = new Chart.Group() {
tracks = new List<Chart.Track>(),
notes = new List<Chart.Note>(),
motions = new List<Chart.Motion> {
new Chart.Motion() { motion = "dir#0:-50,," },
new Chart.Motion() { motion = "dist:5h" },
new Chart.Motion() { motion = "visible:1" },
},
};
chart.groups.Add(group);
int col = src.meta.mode_ext.column;
for (int i = 0; i < col; i++) {
group.tracks.Add(new Chart.Track {
motions = new List<Chart.Motion> {
new Chart.Motion() { motion = "pt:" + ((i + 0.5) / col * 0.9 - 0.45).ToString() + "w,-.35h" },
},
});
}
IEnumerable<MalodyChart.IEvent> events = src.time.Cast<MalodyChart.IEvent>();
if (src.effect != null) events = events.Concat(src.effect.Cast<MalodyChart.IEvent>());
events = events.Concat(src.note.Cast<MalodyChart.IEvent>());
List<MalodyChart.IEvent> endEvents = new List<MalodyChart.IEvent>();
foreach (var ev in events)
if (ev.endbeat != null)
endEvents.Add(new MalodyChart.EndEvent {
beat = ev.endbeat,
StartEvent = ev,
});
events = events.Concat(endEvents)
.OrderBy(e => e.beat[0] + (float)e.beat[1] / e.beat[2])
.ThenBy(e => e.Priority);
Dictionary<MalodyChart.IEvent, StartEventState> longEvents
= new Dictionary<MalodyChart.IEvent, StartEventState>();
float? baseBpm = null;
float pbeat = 0f, ctime = 0f;
int[] endbeat = new int[] { 0, 0, 1 };
foreach (var ev in events) {
float cbeat = bp(ev.beat);
ctime += baseBpm == null ? 0 : (cbeat - pbeat) / baseBpm.Value * 60f;
pbeat = cbeat;
if (ev is MalodyChart.Time) {
var tev = (MalodyChart.Time)ev;
if (baseBpm == null) baseBpm = tev.bpm;
chart.sigs.Add(new Chart.Signature {
time = new BeatTime(ev.beat[0], ev.beat[1], ev.beat[2]),
tempo = tev.bpm,
});
chart.motions.Add(new Chart.Motion {
time = new BeatTime(ev.beat[0], ev.beat[1], ev.beat[2]),
motion = "svm:" + (tev.bpm / baseBpm).ToString()
});
}
else if (ev is MalodyChart.Effect) {
var tev = (MalodyChart.Effect)ev;
if (tev.scroll != null) group.motions.Add(new Chart.Motion {
time = new BeatTime(ev.beat[0], ev.beat[1], ev.beat[2]),
motion = "svm:" + tev.scroll.ToString()
});
}
else if (ev is MalodyChart.Note) {
var tev = (MalodyChart.Note)ev;
if (tev.type == 1) {
if (tev.beat[0] == 0 && tev.beat[1] == 0) {
result.Add(new SongResource(meta.song.name, new FileInfo(file.DirectoryName + "/" + tev.sound)));
chart.sounds.Add(new Chart.Sound {
time = new BeatTime(0, 0, 1),
id = meta.song.name,
offset = -tev.offset / 1000f,
});
}
else throw new NotImplementedException();
}
else {
if (bp(tev.beat) > bp(endbeat)) endbeat = tev.beat;
var rn = new Chart.Note() {
time = new BeatTime(tev.beat[0], tev.beat[1], tev.beat[2]),
judge = "normal",
motions = new List<Chart.Motion> {
new Chart.Motion() { motion = "track:" + tev.column.ToString() }
},
};
if (tev.endbeat != null) {
if (bp(tev.endbeat) > bp(endbeat)) endbeat = tev.endbeat;
rn.endtime = new BeatTime(tev.endbeat[0], tev.endbeat[1], tev.endbeat[2]);
rn.endjudge = "longend";
longEvents.Add(ev, new StartEventState {
Destination = rn,
Time = ctime,
});
}
group.notes.Add(rn);
}
}
else if (ev is MalodyChart.EndEvent) {
var tev = (MalodyChart.EndEvent)ev;
if (tev.StartEvent is MalodyChart.Note) {
var sev = tev.StartEvent;
var state = longEvents[sev];
var dest = (Chart.Note)state.Destination;
dest.motions.Add(new Chart.Motion() {
time = new BeatTime(sev.beat[0], sev.beat[1], sev.beat[2]),
endtime = new BeatTime(ev.beat[0], ev.beat[1], ev.beat[2]),
motion = "judge!long:" + ((ctime - state.Time) * 20).ToString(),
});
longEvents.Remove(sev);
}
else throw new NotSupportedException();
}
else throw new NotSupportedException();
}
chart.endtime = new BeatTime(endbeat[0] + 4, endbeat[1], endbeat[2]);
meta.chart = new ChartMeta.MetaInfo() {
name = src.meta.version,
author = src.meta.creator,
length = ctime,
};
meta.note_count = group.notes.Count;
string chartName = string.Format("{0} - {1}", meta.song.name, meta.chart.name);
result.Add(new ChartResource(chartName, chart, meta));
if (src.meta.background != null)
result.Add(new CoverResource(chartName, new FileInfo(file.DirectoryName + "/" + src.meta.background)));
return result;
}
struct StartEventState {
public float Time { get; set; }
public ChartEvent Destination { get; set; }
}
float bp(int[] beat) {
return beat[0] + (float)beat[1] / beat[2];
}
}
#pragma warning disable IDE1006
public struct MalodyChart {
public interface IEvent {
int[] beat { get; set; }
int[] endbeat { get; set; }
int Priority { get; }
}
public struct EndEvent : IEvent {
public int[] beat { get; set; }
public int[] endbeat { get; set; }
public IEvent StartEvent { get; set; }
public int Priority { get { return StartEvent.Priority - 1; } }
}
public Meta meta;
public struct Meta {
public SongInfo song;
public struct SongInfo {
public string title;
public string artist;
public string titleorg;
public string artistorg;
}
public string background;
public string creator;
public string version;
public int mode;
public ModeExt mode_ext;
public struct ModeExt {
public int column;
}
}
public List<Time> time;
public struct Time : IEvent {
public int[] beat { get; set; }
public int[] endbeat { get; set; }
public float bpm;
public int Priority { get { return -2; } }
}
public List<Effect> effect;
public struct Effect : IEvent {
public int[] beat { get; set; }
public int[] endbeat { get; set; }
public float? scroll;
public int Priority { get { return 0; } }
}
public List<Note> note;
public struct Note : IEvent {
public int[] beat { get; set; }
public int[] endbeat { get; set; }
public int column;
public string sound;
public int offset;
public int type;
public int Priority { get { return 0; } }
}
}
#pragma warning restore IDE1006
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: b3624013a6911ba45933085332724ff1
timeCreated: 1637936498
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,191 @@
using Cryville.Audio;
using Cryville.Audio.Source;
using Cryville.Common;
using Cryville.Common.Unity;
using Cryville.Common.Unity.Input;
using FFmpeg.AutoGen;
using Ionic.Zip;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using Logger = Cryville.Common.Logger;
#if UNITY_ANDROID
using AOT;
#endif
namespace Cryville.Crtr {
public static class Game {
public static string GameDataPath {
get;
private set;
}
public readonly static string FileProtocolPrefix
#if UNITY_STANDALONE_WIN
= "file:///";
#elif UNITY_ANDROID
= "file://";
#else
#error No file protocol prefix is defined.
#endif
public static IAudioDeviceManager AudioManager;
public static AudioClient AudioClient;
public static SimpleSequencerSource AudioSequencer;
public static SimpleSequencerSession AudioSession;
public static InputManager InputManager;
public readonly static NetworkTaskWorker NetworkTaskWorker = new NetworkTaskWorker();
public readonly static JsonSerializerSettings GlobalJsonSerializerSettings
= new JsonSerializerSettings() {
DefaultValueHandling = DefaultValueHandling.Ignore,
};
public static BufferedLogger MainLogger { get; private set; }
static bool _init;
public static void Init() {
if (_init) return;
_init = true;
bool _bcflag = new Version(Settings.Default.LastRunVersion) < new Version("0.4");
if (_bcflag) Settings.Default.Reset();
Logger.SetLogPath(Settings.Default.GameDataPath + "/logs");
MainLogger = new BufferedLogger();
Application.logMessageReceivedThreaded += OnLog;
Logger.Create("main", MainLogger);
if (_bcflag) Logger.Log("main", 2, "Game", "Reset all settings");
GameDataPath = Settings.Default.GameDataPath;
Input.simulateMouseWithTouches = false;
InputManager = new InputManager();
#if UNITY_EDITOR_WIN
ffmpeg.RootPath = Application.dataPath + "/Plugins/Windows";
#elif UNITY_STANDALONE_WIN
ffmpeg.RootPath = Application.dataPath + "/Plugins/x86_64";
#elif UNITY_ANDROID
ffmpeg.RootPath = "";
#else
#error No FFmpeg search path.
#endif
#if UNITY_ANDROID
Cryville.Audio.OpenSL.OutputClient.CallbackFunction = audioCallback;
#endif
AudioManager = EngineBuilder.Create();
Logger.Log("main", 1, "Audio", "Using audio API: {0}", AudioManager.GetType().Namespace);
AudioClient = AudioManager.GetDefaultDevice(DataFlow.Out).Connect();
AudioClient.Init(AudioClient.DefaultFormat);
AudioClient.Source = AudioSequencer = new SimpleSequencerSource();
AudioSession = AudioSequencer.NewSession();
AudioSequencer.Playing = true;
AudioClient.Start();
ChartPlayer.motionRegistry = new Dictionary<string, MotionRegistry> {
{ "dir" , new MotionRegistry(typeof(Vec3)) },
{ "normal" , new MotionRegistry(typeof(Vec3)) },
// { "pdirz", new MotionRegistry(typeof(Vec1)) },
{ "pt" , new MotionRegistry(typeof(VecPt)) },
{ "visible", new MotionRegistry(typeof(VecI1)) },
{ "sv" , new MotionRegistry(new VecPtComp(0f, 0f), new VecPtComp(0f, 1f)) },
{ "svm" , new MotionRegistry(new Vec1m(1f)) },
{ "dist" , new MotionRegistry(new VecPtComp(0f, 0f), new VecPtComp(0f, float.PositiveInfinity)) },
{ "corner" , new MotionRegistry(typeof(VecI1)) },
{ "ctrl0" , new MotionRegistry(typeof(VecCtrl)) },
{ "ctrl1" , new MotionRegistry(typeof(VecCtrl)) },
{ "track" , new MotionRegistry(typeof(Vec1)) },
{ "judge" , new MotionRegistry(typeof(Vec1)) },
{ "width" , new MotionRegistry(new Vec1(0), new Vec1(1)) },
};
var dir = new DirectoryInfo(Settings.Default.GameDataPath + "/charts");
if (!dir.Exists || Settings.Default.LastRunVersion != Application.version) {
Directory.CreateDirectory(dir.FullName);
var defaultData = Resources.Load<TextAsset>("default");
using (var zip = ZipFile.Read(defaultData.bytes)) {
zip.ExtractExistingFile = ExtractExistingFileAction.OverwriteSilently;
zip.ExtractAll(Settings.Default.GameDataPath);
}
}
Settings.Default.LastRunVersion = Application.version;
Settings.Default.Save();
// TODO Remove test log
/*Logger.Log("main", 0, "Game", "Installed fonts:");
foreach (var f in Font.GetOSInstalledFontNames()) {
Logger.Log("main", 0, "Game", " {0}", f);
}*/
Logger.Log("main", 1, "Game", "Initialized");
/*ServicePointManager.SecurityProtocol
= SecurityProtocolType.Ssl3
| SecurityProtocolType.Tls
| SecurityProtocolTypeExtensions.Tls11
| SecurityProtocolTypeExtensions.Tls12
| SecurityProtocolTypeExtensions.Tls13
;
ServicePointManager.ServerCertificateValidationCallback = certValidCallback;*/
}
/*static bool certValidCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) {
return true;
}*/
#if UNITY_ANDROID
[MonoPInvokeCallback(typeof(OpenSL.Native.slBufferQueueCallback))]
static void audioCallback(IntPtr caller, IntPtr context) {
Cryville.Audio.OpenSL.OutputClient.Callback(caller, context);
}
#endif
static bool _shutdown;
public static void Shutdown() {
if (_shutdown) return;
_shutdown = true;
Logger.Log("main", 1, "Game", "Shutting down");
try {
AudioSequencer.Dispose();
AudioClient.Dispose();
AudioManager.Dispose();
}
catch (Exception ex) {
LogException("Game", "An error occured while shutting down", ex);
}
finally {
Logger.Close();
}
}
public static DirectoryInfo[] GetDatabaseList() {
return new DirectoryInfo(GameDataPath + "/db").GetDirectories();
}
public static void ConnectDatabase(string name) {
}
public static void DisconnectDatabase() {
}
public static void LogException(string module, string prefix, Exception ex) {
Logger.Log("main", 4, module, "{0}: {1}", prefix, ex);
}
static void OnLog(string condition, string stackTrace, LogType type) {
int l;
switch (type) {
case LogType.Log: l = 1; break;
case LogType.Assert: l = 2; break;
case LogType.Warning: l = 3; break;
case LogType.Error:
case LogType.Exception: l = 4; break;
default: l = 1; break;
}
Logger.Log("main", l, "Internal", "{0}\n{1}", condition, stackTrace);
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 0c36243a1857ce046a20132c27849902
timeCreated: 1620727037
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,38 @@
using Cryville.Crtr.Components;
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Cryville.Crtr {
public static class GenericResources {
public static Dictionary<string, Type> Components
= new Dictionary<string, Type>();
public static Dictionary<string, Shader> Shaders
= new Dictionary<string, Shader>();
public static Dictionary<string, Mesh> Meshes
= new Dictionary<string, Mesh>();
public static Dictionary<string, Material> Materials
= new Dictionary<string, Material>();
static bool loaded;
public static void LoadDefault() {
if (loaded) return;
Components.Add("image", typeof(SpritePlane));
Components.Add("polysec", typeof(PolygonSGO));
Components.Add("rect", typeof(SpriteRect));
Components.Add("scale3", typeof(SpriteScale3));
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"));
Materials.Add("-CutoutMat", Resources.Load<Material>("CutoutMat"));
Materials.Add("-TransparentMat", Resources.Load<Material>("TransparentMat"));
loaded = true;
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 897359624d6b1394b8c301647647a96b
timeCreated: 1609581468
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,172 @@
using Cryville.Common.Math;
using Cryville.Crtr.Event;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace Cryville.Crtr {
class GroupHandler : ContainerHandler {
// private StampedState cs;
public ChartHandler ch;
// Chart.Group group;
// Dictionary<StampedEvent, GameObject> notePool = new Dictionary<StampedEvent, GameObject>();
SquareMatrix matFrame;
List<ContainerState> tracks;
public GroupHandler(Chart.Group tg, ChartHandler ch) : base() {
//group = tg;
this.ch = ch;
/*foreach (Chart.Track t in group.tracks) {
handlers.Add(new TrackHandler(t, this));
}*/
}
public override string TypeName {
get {
return "group";
}
}
public override void PreInit() {
base.PreInit();
tracks = (
from c in cs.Children
where c.Value.Container is Chart.Track
select c.Value
).ToList();
matFrame = SquareMatrix.WithPolynomialCoefficients(tracks.Count);
}
/*EventPrehandler ph;
List<StampedEvent> sevs = new List<StampedEvent>();
public void StartPrehandler(EventPrehandler parent) {
/*List<Chart.Event> appevs = new List<Chart.Event>();
foreach (Chart.Note ev in group.notes) {
if (ev.duration > 0) {
for (float b = 0f; b < ev.duration; b += ev.jdg_interval) {
appevs.Add(new Chart.InternalJudgement() { beat = ev.beat, BeatOffset = b, Parent = ev });
}
}
}
ph = new EventPrehandler(
parent.chart,
group.motions.Cast<Chart.Event>()
.Concat<Chart.Event>(group.notes.Cast<Chart.Event>()),
parent
);
foreach (TrackHandler h in handlers)
h.StartPrehandler(ph);
}
public void PrehandleToTime(float toTime) {
ph.ForwardToTime(toTime, ev => {
foreach (var h in handlers) h.PrehandleToTime(ph.Time);
/*
if (ev is Chart.Note) {
var tev = (Chart.Note)ev;
sevs.Add(new StampedEvent.Judge() {
Time = phs.Time - Main.judge * tev.tol,
EndTime = phs.Time + Main.judge * tev.tol,
Event = tev,
Type = tev.wipe ? JudgementType.Held : JudgementType.Attack,
JudgeArea = new Area() {
Point1 = phs.Point,
Point2 = phs.Point + new Chart.Point(0f, 0.1f, 0f, 0.1f).ToRelative(Main.hitRect),
Type = AreaType.Circle
}
});
}
else if (ev is Chart.InternalJudgement) {
var tev = (Chart.InternalJudgement)ev;
sevs.Add(new StampedEvent.Judge() {
Time = phs.Time - Main.judge * tev.Parent.tol,
EndTime = phs.Time + Main.judge * tev.Parent.tol,
Event = tev,
Type = JudgementType.Held,
JudgeArea = new Area() {
Point1 = phs.Point,
Point2 = phs.Point + new Chart.Point(0f, 0.1f, 0f, 0.1f).ToRelative(Main.hitRect),
Type = AreaType.Circle
}
});
}
});
}
public void EndPrehandler(StampedState parent) {
sevs = ph.Result;
cs = new StampedState(ch.chart, sevs, parent);
foreach (var h in handlers) h.EndPrehandler(cs);
}*/
/*List<StampedEvent.Judge> judgements = new List<StampedEvent.Judge>();
public void SendInput(int id, TouchPhase phase, Vector2 jpos) {
for (int i = judgements.Count - 1; i >= 0; i--) {
if (judgements[i].JudgeArea.Contains(jpos)) {
if (phase == TouchPhase.Began && judgements[i].Type == JudgementType.Attack) {
ch.ReportJudge(true);
judgements.RemoveAt(i);
}
else if ((phase == TouchPhase.Stationary || phase == TouchPhase.Moved) && judgements[i].Type == JudgementType.Held) {
ch.ReportJudge(true);
judgements.RemoveAt(i);
}
}
}
}*/
/*Vector3 cpoint;
Vector3 cpoint2;
Vector3 prevp = Vector3.zero;
Vector3 prevwp = Vector3.zero;
Vector3 prevp2 = Vector3.zero;
Vector3 prevwp2 = Vector3.zero;*/
public override void Update(ContainerState s, StampedEvent ev) {
base.Update(s, ev);
/*cs.ForwardToTime(toTime);
foreach (var handler in handlers) handler.Update(cs.Time);*/
//cs.ForwardToTime(toTime);
/*ss.ForwardToTime(toTime, ev => {
if (ev is StampedEvent.Judge) {
var tev = (StampedEvent.Judge)ev;
judgements.Add(tev);
}
});
for (int i = judgements.Count - 1; i >= 0; i--) {
if (judgements[i].EndTime < cs.Time) {
ch.ReportJudge(false);
judgements.RemoveAt(i);
}
}*/
// gogroup.rotation = Quaternion.Euler(cs.Direction);
}
public override void EndUpdate(ContainerState s) {
base.EndUpdate(s);
}
public ColumnVector<Vector3> GetCurrentFrame(Func<ContainerState, Vector3> func) {
var vl = from t in tracks select func(t);
return matFrame.Eliminate(
new ColumnVector<Vector3>(vl.ToArray()),
new Vector3Operator()
);
}
}
class Vector3Operator : IVectorOperator<Vector3> {
public Vector3 Add(Vector3 lhs, Vector3 rhs) {
return lhs + rhs;
}
public Vector3 ScalarMultiply(float lhs, Vector3 rhs) {
return lhs * rhs;
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 1d6ad7170a6c76248a8ec305e98a75b2
timeCreated: 1599459182
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,135 @@
using Cryville.Common.Unity.Input;
using System;
using System.Collections.Generic;
namespace Cryville.Crtr {
public class InputProxy {
readonly PdtRuleset _ruleset;
readonly Dictionary<string, InputProxyEntry> _hash1 = new Dictionary<string, InputProxyEntry>();
readonly Dictionary<InputSource, InputProxyEntry> _hash2 = new Dictionary<InputSource, InputProxyEntry>();
readonly Dictionary<string, int> _use = new Dictionary<string, int>();
readonly Dictionary<string, List<string>> _rev = new Dictionary<string, List<string>>();
public event EventHandler<ProxyChangedEventArgs> ProxyChanged;
public InputProxy(PdtRuleset ruleset) {
_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);
}
}
}
public void Set(InputProxyEntry proxy) {
var name = proxy.Target;
if (_use[name] > 0)
throw new InvalidOperationException("Input already assigned");
_hash1.Add(proxy.Target, proxy);
_hash2.Add(proxy.Source, proxy);
if (proxy != null) {
IncrementUseRecursive(name);
IncrementReversedUseRecursive(name);
}
else {
DecrementUseRecursive(name);
DecrementReversedUseRecursive(name);
}
}
void IncrementUseRecursive(string name) {
_use[name]++;
BroadcastProxyChanged(name);
var passes = _ruleset.inputs[name].pass;
if (passes != null) {
foreach (var p in _ruleset.inputs[name].pass)
IncrementUseRecursive(p.Key);
}
}
void IncrementReversedUseRecursive(string name) {
foreach (var p in _rev[name]) {
_use[name]++;
BroadcastProxyChanged(name);
IncrementReversedUseRecursive(p);
}
}
void DecrementUseRecursive(string name) {
_use[name]--;
BroadcastProxyChanged(name);
var passes = _ruleset.inputs[name].pass;
if (passes != null) {
foreach (var p in _ruleset.inputs[name].pass)
DecrementUseRecursive(p.Key);
}
}
void DecrementReversedUseRecursive(string name) {
foreach (var p in _rev[name]) {
_use[name]--;
BroadcastProxyChanged(name);
DecrementReversedUseRecursive(p);
}
}
void BroadcastProxyChanged(string name) {
ProxyChanged(this, new ProxyChangedEventArgs(name, _hash1[name].Source, _use[name] > 0));
}
}
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; }
}
public sealed class InputProxyHandler : InputHandler {
InputDefinition _def;
public InputProxyHandler(InputDefinition def, InputHandler src) : base() {
_def = def;
src.Callback = OnInput;
}
public override void Activate() {
throw new NotImplementedException();
}
public override void Deactivate() {
throw new NotImplementedException();
}
public override void Dispose(bool disposing) {
throw new NotImplementedException();
}
public override bool IsNullable(int type) {
throw new NotImplementedException();
}
public override byte GetDimension(int type) {
throw new NotImplementedException();
}
public override string GetTypeName(int type) {
throw new NotImplementedException();
}
public override double GetCurrentTimestamp() {
throw new NotImplementedException();
}
void OnInput(InputIdentifier id, InputVector vec) {
}
}
}

View File

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

View File

@@ -0,0 +1,731 @@
using Cryville.Common.Pdt;
using Cryville.Common.Unity.Input;
using System.Collections.Generic;
namespace Cryville.Crtr {
#region Obsolete
#if false
[Obsolete]
public class Judge {
/// <summary>
/// The computed positions of the notes.
/// </summary>
readonly Dictionary<StampedEvent.Judge, Vector2> pos
= new Dictionary<StampedEvent.Judge, Vector2>();
struct ActiveJudge : IEquatable<ActiveJudge> {
public StampedEvent.Judge Event;
public NoteHandler NoteHandler;
public bool Equals(ActiveJudge other) {
return Event == other.Event;
}
public override int GetHashCode() {
return Event.GetHashCode();
}
public ActiveJudge(StampedEvent.Judge ev, NoteHandler noteHandler) {
Event = ev; NoteHandler = noteHandler;
}
}
struct JudgeIdentifier : IEquatable<JudgeIdentifier> {
public NoteHandler NoteHandler { get; private set; }
public Chart.Note Note { get { return NoteHandler.Event; } }
public PrimaryJudge TargetJudge { get; private set; }
public int Layer { get { return TargetJudge.layer; } }
public override bool Equals(object obj) {
if (!(obj is JudgeIdentifier)) return false;
return Equals((JudgeIdentifier)obj);
}
public bool Equals(JudgeIdentifier other) {
return NoteHandler.Equals(other.NoteHandler) && Layer == other.Layer;
}
public override int GetHashCode() {
return NoteHandler.GetHashCode() ^ Layer;
}
public JudgeIdentifier(NoteHandler n, PrimaryJudge j) {
NoteHandler = n; TargetJudge = j;
}
}
struct JudgeEventIdentifier {
public JudgeIdentifier JudgeIdentifier { get; private set; }
public StampedEvent.Judge Event { get; private set; }
public JudgeEventIdentifier(JudgeIdentifier jid, StampedEvent.Judge ev) {
JudgeIdentifier = jid;
Event = ev;
}
}
readonly Dictionary<JudgeIdentifier, JudgeState> stateList = new Dictionary<JudgeIdentifier, JudgeState>();
readonly List<JudgeIdentifier> activeList = new List<JudgeIdentifier>();
readonly Dictionary<JudgeIdentifier, List<StampedEvent.Judge>> activeEvents = new Dictionary<JudgeIdentifier, List<StampedEvent.Judge>>();
readonly Dictionary<JudgeIdentifier, PrimaryJudge> immList = new Dictionary<JudgeIdentifier, PrimaryJudge>();
readonly List<StampedEvent.Judge> hitList = new List<StampedEvent.Judge>();
readonly List<JudgeEventIdentifier> missList = new List<JudgeEventIdentifier>();
readonly List<NoteHandler> deactivateList = new List<NoteHandler>();
readonly Dictionary<int, PointerInfo> ptr = new Dictionary<int, PointerInfo>();
readonly List<int> invalidatedPtr = new List<int>();
class JudgeState {
/// <summary>
/// The ID of the pointers currently holding on the note, the first of which is the main pointer.
/// </summary>
public readonly List<int> PointerIds = new List<int>();
/// <summary>
/// The ID of the pointers currently positioned on the note, but not sliding in nor holding down.
/// </summary>
public readonly List<int> NotOwnedPointerIds = new List<int>();
public Vector2 Position;
public Vector2 ImmediatePosition;
}
public readonly Dictionary<string, float> scores = new Dictionary<string, float>();
readonly CompiledRuleset ruleset;
public Judge(CompiledRuleset r) {
ruleset = r;
foreach (var s in r.scores)
scores.Add(s.Key, s.Value.init);
}
public void RecordPos(StampedEvent.Judge ev, Vector2 pt) { pos[ev] = pt; }
internal void Issue(StampedEvent.Judge ev, NoteHandler nh) {
// Logger.Log("main", 0, "Judge", "Issue: {0} {1} {2}", ev.Time, ev.Container.GetHashCode(), ruleset.primary_judges.First(i => i.Value == ev.TargetJudge).Key);
// var u = new ActiveJudge(ev, nh);
/*if (ev.TargetJudge.PassCh.ContainsKey("br"))
Logger.Log("main", 0, "Judge", "{0}", ev.StartEvent == null);*/
if (ev.StartEvent != null) {
var jid = new JudgeIdentifier(nh, ev.StartEvent.TargetJudge);
int i = activeList.IndexOf(jid);
if (i >= 0) missList.Add(new JudgeEventIdentifier(jid, ev.StartEvent));
}
else {
var jid = new JudgeIdentifier(nh, ev.TargetJudge);
if (!activeList.Contains(jid)) {
var i = activeList.FindLastIndex(j => j.TargetJudge.priority <= ev.TargetJudge.priority);
activeList.Insert(i + 1, jid);
}
if (!activeEvents.ContainsKey(jid)) activeEvents.Add(jid, new List<StampedEvent.Judge> { ev });
else activeEvents[jid].Add(ev);
if (!stateList.ContainsKey(jid)) {
stateList.Add(jid, CreateJudgeState(ev.TargetJudge, pos[ev]));
}
stateList[jid].Position = pos[ev];
}
}
internal void IssueImmediate(NoteHandler nh, string pjn, Vector2 pt) {
var key = new JudgeIdentifier(nh, ruleset.primary_judges[pjn]);
if (!immList.ContainsKey(key)) immList.Add(key, ruleset.primary_judges[pjn]);
if (!stateList.ContainsKey(key)) {
stateList.Add(key, CreateJudgeState(ruleset.primary_judges[pjn], pt));
}
stateList[key].ImmediatePosition = pt;
}
JudgeState CreateJudgeState(PrimaryJudge judge, Vector2 pt) {
var state = new JudgeState();
var etor = new Evaluator();
foreach (var p in ptr) {
var info = p.Value;
var wp = ScreenToWorldPoint(info.Position);
etor.Context = new EvaluatorContext {
Extra = new Dictionary<string, object> {
{ "npos", pt },
{ "-hitpos", wp }
}
};
if (MatchArea(judge.PassCh.Values.First().area, etor))
state.NotOwnedPointerIds.Add(info.Id);
}
return state;
}
Vector2 ScreenToWorldPoint(Vector2 pp) {
Vector3 sp = pp;
sp.y = Screen.height - sp.y;
sp.z = -Camera.main.transform.position.z;
return Camera.main.ScreenToWorldPoint(sp);
}
public void NewFrame() {
ptr.Clear();
}
public void Feed(PointerInfo info) {
var etor = new Evaluator();
var wp = ScreenToWorldPoint(info.Position);
foreach (var u in activeList) {
foreach (var j in activeEvents[u]) {
var t = j.NoteTime;
var deltat = info.Time - t;
var pj = j.TargetJudge;
etor.Context = new EvaluatorContext() {
Extra = new Dictionary<string, object>() {
{ "npos", pos[j] },
{ "-hitpos", wp }
}
};
foreach (var sj in pj.PassCh) {
var flag = false;
if (!MatchSecondaryJudge(u.NoteHandler, info.Id, stateList[u], sj.Value, j.IsEndJudge, info, deltat, wp, etor))
continue;
foreach (var tj in sj.Value.PassCh) {
if (!MatchTertiaryJudge(tj.Value, deltat, wp, etor))
continue;
// TODO Fire hit input
foreach (var s in tj.Value.scores)
UpdateScore(s.Key, s.Value);
Logger.Log("main", 0, "Judge", "Hit F: {0} {1}", sj.Key, tj.Key);
hitList.Add(j);
flag = true; break;
}
if (flag) break;
}
}
FlushHitList(u);
}
FlushDeactivateList();
foreach (var u in immList) {
var pj = u.Value;
etor.Context = new EvaluatorContext() {
Extra = new Dictionary<string, object>() {
{ "-hitpos", wp }
}
};
foreach (var sj in pj.PassCh) {
if (!MatchSecondaryJudge(u.Key.NoteHandler, info.Id, stateList[u.Key], sj.Value, false, info, 0, wp, etor, true))
continue;
if (MatchImmJudgeSubProcess(u.Key.NoteHandler, info.Id, sj.Key, sj.Value, sj.Value.type.ToString(), false, 0, wp, etor))
break;
}
}
}
public void Update(PointerInfo info) {
var etor = new Evaluator();
var wp = ScreenToWorldPoint(info.Position);
foreach (var u in activeList) {
foreach (var j in activeEvents[u]) {
var t = j.NoteTime;
var deltat = info.Time - t;
var pj = j.TargetJudge;
etor.Context = new EvaluatorContext() {
Extra = new Dictionary<string, object>() {
{ "npos", pos[j] },
{ "-hitpos", wp }
}
};
foreach (var sj in pj.PassCh) {
var flag = false;
if (!MatchSecondaryActiveJudge(u.NoteHandler, info.Id, stateList[u], sj.Value, j.IsEndJudge, info, deltat, wp, etor))
continue;
foreach (var tj in sj.Value.PassCh) {
if (!MatchTertiaryJudge(tj.Value, deltat, wp, etor))
continue;
// TODO Fire hit input
foreach (var s in tj.Value.scores)
UpdateScore(s.Key, s.Value);
Logger.Log("main", 0, "Judge", "Hit U: {0} {1}", sj.Key, tj.Key);
hitList.Add(j);
flag = true; break;
}
if (flag) break;
}
}
FlushHitList(u);
}
FlushDeactivateList();
if (!invalidatedPtr.Contains(info.Id)) ptr[info.Id] = info;
}
public void Trash(double time) {
var etor = new Evaluator();
foreach (var u in activeList) {
foreach (var j in activeEvents[u]) {
if (MatchImmJudge(u.NoteHandler, j.TargetJudge, j.IsEndJudge, time - j.NoteTime, stateList[u], etor))
hitList.Add(j);
}
// Logger.Log("main", 0, "Judge", "Active Events: {0}", activeEvents[u].Count);
FlushHitList(u);
}
FlushDeactivateList();
// Logger.Log("main", 0, "Judge", "Active States: {0}", activeList.Count);
foreach (var u in missList) {
// TODO this check shouldn't be done here, instead, invalidate/compensate those already in the active events
if (!activeEvents.ContainsKey(u.JudgeIdentifier)) continue;
var evs = activeEvents[u.JudgeIdentifier];
var ev = u.Event;
if (!evs.Contains(ev)) continue;
var pj = ev.TargetJudge;
var flag = false;
foreach (var sj in pj.PassCh) {
if (!MatchSecondaryMissJudge(u.JudgeIdentifier.NoteHandler, sj.Value, etor))
continue;
foreach (var tj in sj.Value.PassCh) {
/*if (!MatchTertiaryJudge(j, tj.Value, etor))
continue;*/
foreach (var s in tj.Value.scores)
UpdateScore(s.Key, s.Value);
Logger.Log("main", 0, "Judge", "Miss: {0}", tj.Key);
flag = true; break;
}
if (flag) break;
}
if (!flag)
Logger.Log("main", 3, "Judge", "Unjudged miss");
evs.Remove(ev);
if (u.Event.IsEndJudge) deactivateList.Add(u.JudgeIdentifier.NoteHandler);
}
FlushDeactivateList();
missList.Clear();
foreach (var j in immList) {
MatchImmJudge(j.Key.NoteHandler, j.Value, false, 0, stateList[j.Key], etor);
}
/*var rmimm = new List<JudgeIdentifier>();
foreach (var i in immList) {
if (i.Value.Active) i.Value.Active = false;
else rmimm.Add(i.Key);
}
foreach (var i in rmimm) immList.Remove(i);*/
// Logger.Log("main", 0, "Judge", "Active List: {0}", activeList.Count);
immList.Clear();
}
void FlushHitList(JudgeIdentifier jid) {
if (activeEvents.ContainsKey(jid))
foreach (var j in hitList) {
activeEvents[jid].Remove(j);
// TODO items in stateList need to be destroyed
}
hitList.Clear();
}
void FlushDeactivateList() {
for (int i = activeList.Count - 1; i >= 0; i--) {
if (deactivateList.Contains(activeList[i].NoteHandler)) {
activeEvents.Remove(activeList[i]);
activeList.RemoveAt(i);
}
}
deactivateList.Clear();
}
bool MatchImmJudge(NoteHandler nh, PrimaryJudge pj, bool endjudge, double deltat, JudgeState v, Evaluator etor) {
bool flag = false;
var ptrids = new Dictionary<int, int>();
foreach (var sj in pj.PassCh) {
var wp = ScreenToWorldPoint(v.ImmediatePosition);
ptrids.Clear();
foreach (var p in ptr) {
int id = p.Key;
Vector3 sp2 = p.Value.Position;
sp2.y = Screen.height - sp2.y;
sp2.z = -Camera.main.transform.position.z;
var wp2 = (Vector2)Camera.main.ScreenToWorldPoint(sp2);
etor.Context = new EvaluatorContext() {
Extra = new Dictionary<string, object>() {
{ "npos", v.Position },
{ "-hitpos", wp2 }
}
};
if (MatchArea(sj.Value.area, etor)) {
if (v.NotOwnedPointerIds.Contains(id)) continue;
bool flag2 = !v.PointerIds.Contains(id);
if (flag2) ptrids.Add(id, 1);
if (flag) continue;
if (sj.Value.type.HasFlag(JudgeType.enterp)) {
if (v.PointerIds.Count == 0) {
flag = MatchImmJudgeSubProcess(nh, p.Key, sj.Key, sj.Value, "enterp", endjudge, deltat, wp, etor);
}
}
else if (sj.Value.type.HasFlag(JudgeType.enters)) {
if (v.PointerIds.Count > 0) {
flag = MatchImmJudgeSubProcess(nh, p.Key, sj.Key, sj.Value, "enters", endjudge, deltat, wp, etor);
}
}
if (flag && sj.Value.@override && flag2) ptrids[id] = 2;
// else if ((int)sj.Value.type >= 4096) continue;
/*if (!v.PointerIds.Contains(id)) {
// Logger.Log("main", 0, "Judge", "push {0}", id);
if (sj.Value.@override) v.PointerIds.Insert(0, id);
else v.PointerIds.Add(id);
}*/
}
else {
if (v.PointerIds.Contains(id)) ptrids.Add(id, 0);
if (v.NotOwnedPointerIds.Contains(id)) ptrids.Add(id, -1);
if (flag) continue;
if (sj.Value.type.HasFlag(JudgeType.leaveb)) {
// Logger.Log("main", 0, "Judge", "POS {0}", v.Position);
if (v.PointerIds.Count == 1 && v.PointerIds[0] == id) {
flag = MatchImmJudgeSubProcess(nh, p.Key, sj.Key, sj.Value, "leaveb", endjudge, deltat, wp, etor);
}
}
else if (sj.Value.type.HasFlag(JudgeType.leavec)) {
if (v.PointerIds.Count > 1 && v.PointerIds[0] == id) {
flag = MatchImmJudgeSubProcess(nh, p.Key, sj.Key, sj.Value, "leavec", endjudge, deltat, wp, etor);
}
}
else if (sj.Value.type.HasFlag(JudgeType.leaves)) {
if (v.PointerIds.Count > 1 && v.PointerIds.IndexOf(id) > 0) {
flag = MatchImmJudgeSubProcess(nh, p.Key, sj.Key, sj.Value, "leaves", endjudge, deltat, wp, etor);
}
}
// else if ((int)sj.Value.type >= 4096) continue;
/*if (v.PointerIds.Contains(id)) {
// Logger.Log("main", 0, "Judge", "pop {0}", id);
v.PointerIds.Remove(id);
}*/
}
}
if (flag) {
foreach (var i in ptrids) {
switch (i.Value) {
case -1: v.NotOwnedPointerIds.Remove(i.Key); break;
case 0: v.PointerIds.Remove(i.Key); break;
case 1: v.PointerIds.Add(i.Key); break;
case 2: v.PointerIds.Insert(0, i.Key); break;
}
}
// Logger.Log("main", 0, "Judge", "{0}", v.PointerIds.Count);
return true;
}
}
foreach (var i in ptrids) {
switch (i.Value) {
case -1: v.NotOwnedPointerIds.Remove(i.Key); break;
case 0: v.PointerIds.Remove(i.Key); break;
case 1: v.PointerIds.Add(i.Key); break;
case 2: v.PointerIds.Insert(0, i.Key); break;
}
}
return false;
}
bool MatchImmJudgeSubProcess(NoteHandler nh, int ptrid, string sj_name, SecondaryJudge sj, string judge_type, bool endjudge, double deltat, Vector2 wp, IEvaluator etor) {
TryInvalidate(nh, sj, ptrid);
if (endjudge) Compensate(nh);
foreach (var tj in sj.PassCh) {
if (MatchTertiaryJudge(tj.Value, deltat, wp, etor)) {
foreach (var s in tj.Value.scores)
UpdateScore(s.Key, s.Value);
Logger.Log("main", 0, "Judge", "Hit I {2}: {0} {1}", sj_name, tj.Key, judge_type);
return true;
}
}
return false;
}
void TryInvalidate(NoteHandler nh, SecondaryJudge sj, int ptrid) {
if (sj.invalidate.HasFlag(Invalidation.finger) && ptrid != -1) {
invalidatedPtr.Add(ptrid);
ptr.Remove(ptrid);
}
if (sj.invalidate.HasFlag(Invalidation.note)) {
List<StampedEvent.Judge> invalidatedList = nh.Invalidate();
// TODO also handle events in `activeEvents`
foreach (var j in invalidatedList) {
if (j.StartEvent != null) continue;
Invalidate(j);
}
deactivateList.Add(nh);
}
}
void Invalidate(StampedEvent.Judge j) {
bool flag = false;
foreach (var sj in j.TargetJudge.PassCh) {
if (!sj.Value.type.HasFlag(JudgeType.invalidate)) continue;
foreach (var tj in sj.Value.PassCh) {
foreach (var s in tj.Value.scores)
UpdateScore(s.Key, s.Value);
Logger.Log("main", 0, "Judge", "Invalidate: {0}", tj.Key);
flag = true; break;
}
if (flag) break;
}
if (!flag) Logger.Log("main", 3, "Judge", "Unjudged invalidation");
}
void Compensate(NoteHandler nh) {
List<StampedEvent.Judge> compensateList = nh.Invalidate();
// Logger.Log("main", 0, "Judge", "comp {0}", compensateList.Count);
// TODO also handle events in `activeEvents`
foreach (var j in compensateList) {
if (j.StartEvent != null) continue;
bool flag = false;
foreach (var sj in j.TargetJudge.PassCh) {
if (!sj.Value.type.HasFlag(JudgeType.compensate)) continue;
foreach (var tj in sj.Value.PassCh) {
foreach (var s in tj.Value.scores)
UpdateScore(s.Key, s.Value);
Logger.Log("main", 0, "Judge", "Compensate: {0}", tj.Key);
flag = true; break;
}
if (flag) break;
}
if (!flag) Logger.Log("main", 3, "Judge", "Unjudged compensation");
}
deactivateList.Add(nh);
}
/// <summary>
/// Matches an attack or release judge.
/// </summary>
bool MatchSecondaryJudge(NoteHandler nh, int ptrid, JudgeState state, SecondaryJudge sj, bool endjudge, PointerInfo p, double deltat, Vector2 wp, IEvaluator etor, bool immsec = false) {
bool flag = false;
int pid = p.Id;
var phase = p.Phase;
if (sj.type == JudgeType.none) return false;
if (!immsec && sj.area != null) if (!MatchArea(sj.area, etor)) return false;
if (phase == PointerPhase.Begin) {
if (sj.type.HasFlag(JudgeType.attackp)) {
if (state.PointerIds.Count == 0) flag = true;
}
if (sj.type.HasFlag(JudgeType.attacks)) {
if (state.PointerIds.Count > 0) flag = true;
}
/*if (!state.PointerIds.Contains(pid)) {
if (sj.@override) ptrop = 2;
else ptrop = 1;
}*/
}
if (phase.HasFlag(PointerPhase.End)) {
if (sj.type.HasFlag(JudgeType.releaseb)) {
if (state.PointerIds.Count == 1 && state.PointerIds[0] == pid) flag = true;
}
if (sj.type.HasFlag(JudgeType.releasec)) {
if (state.PointerIds.Count > 1 && state.PointerIds[0] == pid) flag = true;
}
if (sj.type.HasFlag(JudgeType.releases)) {
if (state.PointerIds.IndexOf(pid) > 0) flag = true;
}
//if (state.PointerIds.IndexOf(pid) >= 0) ptrop = 0;
}
if (!flag) return false;
if (sj.time != null) {
var tr = sj.time.Eval<List<float>>(etor);
if (deltat < tr[0] || deltat > tr[1]) return false;
}
if (endjudge) Compensate(nh);
TryInvalidate(nh, sj, ptrid);
return true;
}
/// <summary>
/// Matches a contact judge.
/// </summary>
bool MatchSecondaryActiveJudge(NoteHandler nh, int ptrid, JudgeState state, SecondaryJudge sj, bool endjudge, PointerInfo p, double deltat, Vector2 wp, IEvaluator etor) {
bool flag = false;
int pid = p.Id;
// Logger.Log("main", 0, "Judge", "Pointers: {0}", state.PointerIds.Count);
if (sj.type == JudgeType.none) return false;
if (sj.type.HasFlag(JudgeType.contactp)) {
if (state.PointerIds.Count > 0 && pid == state.PointerIds[0]) flag = true;
}
if (sj.type.HasFlag(JudgeType.contacts)) {
if (state.PointerIds.Count > 0 && pid != state.PointerIds[0]) flag = true;
// if (sj.@override) stateList[j].PointerId = pid;
}
if (!flag) return false;
if (sj.time != null) {
var tr = sj.time.Eval<List<float>>(etor);
if (deltat < tr[0] || deltat > tr[1]) return false;
}
if (!MatchArea(sj.area, etor)) return false;
TryInvalidate(nh, sj, ptrid);
if (endjudge) Compensate(nh);
return true;
// TODO Invalidate & Call
}
bool MatchSecondaryMissJudge(NoteHandler nh, SecondaryJudge sj, Evaluator etor) {
if (sj.type.HasFlag(JudgeType.miss)) {
TryInvalidate(nh, sj, -1);
return true;
}
return false;
}
bool MatchTertiaryJudge(TertiaryJudge tj, double deltat, Vector3 wp, IEvaluator etor) {
if (tj.time != null) {
var tr = tj.time.Eval<List<float>>(etor);
if (deltat < tr[0] || deltat > tr[1]) return false;
}
if (!MatchArea(tj.area, etor)) return false;
return true;
}
bool MatchArea(Expression exp, IEvaluator etor) {
if (exp != null) {
var a = exp.Eval<float>(etor);
if (a > 0) return false;
}
return true;
}
void UpdateScore(string key, Expression value) {
var etor = new Evaluator();
var extra = new Dictionary<string, object>(scores.Count);
foreach (var s in scores) extra.Add(s.Key, s.Value);
etor.Context = new EvaluatorContext() { Extra = extra };
var ak = key.Split(' ');
string name = ak[ak.Length - 1];
bool setMode = false;
float result = scores[name];
var prop = ruleset.scores[name];
if (ak.Length > 1)
for (int i = 0; i < ak.Length - 1; i++)
if (ak[i] == "@set") setMode = true;
if (setMode)
result = value.Eval<float>(etor);
else
result += value.Eval<float>(etor);
if (prop.range != null) {
var range = prop.range.Eval<List<float>>(etor);
if (result < range[0]) result = range[0];
else if (result > range[1]) result = range[1];
}
if (prop.min != null && result < scores[prop.min])
scores[prop.min] = result;
if (prop.max != null && result > scores[prop.max])
scores[prop.max] = result;
scores[name] = result;
foreach (var s in scores) extra[s.Key] = s.Value;
etor.Context = new EvaluatorContext() { Extra = extra };
foreach (var s in ruleset.scores.Keys) {
if (ruleset.scores[s].value != null) {
scores[s] = ruleset.scores[s].value.Eval<float>(etor);
}
}
ScoreCache.Clear();
}
readonly Dictionary<string, string> ScoreCache = new Dictionary<string, string>();
public Dictionary<string, string> GetScoreStrings() {
if (ScoreCache.Count == 0) {
foreach (var s in scores) {
ScoreCache.Add(s.Key, s.Value.ToString(ruleset.scores[s.Key].format));
}
}
return ScoreCache;
}
public string FormatScores() {
using (gstring.Block()) {
bool flag = false;
gstring result = new gstring(0);
foreach (var s in GetScoreStrings()) {
result += gstring.Format(flag ? "\n{0}: {1}" : "{0}: {1}", s.Key, (string)s.Value);
flag = true;
}
return result.Intern();
}
}
}
[Obsolete]
public class PrimaryJudge {
public List<string> pass;
public Dictionary<string, SecondaryJudge> PassCh
= new Dictionary<string, SecondaryJudge>();
public Expression time;
/// <summary>
/// The layer of the primary judge. Judges on different layers do not interfere with each other.
/// </summary>
public int layer = 0;
/// <summary>
/// The priority of the primary judge. Judges with higher priority are handled first on the same layer.
/// </summary>
public int priority = 0;
}
[Obsolete]
public class SecondaryJudge {
public JudgeType type;
public List<string> call;
public Dictionary<string, SecondaryJudge> CallCh
= new Dictionary<string, SecondaryJudge>();
public bool @return;
public List<string> pass;
public Dictionary<string, TertiaryJudge> PassCh
= new Dictionary<string, TertiaryJudge>();
public Expression time;
public Expression area;
public Invalidation invalidate;
public bool @override;
}
[Flags][Obsolete]
public enum JudgeType {
none = 0,
attackp = 1, attacks = 2, attack = 3,
releaseb = 4, releasec = 8, releasep = 12, releases = 16, release = 28,
enterp = 32, enters = 64, enter = 96,
leaveb = 128, leavec = 256, leavep = 384, leaves = 512, leave = 896,
setp = 33, sets = 66, set = 99,
unsetb = 132, unsetc = 264, unsetp = 396, unsets = 528, unset = 924,
contactp = 1024, contacts = 2048, contact = 3072,
miss = 4096, compensate = 8192, invalidate = 16384
}
[Flags][Obsolete]
public enum Invalidation {
none = 0, finger = 1, note = 2
}
[Obsolete]
public class TertiaryJudge {
public Expression time;
public Expression area;
public Dictionary<string, Expression> scores
= new Dictionary<string, Expression>();
}
[Obsolete]
public class Score {
public Expression range;
public Expression value;
public float init = 0;
public string min;
public string max;
public string format = "";
}
#endif
#endregion
public class Judge {
readonly PdtRuleset rs;
public Judge() {
rs = ChartPlayer.pruleset;
foreach (var s in rs.scores)
scores.Add(s.Key, s.Value.init);
}
public void StartFrame() {
}
public void Feed(InputEvent ev) {
}
public void EndFrame() {
}
public readonly Dictionary<string, float> scores = new Dictionary<string, float>();
readonly Dictionary<string, string> ScoreCache = new Dictionary<string, string>();
public Dictionary<string, string> GetFormattedScoreStrings() {
if (ScoreCache.Count == 0) {
foreach (var s in scores)
ScoreCache.Add(s.Key, s.Value.ToString(rs.scores[s.Key].format));
}
return ScoreCache;
}
public string GetFullFormattedScoreString() {
bool flag = false;
string result = "";
foreach (var s in GetFormattedScoreStrings()) {
result += string.Format(flag ? "\n{0}: {1}" : "{0}: {1}", s.Key, s.Value);
flag = true;
}
return result;
}
}
public class InputDefinition {
public int dim;
public bool notnull;
public Dictionary<string, PdtExpression> pass;
}
public class JudgeDefinition {
public PdtExpression clip;
public PdtExpression hit;
public string[] pass;
public string miss;
public Dictionary<string, PdtExpression> scores;
}
public class ScoreOperation {
public string name;
public PdtOperator op;
}
public class ScoreDefinition {
public PdtExpression value;
public float init = 0;
public string format = "";
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 1207cc17aa0c9ea469cfcf1508a3d5bb
timeCreated: 1618822453
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,23 @@
using UnityEngine;
using Logger = Cryville.Common.Logger;
namespace Cryville.Crtr {
internal class Master : MonoBehaviour {
#pragma warning disable IDE0044
[SerializeField]
private GameObject m_menu;
#pragma warning restore IDE0044
internal void ShowMenu() {
m_menu.SetActive(true);
}
internal void HideMenu() {
m_menu.SetActive(false);
}
void OnApplicationQuit() {
Game.Shutdown();
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 6f99b215329396d4494d41dad6bd65eb
timeCreated: 1637847515
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,57 @@
using Cryville.Common.Unity.UI;
using Cryville.Crtr.Browsing;
using UnityEngine;
namespace Cryville.Crtr {
public class Menu : MonoBehaviour {
#pragma warning disable IDE0044
[SerializeField]
private ResourceBrowserMaster m_browserMaster;
[SerializeField]
private Animator m_targetAnimator;
[SerializeField]
private ProgressBar m_progressBar;
#pragma warning restore IDE0044
bool initialized = false;
int totalTasks = -1;
#pragma warning disable IDE0051
void Awake() {
Game.Init();
transform.parent.Find("Canvas/Contents").gameObject.SetActive(true);
}
void Update() {
if (!initialized) {
int taskCount = Game.NetworkTaskWorker.TaskCount;
if (totalTasks == -1) totalTasks = taskCount;
m_progressBar.value = 1 - (float)taskCount / totalTasks;
if (taskCount == 0) {
initialized = true;
m_targetAnimator.SetTrigger("T_Main");
}
}
if (Input.GetKeyDown(KeyCode.Escape)) {
if (m_targetAnimator != null) Back();
}
}
private static string animatorState = null;
void OnDisable() {
animatorState = m_targetAnimator.GetCurrentAnimatorClipInfo(0)[0].clip.name;
}
void OnEnable() {
Application.targetFrameRate = 60;
if (animatorState != null) m_targetAnimator.PlayInFixedTime(animatorState, 0, 0);
Game.NetworkTaskWorker.ResumeBackgroundTasks();
}
#pragma warning restore IDE0051
public void Back() {
if (m_browserMaster.Back()) return;
m_targetAnimator.SetTrigger("G_Back");
}
public void Quit() {
Application.Quit();
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: ceefede648e4d6d40839f2dda9019066
timeCreated: 1637222453
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,63 @@
using UnityEngine;
using System.Collections;
namespace Cryville.Crtr {
public class MeshWrapper {
public GameObject MeshObject {
get;
private set;
}
public MeshFilter MeshFilter {
get;
private set;
}
public Mesh Mesh {
get { return MeshFilter.mesh; }
set { MeshFilter.mesh = value; }
}
public Transform MeshTransform {
get;
private set;
}
public Renderer Renderer {
get;
private set;
}
public bool Transparent {
get;
private set;
}
public bool Initialized {
get;
private set;
}
public Material NewMaterial {
get {
return Material.Instantiate(GenericResources.Materials[
Transparent ? "-TransparentMat" : "-CutoutMat"
]);
}
}
public void Init(Transform parent, bool transparent = false) {
Transparent = transparent;
MeshObject = new GameObject("__mesh__");
MeshTransform = MeshObject.transform;
MeshTransform.SetParent(parent, false);
if (MeshObject.GetComponent<MeshFilter>() == null)
MeshObject.AddComponent<MeshFilter>();
if (MeshObject.GetComponent<MeshRenderer>() == null)
MeshObject.AddComponent<MeshRenderer>();
MeshFilter = MeshObject.GetComponent<MeshFilter>();
Renderer = MeshObject.GetComponent<Renderer>();
Renderer.material = GenericResources.Materials[
transparent ? "-TransparentMat" : "-CutoutMat"
]; // TODO
Initialized = true;
}
public void Destroy() {
Mesh.Destroy(Mesh);
if (Renderer.material != null) Material.Destroy(Renderer.material);
GameObject.Destroy(MeshObject);
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 39e842e4379944f46ae46577bd5f51d4
timeCreated: 1636616568
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More