Code structure cleanup.

This commit is contained in:
2023-08-24 15:47:34 +08:00
parent e40c98ae1b
commit 1f58390298
137 changed files with 439 additions and 362 deletions

View File

@@ -0,0 +1,13 @@
using Cryville.Crtr.Browsing;
using UnityEngine;
namespace Cryville.Crtr.UI {
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;
}
}
}

View File

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

View File

@@ -0,0 +1,54 @@
using Cryville.Crtr.Browsing;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace Cryville.Crtr.UI {
internal class BrowserItemTile : BrowserItem {
#pragma warning disable IDE0044
[SerializeField]
private Sprite m_iconPlaceholder;
#pragma warning restore IDE0044
private bool _dir;
private Image _icon;
private TMP_Text _title;
private TMP_Text _desc;
#pragma warning disable IDE0051
void Awake() {
_icon = transform.Find("__content__/Icon").GetComponent<Image>();
_title = transform.Find("__content__/Texts/Title/__text__").GetComponent<TMP_Text>();
_desc = transform.Find("__content__/Texts/Description/__text__").GetComponent<TMP_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, 160, 0, SpriteMeshType.FullRect);
}
}
public void OnClick() {
if (Id == null) return;
var resourceBrowser = GetComponentInParent<ResourceBrowser>();
if (_dir) resourceBrowser.OnDirectoryItemClicked(Id.Value);
else resourceBrowser.OnObjectItemClicked(Id.Value);
}
}
}

View File

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

View File

@@ -0,0 +1,68 @@
using Cryville.Common;
using Cryville.Crtr.Browsing;
using System;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace Cryville.Crtr.UI {
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;
Transform _content;
Image _cover;
TMP_Text _title;
TMP_Text _desc;
protected override void Awake() {
base.Awake();
_placeholder = transform.Find("__placeholder__").gameObject;
_outerContent = transform.Find("__content__").gameObject;
_content = _outerContent.transform.Find("__content__");
_cover = _content.Find("Cover").GetComponent<Image>();
_title = _content.Find("Texts/Title").GetComponent<TMP_Text>();
_desc = _content.Find("Texts/Description").GetComponent<TMP_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);
}
}
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.name);
_desc.text = string.Format(
"Music artist: {0}\nCharter: {1}\nLength: {2}\nNote Count: {3}",
meta.song.author, meta.author,
TimeSpan.FromSeconds(meta.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, 160, 0, SpriteMeshType.FullRect);
}
}
public void OnPlay() {
Master.Open(_id, _data);
}
public void OnConfig() {
Master.OpenConfig(_id, _data);
}
}
}

View File

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

View File

