Plugin.cs 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. using BeatLyrics.Common;
  2. using BeatLyrics.Common.Models;
  3. using IllusionPlugin;
  4. using Newtonsoft.Json;
  5. using SongCore.Utilities;
  6. using System;
  7. using System.Collections;
  8. using System.IO;
  9. using System.Linq;
  10. using TMPro;
  11. using UnityEngine;
  12. using UnityEngine.SceneManagement;
  13. namespace BeatLyrics
  14. {
  15. /// <summary>
  16. /// Entry point of the plugin.
  17. /// </summary>
  18. public sealed class Plugin : IPlugin
  19. {
  20. public string Name => "Beat Lyrics";
  21. public string Version => "0.0.0.1";
  22. private LyricsComponent _lastUsedLyricsComponent;
  23. public void OnApplicationStart()
  24. {
  25. SceneManager.activeSceneChanged += OnActiveSceneChanged;
  26. }
  27. public void OnApplicationQuit()
  28. {
  29. SceneManager.activeSceneChanged -= OnActiveSceneChanged;
  30. }
  31. #region Unused
  32. public void OnLevelWasInitialized(int level)
  33. {
  34. }
  35. public void OnLevelWasLoaded(int level)
  36. {
  37. }
  38. public void OnUpdate()
  39. {
  40. }
  41. public void OnFixedUpdate()
  42. {
  43. }
  44. #endregion Unused
  45. public void OnActiveSceneChanged(Scene _, Scene newScene)
  46. {
  47. if (newScene.name == "GameCore")
  48. {
  49. _lastUsedLyricsComponent = newScene.GetRootGameObjects()[0].AddComponent<LyricsComponent>();
  50. }
  51. else
  52. {
  53. if (_lastUsedLyricsComponent != null)
  54. {
  55. //TODO: cleanup
  56. }
  57. }
  58. }
  59. }
  60. public class LyricsComponent : MonoBehaviour
  61. {
  62. private static readonly Quaternion Rot = Quaternion.Euler(new Vector3(0, 0, 0));
  63. private static readonly Vector3 Pos = new Vector3(0, 1.5f, 15f);
  64. private static readonly float FontSize = 20;
  65. private static readonly Color FontColor = new Color(1.0f, 1.0f, 1.0f, 0.4f);
  66. private static readonly float OutlineWidth = 1;
  67. private static readonly Color OutlineColor = new Color(1.0f, 1.0f, 1.0f, 0.8f);
  68. private readonly AudioTimeSyncController _audioTime;
  69. private readonly GameObject _clockCanvas = null;
  70. private readonly TextMeshProUGUI _text = null;
  71. private GameplayCoreSceneSetupData _data;
  72. private LyricFile _lyricFile;
  73. private string _lyricFileName;
  74. private string _debugInfo;
  75. public LyricsComponent()
  76. {
  77. _audioTime = Resources.FindObjectsOfTypeAll<AudioTimeSyncController>().FirstOrDefault();
  78. _clockCanvas = new GameObject();
  79. _clockCanvas.AddComponent<Canvas>();
  80. _clockCanvas.name = "Clock Canvas";
  81. _clockCanvas.transform.position = Pos;
  82. _clockCanvas.transform.rotation = Rot;
  83. _clockCanvas.transform.localScale = new Vector3(0.02f, 0.02f, 1.0f);
  84. var textObj = new GameObject();
  85. textObj.transform.SetParent(_clockCanvas.transform);
  86. textObj.transform.localPosition = Vector3.zero;
  87. textObj.transform.localRotation = Quaternion.identity;
  88. textObj.transform.localScale = Vector3.one;
  89. _text = textObj.AddComponent<TextMeshProUGUI>();
  90. _text.name = "Lyrics Text";
  91. _text.alignment = TextAlignmentOptions.Center;
  92. _text.fontSize = FontSize;
  93. _text.enableWordWrapping = false;
  94. _text.color = FontColor;
  95. _text.outlineColor = OutlineColor;
  96. _text.outlineWidth = OutlineWidth;
  97. _text.text = "BeatLyrics";
  98. //TODO: Select Font
  99. //text.font=
  100. }
  101. public IEnumerator Start()
  102. {
  103. var sceneSetup = FindObjectOfType<GameplayCoreSceneSetup>();
  104. _data = (GameplayCoreSceneSetupData)sceneSetup?.GetField("_sceneSetupData");
  105. //HACK: NJS Cheat
  106. if (_data != null) //TODO: Create New Plugin - OR - Load from Config
  107. {
  108. try
  109. {
  110. _data.difficultyBeatmap.SetField("_noteJumpMovementSpeed", 15);
  111. }
  112. catch (Exception e)
  113. {
  114. System.Diagnostics.Debug.Print(e.ToString());
  115. }
  116. }
  117. try
  118. {
  119. LoadLrc();
  120. }
  121. catch (Exception e)
  122. {
  123. _debugInfo = "Error Load Lrc:" + e.Message;
  124. }
  125. yield break;
  126. }
  127. private void LoadLrc()
  128. {
  129. if (_data?.difficultyBeatmap.level.levelID != null)
  130. {
  131. var beatLyricsDir = DirProvider.BeatLyricsDir;
  132. if (beatLyricsDir != null)
  133. {
  134. var path = GetSetFilePath(_data.difficultyBeatmap.level.levelID);
  135. if (File.Exists(path))
  136. {
  137. var jsonFileName = File.ReadAllText(path);
  138. var jsonFilePath = Path.Combine(beatLyricsDir, _data.difficultyBeatmap.level.levelID, jsonFileName);
  139. if (File.Exists(jsonFilePath))
  140. {
  141. var json = File.ReadAllText(jsonFilePath);
  142. _lyricFile = JsonConvert.DeserializeObject<LyricFile>(json);
  143. _lyricFileName = Path.GetFileNameWithoutExtension(jsonFileName);
  144. }
  145. else
  146. {
  147. _debugInfo += "json file not found";
  148. }
  149. }
  150. else
  151. {
  152. _debugInfo += "set.txt file not found";
  153. }
  154. }
  155. }
  156. }
  157. public void Update()
  158. {
  159. var milliseconds = _audioTime?.songTime * 1000 ?? 0;
  160. if (_lyricFile != null)
  161. {
  162. if (milliseconds < 1)
  163. {
  164. _text.text = _lyricFileName;
  165. }
  166. else
  167. {
  168. //Show LRC
  169. _text.text = _lyricFile.Main?.FirstOrDefault(p => p.TimeMs <= milliseconds && p.TimeMs + p.DurationMs >= milliseconds)?.Text
  170. + Environment.NewLine + _lyricFile.Subtitle?.FirstOrDefault(p => p.TimeMs <= milliseconds && p.TimeMs + p.DurationMs >= milliseconds)?.Text;
  171. }
  172. }
  173. else if (milliseconds < 1)
  174. {
  175. var level = _data?.difficultyBeatmap.level;
  176. _text.text = "此处应有歌词,但是未能加载" +
  177. $"{Environment.NewLine}{level?.levelID}" +
  178. $"{Environment.NewLine}{_debugInfo}";
  179. }
  180. else
  181. {
  182. _text.text = "";
  183. }
  184. }
  185. public static string GetSetFilePath(string levelId)
  186. {
  187. return Path.Combine(DirProvider.BeatLyricsDir, levelId + DirProvider.SuffixSet);
  188. }
  189. }
  190. }