Files
Convention-Unity-Demo/Assets/Scripts/Framework/GameContent/GameController.cs

316 lines
12 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using Cinemachine;
using Convention;
using Convention.WindowsUI.Variant;
using Unity.Profiling;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.SceneManagement;
namespace Demo.Game
{
public partial class GameController : MonoBehaviour
{
[Resources, SerializeField] public BasicAudioSystem MainAudio;
[Resources, SerializeField] private CinemachineVirtualCamera MainCamera;
[Resources, SerializeField] public GlobalConfig MainConfig;
[Content] private RootObject MainObject;
[Content] public bool IsHideTrackRender = false;
public string RootSourcePath { get; private set; }
public Action<float, float> SetupSongDuration { get; private set; } = (_, _) => { };
public Action<float> SetSongCurrentTime { get; private set; } = _ => { };
public bool IsMain { get; set; } = false;
public bool IsAutoPlay { get; private set; } = false;
public string ScriptEditor { get; private set; } = "{0}";
public ProjectDefaultFileStyle CurrentProjectDefaultFileStyle = default;
public float SongOffset;
public float CurrentTime => MainAudio.CurrentTime - SongOffset;
public Transform MainCameraTransform => MainCamera.transform;
[Header("Environment")]
[Resources] public Transform GlobalLight;
public IEnumerator GameInit()
{
GameContent content = GameContent.instance;
yield return new WaitUntil(() => content != null);
try
{
RootSourcePath = content.RootSourceDir;
MainConfig = new(content.RootSourceDir, content.IsCreateNewProject, true);
Debug.Log($"{content.RootSourceDir} loading", this);
}
catch (Exception ex)
{
Debug.LogException(ex, this);
Debug.LogError($"{content.RootSourceDir} is not a valid project", this);
StartCoroutine(GameExit());
yield break;
}
// Load Song
if (Editor.EditorController.instance.MainGameController == this)
{
string clipPath = (string)MainConfig.FindItem("song", "");
AudioType audioType = (AudioType)MainConfig.FindItem("audioType", BasicAudioSystem.GetAudioType(clipPath));
if (string.IsNullOrEmpty(clipPath))
{
foreach (var file in MainConfig.ConfigFile.BackToParentDir().DirToolFileIter())
{
if (file.IsFile() && !file.IsFileEmpty())
{
if (BasicAudioSystem.GetAudioType(file.GetExtension()) != AudioType.UNKNOWN)
{
clipPath = file.GetFullPath();
break;
}
}
}
}
if (string.IsNullOrEmpty(clipPath) == false)
{
IEnumerator Run()
{
var clipFile = new Interaction(clipPath);
if (clipFile.Exists() == false)
clipFile = new(MainConfig.GetFile(clipPath).GetFullPath());
if (clipFile.Exists() == false)
{
Debug.LogError($"Cannt load {clipPath}", this);
yield break;
}
yield return MainAudio.LoadAudio(clipFile, audioType);
content.SongLoadOverCallback(MainAudio);
yield return GameAudioSystemInit();
}
StartCoroutine(Run());
}
}
else
{
MainAudio = Editor.EditorController.instance.MainGameController.MainAudio;
yield return GameAudioSystemInit();
}
yield return null;
// Setup Game Rules
if (Editor.EditorController.instance.MainGameController == this)
{
ScriptableObject.FastScriptableObjectTypen = content.ScriptableObjectTypen;
ScriptableObject.IsAutoPlay = content.IsAutoPlay;
SetupSongDuration = GameContent.instance.SetupSongDuration;
SetSongCurrentTime = GameContent.instance.SetSongCurrentTime;
SongOffset = GameContent.instance.SongOffset;
}
{
IsHideTrackRender = (bool)MainConfig.FindItem(nameof(IsHideTrackRender), false);
IsAutoPlay = GameContent.instance.IsAutoPlay;
ScriptEditor = (string)MainConfig.FindItem(nameof(ScriptEditor), ScriptEditor);
CurrentProjectDefaultFileStyle = content.CurrentProjectDefaultFileStyle;
}
yield return null;
MainConfig.SaveProperties();
// Load Root Object
{
while (MainConfig.Contains("root") == false)
{
string defaultRootPath = "root" + CurrentProjectDefaultFileStyle switch
{
ProjectDefaultFileStyle.PY => ".py",
_ => ".h"
};
if (content.IsCreateNewProject)
{
MainConfig["root"] = defaultRootPath;
if (MainConfig.CreateFile(defaultRootPath))
{
MainConfig.SaveProperties();
break;
}
}
Debug.LogError($"{nameof(defaultRootPath)} is cannt create or config's root property is not exist", this);
StartCoroutine(GameExit());
yield break;
}
var rootFileName = (string)MainConfig.FindItem("root");
var rootObject = new ToolFile(Path.Combine(content.RootSourceDir, rootFileName));
rootObject.MustExistsPath();
var rootGameObject = new GameObject(rootObject.GetName(true)).AddComponent<RootObject>();
rootGameObject.transform.SetParent(transform);
rootGameObject.ScriptName = rootObject.GetName(true);
rootGameObject.audioSystem = MainAudio;
rootGameObject.EnableScript(content.RootSourceDir, rootObject.GetFullPath(), this);
try
{
yield return rootGameObject.LoadScript(rootObject.LoadAsText());
}
finally
{
MainObject = rootGameObject;
}
}
}
public IEnumerator GameInitBySubWorld(List<RootObject.InputCatchEntry> entrys)
{
yield return GameInit();
MainObject.InputCatch = entrys;
}
[Content, SerializeField] private bool IsEnableUpdate = false;
private IEnumerator GameAudioSystemInit()
{
yield return null;
IsEnableUpdate = true;
yield return new WaitUntil(() => MainObject != null);
MainObject.ScriptUpdate(0, Time.deltaTime, ScriptableObject.TickType.Reset);
}
public void Stop()
{
MainAudio.Stop();
if (IsMain)
{
SetSongCurrentTime(-SongOffset);
}
MainObject.ScriptUpdate(-SongOffset, Time.deltaTime, ScriptableObject.TickType.Reset);
}
public void Pause()
{
MainAudio.Pause();
if (IsMain)
{
SetSongCurrentTime(CurrentTime);
}
MainObject.ScriptUpdate(CurrentTime, Time.deltaTime, ScriptableObject.TickType.Pause);
}
public void Play()
{
MainAudio.Play();
if (IsMain)
{
GameContent.instance.SetupSongDuration(0, MainAudio.CurrentClip.length);
}
SetSongCurrentTime(CurrentTime);
MainObject.ScriptUpdate(CurrentTime, Time.deltaTime, ScriptableObject.TickType.Start);
}
public void ForceScriptUpdate(ScriptableObject.TickType type = ScriptableObject.TickType.Update)
{
MainObject.ScriptUpdate(CurrentTime, Time.deltaTime, type);
}
private bool IsScrollTimeline = false;
#if UNITY_EDITOR
public ProfilerMarker s_PreparePerfMarker = new(nameof(GameController) + "Runtime");
#endif
private void Update()
{
float deltaTime = Time.deltaTime;
var currentClip = MainAudio.CurrentClip;
if (MainObject == null || IsEnableUpdate == false)
return;
// 因为涉及到其他UI和时间切片的全局更新所以需要提前
// TODO : 修正这个逻辑,这个逻辑是反常的
if (MainAudio.IsPlaying())
{
SetSongCurrentTime(CurrentTime);
MainObject.ScriptUpdate(CurrentTime, deltaTime, ScriptableObject.TickType.Update);
}
if (IsMain == false)
return;
#if UNITY_EDITOR
s_PreparePerfMarker.Begin(this);
#endif
#if UNITY_EDITOR
if (Keyboard.current[Key.LeftShift].isPressed)
#else
if (Keyboard.current[Key.LeftCtrl].isPressed)
#endif
{
if (currentClip != null)
{
if (Keyboard.current[Key.P].wasPressedThisFrame)
{
if (MainAudio.IsPlaying())
{
Pause();
}
else
{
Play();
}
}
else if (Keyboard.current[Key.S].wasPressedThisFrame)
{
Stop();
}
var scrollTime = Mouse.current.scroll.ReadValue().y / 120.0f;
if (Mathf.Approximately(scrollTime, 0) == false)
{
IsScrollTimeline = true;
if (MainAudio.IsPlaying())
{
Pause();
}
MainAudio.CurrentTime = Mathf.Clamp(MainAudio.CurrentTime + scrollTime, 0, currentClip.length);
if (IsMain)
{
SetSongCurrentTime(CurrentTime);
}
MainObject.ScriptUpdate(CurrentTime, deltaTime, ScriptableObject.TickType.Update);
}
else if (IsScrollTimeline == true)
{
IsScrollTimeline = false;
MainObject.ScriptUpdate(CurrentTime, deltaTime, ScriptableObject.TickType.Reset);
MainObject.ScriptUpdate(CurrentTime, deltaTime, ScriptableObject.TickType.Update);
}
}
}
#if UNITY_EDITOR
s_PreparePerfMarker.End();
#endif
}
public IEnumerator GameExit()
{
try
{
yield return MainObject.UnloadScript();
}
finally
{
Destroy(MainObject.gameObject);
if (Editor.EditorController.instance.MainGameController == this)
{
Editor.EditorController.instance.MainGameController = null;
}
SceneManager.UnloadSceneAsync(gameObject.scene, UnloadSceneOptions.UnloadAllEmbeddedSceneObjects);
}
}
}
}