@@ -0,0 +1,89 @@
using System;
using System.Collections.Generic;
using System.Threading;
using UnityEngine;
using UnityEngine.UI;
namespace Cryville.Crtr.UI {
public class Dialog : MonoBehaviour {
static Dialog _instance;
[SerializeField] CanvasGroup m_group;
[SerializeField] Text m_msgText;
[SerializeField] Text m_button0Text;
[SerializeField] Text m_button1Text;
[SerializeField] GameObject m_button1;
[SerializeField] AnimationCurve m_fadeCurve;
float _fadeDuration;
static readonly Queue<DialogEntry> _queue = new Queue<DialogEntry>();
struct DialogEntry {
public Action<int> callback;
public string message;
public string action0;
public string action1;
}
void Awake() {
_instance = this;
_fadeDuration = m_fadeCurve[m_fadeCurve.length - 1].time;
}
float _timer;
DialogEntry? _cur;
static bool _suppressed;
void Update() {
if (_cur == null) {
if (_timer > 0) {
_timer -= Time.deltaTime;
if (_timer < 0) {
_timer = 0;
m_group.gameObject.SetActive(false);
}
m_group.alpha = m_fadeCurve.Evaluate(_timer);
}
if (_queue.Count > 0 && !_suppressed) {
m_group.gameObject.SetActive(true);
_cur = _queue.Dequeue();
m_msgText.text = _cur.Value.message;
m_button0Text.text = _cur.Value.action0;
m_button1Text.text = _cur.Value.action1;
m_button1.SetActive(_cur.Value.action1 != null);
}
}
else {
if (_timer < _fadeDuration) {
_timer += Time.deltaTime;
if (_timer > _fadeDuration) _timer = _fadeDuration;
m_group.alpha = m_fadeCurve.Evaluate(_timer);
}
}
}
public void OnButton(int id) {
if (_cur == null) return;
var cb = _cur.Value.callback;
if (cb != null) cb(id);
_cur = null;
}
public static void Suppress() {
_suppressed = true;
if (_instance._cur != null) {
_queue.Enqueue(_instance._cur.Value);
_instance._cur = null;
}
}
public static void Release() {
_suppressed = false;
}
public static void Show(Action<int> callback, string message, string action0 = "OK", string action1 = null) {
_queue.Enqueue(new DialogEntry { callback = callback, message = message, action0 = action0, action1 = action1 });
}
public static int ShowAndWait(string message, string action0 = "OK", string action1 = null) {
using (var ev = new AutoResetEvent(false)) {
int result = 0;
_queue.Enqueue(new DialogEntry {
callback = r => { result = r; ev.Set(); },
message = message, action0 = action0, action1 = action1,
});
ev.WaitOne();
return result;
}
}
}
}

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,85 @@
using Cryville.Common.Unity.UI;
using Cryville.Crtr.Config;
using Cryville.Crtr.UI;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using unity = UnityEngine;
namespace Cryville.Crtr.UI {
public class Menu : MonoBehaviour {
#pragma warning disable IDE0044
[SerializeField]
ResourceBrowserMaster m_browserMaster;
[SerializeField]
Animator m_targetAnimator;
[SerializeField]
ProgressBar m_progressBar;
[SerializeField]
PropertyMasterPanel m_settingsPanel;
[SerializeField]
TMP_Text m_title;
[SerializeField]
GameObject[] m_backBlockingObjects;
#pragma warning restore IDE0044
int frameIndex = 2;
bool initialized = false;
int totalTasks = 0;
#pragma warning disable IDE0051
void Awake() {
Game.Init();
transform.parent.Find("Canvas/Contents").gameObject.SetActive(true);
m_settingsPanel.Adapter = new DefaultPropertyMasterAdapter(Settings.Default);
PushTitle("Chart Browser");
}
void Update() {
if (!initialized) {
int taskCount = Game.NetworkTaskWorker.TaskCount;
if (totalTasks < taskCount) totalTasks = taskCount;
if (frameIndex > 0) {
frameIndex--;
return;
}
m_progressBar.value = totalTasks == 0 ? 1 : (1 - (float)taskCount / totalTasks);
if (taskCount == 0) {
initialized = true;
m_targetAnimator.SetTrigger("T_Main");
}
}
if (unity::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.ResumeBackgroundTasks();
}
#pragma warning restore IDE0051
readonly Stack<string> _uiStack = new Stack<string>();
public void PushTitle(string title) {
_uiStack.Push(title);
m_title.SetText(title);
}
public void Back() {
foreach (var obj in m_backBlockingObjects) {
if (obj.activeInHierarchy) return;
}
if (m_browserMaster.Back()) return;
m_targetAnimator.SetTrigger("G_Back");
if (_uiStack.Count <= 1) return;
_uiStack.Pop();
m_title.SetText(_uiStack.Peek());
}
public void Quit() {
Application.Quit();
}
}
}

View File

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

View File

@@ -0,0 +1,27 @@
using UnityEngine;
using UnityEngine.UI;
namespace Cryville.Crtr.UI {
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,11 @@
fileFormatVersion: 2
guid: 61827f7104dbb3045bb0bf488132984d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,37 @@
using System;
using UnityEngine;
using UnityEngine.UI;
namespace Cryville.Crtr.UI {
public class Popup : MonoBehaviour {
public string Message = "";
CanvasGroup group;
float timer = 0;
const float DURATION = 5.0f;
const float DURIN = 0.4f;
const float DUROUT = 0.4f;
void Start() {
group = GetComponent<CanvasGroup>();
group.alpha = 0;
GetComponentInChildren<Text>().text = Message;
transform.SetParent(GameObject.Find("PopupList").transform, false);
}
void Update() {
if (timer <= DURIN) group.alpha = timer / DURIN;
else if (timer >= DURATION) GameObject.Destroy(gameObject);
else if (timer >= DURATION - DUROUT) group.alpha = (DURATION - timer) / DUROUT;
timer += Time.deltaTime;
}
public static void CreateException(Exception ex) {
Create(ex.Message);
}
public static void Create(string msg) {
Instantiate(Resources.Load<GameObject>("Common/Popup")).GetComponent<Popup>().Message = msg;
}
}
}

View File

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

View File

@@ -0,0 +1,78 @@
using Cryville.Common.Unity;
using Cryville.Common.Unity.UI;
using Cryville.Crtr.Browsing;
using System;
using UnityEngine;
using UnityEngine.UI;
namespace Cryville.Crtr.UI {
public class ResourceBrowser : ResourceBrowserUnit {
public IResourceManager<ChartDetail> ResourceManager;
public ScrollableItemGrid PathContainer;
public ScrollableItemGrid ItemContainer;
FileDialog _dialog;
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);
_dialog.Filter = ResourceManager.GetSupportedFormats();
_dialog.PresetPaths = ResourceManager.GetPresetPaths();
_dialog.OnClose += OnAddDialogClosed;
}
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>();
try {
var item = ResourceManager.GetItemMeta(id);
bi.Load(id, item);
}
catch (Exception) {
bi.Load(id, new ResourceItemMeta { Name = "<color=#ff0000>Invalid resource</color>" });
}
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.Show();
}
private void OnAddDialogClosed() {
if (_dialog.FileName == null) return;
if (ResourceManager.ImportItemFrom(_dialog.FileName)) {
Popup.Create("Import succeeded");
OnPathClicked(ResourceManager.CurrentDirectory.Length - 1);
}
else {
Popup.Create("Import failed");
}
}
}
}

