Add project files.
This commit is contained in:
15
Assets/Cryville/Crtr/Anchor.cs
Normal file
15
Assets/Cryville/Crtr/Anchor.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
12
Assets/Cryville/Crtr/Anchor.cs.meta
Normal file
12
Assets/Cryville/Crtr/Anchor.cs.meta
Normal 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:
|
9
Assets/Cryville/Crtr/Browsing.meta
Normal file
9
Assets/Cryville/Crtr/Browsing.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bf6d413b13da4fe4eab20a567d8ee795
|
||||
folderAsset: yes
|
||||
timeCreated: 1638415418
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
21
Assets/Cryville/Crtr/Browsing/BrowserItem.cs
Normal file
21
Assets/Cryville/Crtr/Browsing/BrowserItem.cs
Normal 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; }
|
||||
}
|
||||
}
|
12
Assets/Cryville/Crtr/Browsing/BrowserItem.cs.meta
Normal file
12
Assets/Cryville/Crtr/Browsing/BrowserItem.cs.meta
Normal 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:
|
52
Assets/Cryville/Crtr/Browsing/BrowserItemTile.cs
Normal file
52
Assets/Cryville/Crtr/Browsing/BrowserItemTile.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
12
Assets/Cryville/Crtr/Browsing/BrowserItemTile.cs.meta
Normal file
12
Assets/Cryville/Crtr/Browsing/BrowserItemTile.cs.meta
Normal 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:
|
71
Assets/Cryville/Crtr/Browsing/DetailPanel.cs
Normal file
71
Assets/Cryville/Crtr/Browsing/DetailPanel.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
12
Assets/Cryville/Crtr/Browsing/DetailPanel.cs.meta
Normal file
12
Assets/Cryville/Crtr/Browsing/DetailPanel.cs.meta
Normal 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:
|
14
Assets/Cryville/Crtr/Browsing/IResourceManager.cs
Normal file
14
Assets/Cryville/Crtr/Browsing/IResourceManager.cs
Normal 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();
|
||||
}
|
||||
}
|
12
Assets/Cryville/Crtr/Browsing/IResourceManager.cs.meta
Normal file
12
Assets/Cryville/Crtr/Browsing/IResourceManager.cs.meta
Normal 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:
|
155
Assets/Cryville/Crtr/Browsing/LegacyResourceManager.cs
Normal file
155
Assets/Cryville/Crtr/Browsing/LegacyResourceManager.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
12
Assets/Cryville/Crtr/Browsing/LegacyResourceManager.cs.meta
Normal file
12
Assets/Cryville/Crtr/Browsing/LegacyResourceManager.cs.meta
Normal 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:
|
55
Assets/Cryville/Crtr/Browsing/PVPBool.cs
Normal file
55
Assets/Cryville/Crtr/Browsing/PVPBool.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Cryville/Crtr/Browsing/PVPBool.cs.meta
Normal file
11
Assets/Cryville/Crtr/Browsing/PVPBool.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b281561aca5d19f43ba8af035de8ec98
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
147
Assets/Cryville/Crtr/Browsing/PVPNumber.cs
Normal file
147
Assets/Cryville/Crtr/Browsing/PVPNumber.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Cryville/Crtr/Browsing/PVPNumber.cs.meta
Normal file
11
Assets/Cryville/Crtr/Browsing/PVPNumber.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1eb74ffd69f934d4a8eca80aa3077b6c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
27
Assets/Cryville/Crtr/Browsing/PathPart.cs
Normal file
27
Assets/Cryville/Crtr/Browsing/PathPart.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
12
Assets/Cryville/Crtr/Browsing/PathPart.cs.meta
Normal file
12
Assets/Cryville/Crtr/Browsing/PathPart.cs.meta
Normal 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:
|
55
Assets/Cryville/Crtr/Browsing/PropertyCategoryPanel.cs
Normal file
55
Assets/Cryville/Crtr/Browsing/PropertyCategoryPanel.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
12
Assets/Cryville/Crtr/Browsing/PropertyCategoryPanel.cs.meta
Normal file
12
Assets/Cryville/Crtr/Browsing/PropertyCategoryPanel.cs.meta
Normal 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:
|
73
Assets/Cryville/Crtr/Browsing/PropertyPanel.cs
Normal file
73
Assets/Cryville/Crtr/Browsing/PropertyPanel.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
12
Assets/Cryville/Crtr/Browsing/PropertyPanel.cs.meta
Normal file
12
Assets/Cryville/Crtr/Browsing/PropertyPanel.cs.meta
Normal 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:
|
9
Assets/Cryville/Crtr/Browsing/PropertyValuePanel.cs
Normal file
9
Assets/Cryville/Crtr/Browsing/PropertyValuePanel.cs
Normal 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; }
|
||||
}
|
||||
}
|
11
Assets/Cryville/Crtr/Browsing/PropertyValuePanel.cs.meta
Normal file
11
Assets/Cryville/Crtr/Browsing/PropertyValuePanel.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fca3da10a8b0677439885f6732ac3b6e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
73
Assets/Cryville/Crtr/Browsing/ResourceBrowser.cs
Normal file
73
Assets/Cryville/Crtr/Browsing/ResourceBrowser.cs
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
12
Assets/Cryville/Crtr/Browsing/ResourceBrowser.cs.meta
Normal file
12
Assets/Cryville/Crtr/Browsing/ResourceBrowser.cs.meta
Normal 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:
|
113
Assets/Cryville/Crtr/Browsing/ResourceBrowserMaster.cs
Normal file
113
Assets/Cryville/Crtr/Browsing/ResourceBrowserMaster.cs
Normal 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
|
||||
}
|
12
Assets/Cryville/Crtr/Browsing/ResourceBrowserMaster.cs.meta
Normal file
12
Assets/Cryville/Crtr/Browsing/ResourceBrowserMaster.cs.meta
Normal 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:
|
14
Assets/Cryville/Crtr/Browsing/ResourceBrowserUnit.cs
Normal file
14
Assets/Cryville/Crtr/Browsing/ResourceBrowserUnit.cs
Normal 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() { }
|
||||
}
|
||||
}
|
12
Assets/Cryville/Crtr/Browsing/ResourceBrowserUnit.cs.meta
Normal file
12
Assets/Cryville/Crtr/Browsing/ResourceBrowserUnit.cs.meta
Normal 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:
|
33
Assets/Cryville/Crtr/Browsing/ResourceConverter.cs
Normal file
33
Assets/Cryville/Crtr/Browsing/ResourceConverter.cs
Normal 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; }
|
||||
}
|
||||
}
|
12
Assets/Cryville/Crtr/Browsing/ResourceConverter.cs.meta
Normal file
12
Assets/Cryville/Crtr/Browsing/ResourceConverter.cs.meta
Normal 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:
|
91
Assets/Cryville/Crtr/CastedList.cs
Normal file
91
Assets/Cryville/Crtr/CastedList.cs
Normal 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(); }
|
||||
}
|
||||
}
|
11
Assets/Cryville/Crtr/CastedList.cs.meta
Normal file
11
Assets/Cryville/Crtr/CastedList.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4772e6a04d244554d963e3ed64094417
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
477
Assets/Cryville/Crtr/Chart.cs
Normal file
477
Assets/Cryville/Crtr/Chart.cs
Normal 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; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
12
Assets/Cryville/Crtr/Chart.cs.meta
Normal file
12
Assets/Cryville/Crtr/Chart.cs.meta
Normal 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:
|
164
Assets/Cryville/Crtr/ChartHandler.cs
Normal file
164
Assets/Cryville/Crtr/ChartHandler.cs
Normal 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);
|
||||
}
|
||||
}*/
|
||||
}
|
12
Assets/Cryville/Crtr/ChartHandler.cs.meta
Normal file
12
Assets/Cryville/Crtr/ChartHandler.cs.meta
Normal 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:
|
630
Assets/Cryville/Crtr/ChartPlayer.cs
Normal file
630
Assets/Cryville/Crtr/ChartPlayer.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
12
Assets/Cryville/Crtr/ChartPlayer.cs.meta
Normal file
12
Assets/Cryville/Crtr/ChartPlayer.cs.meta
Normal 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:
|
188
Assets/Cryville/Crtr/Cocos2dFrames.cs
Normal file
188
Assets/Cryville/Crtr/Cocos2dFrames.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
12
Assets/Cryville/Crtr/Cocos2dFrames.cs.meta
Normal file
12
Assets/Cryville/Crtr/Cocos2dFrames.cs.meta
Normal 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:
|
9
Assets/Cryville/Crtr/Components.meta
Normal file
9
Assets/Cryville/Crtr/Components.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7ccb6283af616de43881e90749df8f19
|
||||
folderAsset: yes
|
||||
timeCreated: 1609142378
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
291
Assets/Cryville/Crtr/Components/SectionalGameObject.cs
Normal file
291
Assets/Cryville/Crtr/Components/SectionalGameObject.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
12
Assets/Cryville/Crtr/Components/SectionalGameObject.cs.meta
Normal file
12
Assets/Cryville/Crtr/Components/SectionalGameObject.cs.meta
Normal 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:
|
76
Assets/Cryville/Crtr/Components/SkinComponent.cs
Normal file
76
Assets/Cryville/Crtr/Components/SkinComponent.cs
Normal 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();
|
||||
}
|
||||
}
|
12
Assets/Cryville/Crtr/Components/SkinComponent.cs.meta
Normal file
12
Assets/Cryville/Crtr/Components/SkinComponent.cs.meta
Normal 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:
|
155
Assets/Cryville/Crtr/Components/SpriteBase.cs
Normal file
155
Assets/Cryville/Crtr/Components/SpriteBase.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
12
Assets/Cryville/Crtr/Components/SpriteBase.cs.meta
Normal file
12
Assets/Cryville/Crtr/Components/SpriteBase.cs.meta
Normal 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:
|
156
Assets/Cryville/Crtr/Components/SpritePlane.cs
Normal file
156
Assets/Cryville/Crtr/Components/SpritePlane.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
12
Assets/Cryville/Crtr/Components/SpritePlane.cs.meta
Normal file
12
Assets/Cryville/Crtr/Components/SpritePlane.cs.meta
Normal 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:
|
39
Assets/Cryville/Crtr/Components/SpriteRect.cs
Normal file
39
Assets/Cryville/Crtr/Components/SpriteRect.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
12
Assets/Cryville/Crtr/Components/SpriteRect.cs.meta
Normal file
12
Assets/Cryville/Crtr/Components/SpriteRect.cs.meta
Normal 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:
|
93
Assets/Cryville/Crtr/Components/SpriteScale3.cs
Normal file
93
Assets/Cryville/Crtr/Components/SpriteScale3.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
12
Assets/Cryville/Crtr/Components/SpriteScale3.cs.meta
Normal file
12
Assets/Cryville/Crtr/Components/SpriteScale3.cs.meta
Normal 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:
|
201
Assets/Cryville/Crtr/Components/SpriteText.cs
Normal file
201
Assets/Cryville/Crtr/Components/SpriteText.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
12
Assets/Cryville/Crtr/Components/SpriteText.cs.meta
Normal file
12
Assets/Cryville/Crtr/Components/SpriteText.cs.meta
Normal 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:
|
31
Assets/Cryville/Crtr/Components/TrackLine.cs
Normal file
31
Assets/Cryville/Crtr/Components/TrackLine.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
12
Assets/Cryville/Crtr/Components/TrackLine.cs.meta
Normal file
12
Assets/Cryville/Crtr/Components/TrackLine.cs.meta
Normal 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:
|
12
Assets/Cryville/Crtr/Components/TransformInterface.cs
Normal file
12
Assets/Cryville/Crtr/Components/TransformInterface.cs
Normal 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() { }
|
||||
}
|
||||
}
|
11
Assets/Cryville/Crtr/Components/TransformInterface.cs.meta
Normal file
11
Assets/Cryville/Crtr/Components/TransformInterface.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6a8a184616fd97d4a877c59c2ff76ba3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
170
Assets/Cryville/Crtr/Console.cs
Normal file
170
Assets/Cryville/Crtr/Console.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
12
Assets/Cryville/Crtr/Console.cs.meta
Normal file
12
Assets/Cryville/Crtr/Console.cs.meta
Normal 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:
|
331
Assets/Cryville/Crtr/Evaluator.cs
Normal file
331
Assets/Cryville/Crtr/Evaluator.cs
Normal 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
|
||||
}
|
12
Assets/Cryville/Crtr/Evaluator.cs.meta
Normal file
12
Assets/Cryville/Crtr/Evaluator.cs.meta
Normal 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:
|
9
Assets/Cryville/Crtr/Event.meta
Normal file
9
Assets/Cryville/Crtr/Event.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a65cec040b88e9b43b6e2058eb13562f
|
||||
folderAsset: yes
|
||||
timeCreated: 1617701650
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
137
Assets/Cryville/Crtr/Event/ContainerHandler.cs
Normal file
137
Assets/Cryville/Crtr/Event/ContainerHandler.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
12
Assets/Cryville/Crtr/Event/ContainerHandler.cs.meta
Normal file
12
Assets/Cryville/Crtr/Event/ContainerHandler.cs.meta
Normal 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:
|
485
Assets/Cryville/Crtr/Event/ContainerState.cs
Normal file
485
Assets/Cryville/Crtr/Event/ContainerState.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
12
Assets/Cryville/Crtr/Event/ContainerState.cs.meta
Normal file
12
Assets/Cryville/Crtr/Event/ContainerState.cs.meta
Normal 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:
|
47
Assets/Cryville/Crtr/Event/EventBatch.cs
Normal file
47
Assets/Cryville/Crtr/Event/EventBatch.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
12
Assets/Cryville/Crtr/Event/EventBatch.cs.meta
Normal file
12
Assets/Cryville/Crtr/Event/EventBatch.cs.meta
Normal 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:
|
147
Assets/Cryville/Crtr/Event/EventBatcher.cs
Normal file
147
Assets/Cryville/Crtr/Event/EventBatcher.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
12
Assets/Cryville/Crtr/Event/EventBatcher.cs.meta
Normal file
12
Assets/Cryville/Crtr/Event/EventBatcher.cs.meta
Normal 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:
|
177
Assets/Cryville/Crtr/Event/EventBus.cs
Normal file
177
Assets/Cryville/Crtr/Event/EventBus.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
12
Assets/Cryville/Crtr/Event/EventBus.cs.meta
Normal file
12
Assets/Cryville/Crtr/Event/EventBus.cs.meta
Normal 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:
|
39
Assets/Cryville/Crtr/Event/RMVPool.cs
Normal file
39
Assets/Cryville/Crtr/Event/RMVPool.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Cryville/Crtr/Event/RMVPool.cs.meta
Normal file
11
Assets/Cryville/Crtr/Event/RMVPool.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 765cb7bc1f7fe3e4db42f09a939fc393
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
9
Assets/Cryville/Crtr/Extensions.meta
Normal file
9
Assets/Cryville/Crtr/Extensions.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8e2ddc61234cc7a46918e4ae935dc314
|
||||
folderAsset: yes
|
||||
timeCreated: 1637936544
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
9
Assets/Cryville/Crtr/Extensions/Malody.meta
Normal file
9
Assets/Cryville/Crtr/Extensions/Malody.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dfd44d1c0681e4842a1f031556519042
|
||||
folderAsset: yes
|
||||
timeCreated: 1637936550
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
243
Assets/Cryville/Crtr/Extensions/Malody/MalodyChartConverter.cs
Normal file
243
Assets/Cryville/Crtr/Extensions/Malody/MalodyChartConverter.cs
Normal 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
|
||||
}
|
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b3624013a6911ba45933085332724ff1
|
||||
timeCreated: 1637936498
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
191
Assets/Cryville/Crtr/Game.cs
Normal file
191
Assets/Cryville/Crtr/Game.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
12
Assets/Cryville/Crtr/Game.cs.meta
Normal file
12
Assets/Cryville/Crtr/Game.cs.meta
Normal 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:
|
38
Assets/Cryville/Crtr/GenericResources.cs
Normal file
38
Assets/Cryville/Crtr/GenericResources.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
12
Assets/Cryville/Crtr/GenericResources.cs.meta
Normal file
12
Assets/Cryville/Crtr/GenericResources.cs.meta
Normal 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:
|
172
Assets/Cryville/Crtr/GroupHandler.cs
Normal file
172
Assets/Cryville/Crtr/GroupHandler.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
12
Assets/Cryville/Crtr/GroupHandler.cs.meta
Normal file
12
Assets/Cryville/Crtr/GroupHandler.cs.meta
Normal 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:
|
135
Assets/Cryville/Crtr/InputProxy.cs
Normal file
135
Assets/Cryville/Crtr/InputProxy.cs
Normal 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) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Cryville/Crtr/InputProxy.cs.meta
Normal file
11
Assets/Cryville/Crtr/InputProxy.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 745ed7d8ca6e4ac458c7e008b966aad1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
731
Assets/Cryville/Crtr/Judge.cs
Normal file
731
Assets/Cryville/Crtr/Judge.cs
Normal 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 = "";
|
||||
}
|
||||
}
|
12
Assets/Cryville/Crtr/Judge.cs.meta
Normal file
12
Assets/Cryville/Crtr/Judge.cs.meta
Normal 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:
|
23
Assets/Cryville/Crtr/Master.cs
Normal file
23
Assets/Cryville/Crtr/Master.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
12
Assets/Cryville/Crtr/Master.cs.meta
Normal file
12
Assets/Cryville/Crtr/Master.cs.meta
Normal 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:
|
57
Assets/Cryville/Crtr/Menu.cs
Normal file
57
Assets/Cryville/Crtr/Menu.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
12
Assets/Cryville/Crtr/Menu.cs.meta
Normal file
12
Assets/Cryville/Crtr/Menu.cs.meta
Normal 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:
|
63
Assets/Cryville/Crtr/MeshWrapper.cs
Normal file
63
Assets/Cryville/Crtr/MeshWrapper.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
12
Assets/Cryville/Crtr/MeshWrapper.cs.meta
Normal file
12
Assets/Cryville/Crtr/MeshWrapper.cs.meta
Normal 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:
|
1156
Assets/Cryville/Crtr/Motion.cs
Normal file
1156
Assets/Cryville/Crtr/Motion.cs
Normal file
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
Reference in New Issue
Block a user