-
Notifications
You must be signed in to change notification settings - Fork 54
[+] 标题画面播放自定义视频 #115
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
WUGqnwvMQPzl
wants to merge
7
commits into
MuNET-OSS:main
Choose a base branch
from
WUGqnwvMQPzl:title-video
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+251
−0
Open
[+] 标题画面播放自定义视频 #115
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
72cf6ac
[+] TitleScreenVideo
WUGqnwvMQPzl 14f593d
[O] materials
WUGqnwvMQPzl eb0bdb0
[O] clean up unnecessary code i guess?
WUGqnwvMQPzl a73f516
[O] make video ready flag thread safe i guess
WUGqnwvMQPzl 279d89a
[O] config field fix
WUGqnwvMQPzl 6552297
[+] add option to skip allnet logo if title video is loaded
WUGqnwvMQPzl 2f14037
[+] hide copyright on the title screen
WUGqnwvMQPzl File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,251 @@ | ||
| using AquaMai.Config.Attributes; | ||
| using AquaMai.Core.Attributes; | ||
| using AquaMai.Core.Helpers; | ||
| using HarmonyLib; | ||
| using MAI2.Util; | ||
| using Manager; | ||
| using MelonLoader; | ||
| using Monitor; | ||
| using Process; | ||
| using System.Collections.Generic; | ||
| using System.Threading; | ||
| using UnityEngine; | ||
| using UnityEngine.Video; | ||
|
|
||
| namespace AquaMai.Mods.Fancy; | ||
|
|
||
| [ConfigSection( | ||
| "标题画面视频", | ||
| en: "Plays custom video on title screen, just like in the good ol' days", | ||
| zh: "复刻 bud 代之前的标题界面视频动画")] | ||
| [EnableGameVersion(24000)] | ||
| public class TitleScreenVideo | ||
| { | ||
| [ConfigEntry( | ||
| en: "Title Video / Audio File Path (without file extensions, mp4 video and acb/awb audio are supported)", | ||
| zh: "标题视音频文件路径,不包括文件后缀名(视频为 mp4 格式,音频为 acb/awb 格式)")] | ||
| public static readonly string VideoPath = "LocalAssets/DX_title"; | ||
|
|
||
| [ConfigEntry( | ||
| en: "Skip the SEGA / All.Net logo when custom title video file is loaded", | ||
| zh: "自定标题视频成功加载后,跳过 SEGA / All.Net 标志动画")] | ||
| public static readonly bool SkipLogo = false; | ||
|
|
||
| [ConfigEntry( | ||
| en: "Hide copyright information on the bottom of the title screen", | ||
| zh: "隐藏标题画面底部的版权信息")] | ||
| public static readonly bool HideCopyright = false; | ||
|
|
||
| private static GameObject[] _movieObjects = new GameObject[2]; | ||
| private static VideoPlayer[] _videoPlayers = new VideoPlayer[2]; | ||
| private static Material[] _videoMaterials = new Material[2]; | ||
|
|
||
| private static List<string>[] _disabledCompoments = [[], []]; | ||
|
|
||
| private static int _videoPreparedCount = 0; | ||
| private static bool IsVideoPrepared => _videoPreparedCount >= 2; | ||
|
|
||
| private static bool _isAudioPrepared = false; | ||
|
|
||
| [HarmonyPostfix] | ||
| [HarmonyPatch(typeof(AdvertiseProcess), "OnStart")] | ||
| public static void OnStart_Postfix(AdvertiseMonitor[] ____monitors) | ||
| { | ||
| var moviePref = Resources.Load<GameObject>("Process/AdvertiseCommercial/AdvertiseCommercialProcess").transform.Find("Canvas/Main/MovieMask").gameObject; | ||
|
|
||
| for (int i = 0; i < ____monitors.Length; ++i) | ||
| { | ||
| var monitor = ____monitors[i]; | ||
|
|
||
| // Disable fade out cover on cir (and maybe future version?) | ||
| if (GameInfo.GameVersion >= 26000) | ||
| monitor.transform.Find("Canvas/Main/UI_ADV_Title/Null_all/out_cover")?.gameObject.SetActive(false); | ||
|
|
||
| // Hide copyright information | ||
| if (HideCopyright) | ||
| monitor.transform.Find("Canvas/Main/UI_ADV_Title/Null_all/Licence").gameObject.SetActive(false); | ||
|
|
||
| var titleLoop = monitor.transform.Find("Canvas/Main/UI_ADV_Title/Null_all/TitleLoop"); | ||
|
|
||
| // Disable all elements on the original title screen | ||
| for (int j = 0; j < titleLoop.childCount; ++j) | ||
| { | ||
| var obj = titleLoop.GetChild(j).gameObject; | ||
| if (obj.activeSelf) | ||
| { | ||
| obj.SetActive(false); | ||
| _disabledCompoments[i].Add(obj.name); | ||
| } | ||
| } | ||
|
|
||
| _movieObjects[i] = UnityEngine.Object.Instantiate(moviePref, titleLoop); | ||
| _movieObjects[i].GetComponent<SpriteRenderer>().color = new Color(0, 0, 0, 0); | ||
|
|
||
| _videoPlayers[i] = _movieObjects[i].AddComponent<VideoPlayer>(); | ||
| _videoPlayers[i].url = FileSystem.ResolvePath(VideoPath + ".mp4"); | ||
| _videoPlayers[i].playOnAwake = false; | ||
| _videoPlayers[i].isLooping = false; | ||
| _videoPlayers[i].renderMode = VideoRenderMode.MaterialOverride; | ||
| _videoPlayers[i].audioOutputMode = VideoAudioOutputMode.None; | ||
|
|
||
| var movieSprite = _movieObjects[i].transform.Find("Movie").gameObject.GetComponent<SpriteRenderer>(); | ||
|
|
||
| _videoPlayers[i].prepareCompleted += (source) => | ||
| { | ||
| // Prevent autoplay | ||
| source.Pause(); | ||
| source.time = 0; | ||
|
|
||
| // Setting the video player size | ||
| var vWidth = source.width; | ||
| var vHeight = source.height; | ||
|
|
||
| var calWidth = vHeight > vWidth ? (1080 * vWidth / vHeight) : 1080; | ||
| var calHeight = vHeight > vWidth ? 1080 : (1080 * vHeight / vWidth); | ||
|
|
||
| movieSprite.size = new Vector2(calWidth, calHeight); | ||
|
|
||
| Interlocked.Increment(ref _videoPreparedCount); | ||
| }; | ||
|
|
||
| _videoPlayers[i].errorReceived += (source, err) => | ||
| { | ||
| MelonLogger.Error($"[TitleScreenVideo] Failed to load video file: {err}"); | ||
| }; | ||
|
|
||
| _videoPlayers[i].Prepare(); | ||
|
|
||
| _videoMaterials[i] = new Material(Shader.Find("Sprites/Default")); | ||
| movieSprite.material = _videoMaterials[i]; | ||
| _videoPlayers[i].targetMaterialRenderer = movieSprite; | ||
| } | ||
|
|
||
| _isAudioPrepared = SoundManager.MusicPrepareForFileName(VideoPath); | ||
| if (!_isAudioPrepared) | ||
| MelonLogger.Warning("[TitleScreenVideo] Failed to load audio file, game's default title jingle will be played instead"); | ||
| } | ||
|
|
||
| [HarmonyPostfix] | ||
| [HarmonyPatch(typeof(AdvertiseProcess), "OnUpdate")] | ||
| public static void OnUpdate_Postfix(AdvertiseProcess.AdvertiseSequence ____state, AdvertiseMonitor[] ____monitors) | ||
| { | ||
| if (____state == AdvertiseProcess.AdvertiseSequence.TransitionOut && IsVideoPrepared) | ||
| { | ||
| for (int i = 0; i < ____monitors.Length; ++i) | ||
| { | ||
| // Stop yelling "maimai deluxe" I'm tired to hearing it | ||
| SoundManager.StopVoice(i); | ||
|
|
||
| _videoPlayers[i].Play(); | ||
|
|
||
| if (_isAudioPrepared) | ||
| { | ||
| // Stop game's original title music and plays our own | ||
| SoundManager.StopJingle(i); | ||
| SoundManager.StartMusic(); | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| [HarmonyPostfix] | ||
| [HarmonyPatch(typeof(AdvertiseProcess), "LeaveAdvertise")] | ||
| public static void LeaveAdvertise_Postfix() | ||
| { | ||
| if (_isAudioPrepared) | ||
| { | ||
| // Stop and unloads title music | ||
| SoundManager.StopMusic(); | ||
| Singleton<SoundCtrl>.Instance.UnloadCueSheet(1); | ||
|
WUGqnwvMQPzl marked this conversation as resolved.
|
||
| } | ||
| } | ||
|
|
||
| [HarmonyPrefix] | ||
| [HarmonyPatch(typeof(AdvertiseProcess), "OnRelease")] | ||
| public static void OnRelease_Prefix(AdvertiseMonitor[] ____monitors) | ||
| { | ||
| for (int i = 0; i < ____monitors.Length; ++i) | ||
| { | ||
| if (_videoMaterials[i] != null) | ||
| { | ||
| UnityEngine.Object.Destroy(_videoMaterials[i]); | ||
| _videoMaterials[i] = null; | ||
| } | ||
|
|
||
| if (_videoPlayers[i] != null) | ||
| { | ||
| UnityEngine.Object.Destroy(_videoPlayers[i]); | ||
| _videoPlayers[i] = null; | ||
| } | ||
|
|
||
| if (_movieObjects[i] != null) | ||
| { | ||
| UnityEngine.Object.Destroy(_movieObjects[i]); | ||
| _movieObjects[i] = null; | ||
| } | ||
| } | ||
|
|
||
| // Resets status | ||
| Interlocked.Exchange(ref _videoPreparedCount, 0); | ||
| _isAudioPrepared = false; | ||
| _disabledCompoments = [[], []]; | ||
| } | ||
|
|
||
| [HarmonyPrefix] | ||
| [HarmonyPatch(typeof(AdvertiseMonitor), "AllStop")] | ||
| public static bool Monitor_AllStop_Prefix() | ||
| { | ||
| // So uhh... When I was testing the feature, this method makes title screen suddently go black before transition | ||
| // I don't like the sudden cutout so I disabled it, not sure about the side effect or compatibility though | ||
|
WUGqnwvMQPzl marked this conversation as resolved.
|
||
| return false; | ||
| } | ||
|
|
||
| [HarmonyPrefix] | ||
| [HarmonyPatch(typeof(AdvertiseMonitor), "IsTitleAnimationEnd")] | ||
| public static bool Monitor_IsTitleAnimationEnd_Prefix(ref bool __result, int ___monitorIndex) | ||
| { | ||
| if (!IsVideoPrepared) | ||
| return true; | ||
|
|
||
| __result = !_videoPlayers[___monitorIndex].isPlaying && _videoPlayers[___monitorIndex].frame >= (long) _videoPlayers[___monitorIndex].frameCount - 1; | ||
| return false; | ||
| } | ||
|
|
||
| [HarmonyPrefix] | ||
| [HarmonyPatch(typeof(AdvertiseMonitor), "PlayLogo")] | ||
| public static bool Monitor_PlayLogo_Prefix(int ___monitorIndex, GameObject ____eventModeObject, CanvasGroup ___Main) | ||
| { | ||
| if (!IsVideoPrepared) | ||
| { | ||
| // Re-enable original title screen elements if the video is unavailable | ||
| // doing this early so the transition will be less noticable | ||
| _movieObjects[___monitorIndex].SetActive(false); | ||
|
|
||
| var titleLoop = ___Main.transform.Find("UI_ADV_Title/Null_all/TitleLoop"); | ||
| foreach (string name in _disabledCompoments[___monitorIndex]) | ||
| titleLoop.Find(name).gameObject.SetActive(true); | ||
|
|
||
| _disabledCompoments[___monitorIndex] = []; | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| if (!SkipLogo) | ||
| return true; | ||
|
|
||
| ____eventModeObject.SetActive(GameManager.IsEventMode); | ||
| ___Main.transform.Find("UI_ADV_SegaAllNet").gameObject.SetActive(false); | ||
| return false; | ||
| } | ||
|
|
||
| [HarmonyPrefix] | ||
| [HarmonyPatch(typeof(AdvertiseMonitor), "IsLogoAnimationEnd")] | ||
| public static bool Monitor_IsLogoAnimationEnd_Prefix(ref bool __result) | ||
| { | ||
| if (!IsVideoPrepared || !SkipLogo) | ||
| return true; | ||
|
|
||
| __result = true; | ||
| return false; | ||
| } | ||
| } | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.