View File

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

View File

@@ -0,0 +1,91 @@
using Cryville.Common.Unity.UI;
using Cryville.Crtr.Browsing;
using Cryville.Crtr.Config;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
namespace Cryville.Crtr.UI {
public class ResourceBrowserMaster : MonoBehaviour {
[SerializeField]
private Button m_playButton;
[SerializeField]
private Button m_configButton;
[SerializeField]
private ConfigPanelMaster m_configPanel;
private DockLayoutGroup _group;
public ResourceBrowser MainBrowser { get; private set; }
private DetailPanel _detailPanel;
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>();
_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, ChartDetail detail) {
SetDataSettings(id, detail);
#if UNITY_5_3_OR_NEWER
SceneManager.LoadScene("Play", LoadSceneMode.Additive);
#else
Application.LoadLevelAdditive("Play");
#endif
GameObject.Find("/Master").GetComponent<Master>().HideMenu();
#if UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN
DiscordController.Instance.SetPlaying(string.Format("{0} - {1}", detail.Meta.song.name, detail.Meta.name), detail.Meta.length);
#endif
}
public void OpenConfig(int id, ChartDetail detail) {
SetDataSettings(id, detail);
}
void SetDataSettings(int id, ChartDetail detail) {
Settings.Default.LoadRuleset = detail.Meta.ruleset + "/.umgr";
Settings.Default.LoadRulesetConfig = detail.Meta.ruleset + ".json";
Settings.Default.LoadChart = MainBrowser.ResourceManager.GetItemPath(id);
}
}
}

View File

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

View File

@@ -0,0 +1,12 @@
using UnityEngine;
namespace Cryville.Crtr.UI {
public abstract class ResourceBrowserUnit : MonoBehaviour {
protected ResourceBrowserMaster Master { get; private set; }
protected virtual void Awake() {
Master = GetComponentInParent<ResourceBrowserMaster>();
}
public virtual void SlideToLeft() { }
public virtual void SlideToRight() { }
}
}

View File

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