Add project files.

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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