This commit is contained in:
CortexCore
2024-11-03 16:42:23 +08:00
commit b125894cc3
5904 changed files with 1070129 additions and 0 deletions

View File

@@ -0,0 +1,21 @@
{
"name": "BITKit.Scenes",
"rootNamespace": "",
"references": [
"GUID:14fe60d984bf9f84eac55c6ea033a8f4",
"GUID:045a42f233e479d41adc32d02b99631e",
"GUID:f51ebe6a0ceec4240a699833d6309b23",
"GUID:6ef4ed8ff60a7aa4bb60a8030e6f4008",
"GUID:e34a5702dd353724aa315fb8011f08c3",
"GUID:296866320aab85a42a0403bf684bac59"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

@@ -0,0 +1,17 @@
{
"name": "BITKit.Scenes.Core",
"rootNamespace": "",
"references": [
"GUID:14fe60d984bf9f84eac55c6ea033a8f4",
"GUID:f51ebe6a0ceec4240a699833d6309b23"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

@@ -0,0 +1,124 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using Cysharp.Threading.Tasks;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace BITKit.SceneManagement
{
/// <summary>
/// 场景服务,负责场景的加载和卸载
/// </summary>
public interface ISceneService
{
/// <summary>
/// 在场景加载完成后,是否初始化主场景
/// </summary>
bool InitializeMainSceneOnLoad { get; }
string[] GetScenes(params string[] tags);
/// <summary>
/// 加载场景
/// </summary>
/// <param name="sceneName">场景名称,通常为AddressablePath</param>
/// <param name="cancellationToken">取消令牌</param>
/// <param name="loadSceneMode">加载模式</param>
/// <param name="activateOnLoad">加载完成后激活</param>
/// <returns></returns>
public UniTask LoadSceneAsync(string sceneName,CancellationToken cancellationToken, LoadSceneMode loadSceneMode = LoadSceneMode.Additive, bool activateOnLoad = true);
public UniTask UnloadSceneAsync(string sceneName,CancellationToken cancellationToken);
/// <summary>
/// 开始加载场景的回调
/// </summary>
event Action<string> OnLoadScene;
/// <summary>
/// 加载场景进度的回调
/// </summary>
event Action<string,float> OnSceneLoadProgress;
/// <summary>
/// 场景加载完成的回调
/// </summary>
event Action<string> OnSceneLoaded;
/// <summary>
/// 注册加载任务
/// </summary>
void RegisterLoadTaskAsync(Func<UniTask> task);
/// <summary>
/// 注销加载任务
/// </summary>
/// <param name="task"></param>
void UnRegisterLoadTaskAsync(Func<UniTask> task);
/// <summary>
/// 当开始卸载场景时
/// </summary>
event Action<string> OnUnloadScene;
/// <summary>
/// 当场景卸载完成时
/// </summary>
event Action<string> OnSceneUnloaded;
}
/// <summary>
/// 场景服务代理实现,主要用于快速继承
/// </summary>
public abstract class SceneServiceImplement:ISceneService
{
private ISceneService _sceneServiceImplementation1 => _sceneServiceImplementation;
protected abstract ISceneService _sceneServiceImplementation { get; }
public bool InitializeMainSceneOnLoad => _sceneServiceImplementation.InitializeMainSceneOnLoad;
public string[] GetScenes(params string[] tags)=> _sceneServiceImplementation.GetScenes(tags);
public UniTask LoadSceneAsync(string sceneName,CancellationToken cancellationToken, LoadSceneMode loadSceneMode = LoadSceneMode.Additive,
bool activateOnLoad = true)
{
return _sceneServiceImplementation.LoadSceneAsync(sceneName,cancellationToken, loadSceneMode, activateOnLoad);
}
public UniTask UnloadSceneAsync(string sceneName, CancellationToken cancellationToken)
{
return _sceneServiceImplementation1.UnloadSceneAsync(sceneName, cancellationToken);
}
public event Action<string> OnLoadScene
{
add => _sceneServiceImplementation.OnLoadScene += value;
remove => _sceneServiceImplementation.OnLoadScene -= value;
}
public event Action<string, float> OnSceneLoadProgress
{
add => _sceneServiceImplementation.OnSceneLoadProgress += value;
remove => _sceneServiceImplementation.OnSceneLoadProgress -= value;
}
public event Action<string> OnSceneLoaded
{
add => _sceneServiceImplementation.OnSceneLoaded += value;
remove => _sceneServiceImplementation.OnSceneLoaded -= value;
}
public void RegisterLoadTaskAsync(Func<UniTask> task)
{
_sceneServiceImplementation.RegisterLoadTaskAsync(task);
}
public void UnRegisterLoadTaskAsync(Func<UniTask> task)
{
_sceneServiceImplementation.UnRegisterLoadTaskAsync(task);
}
public event Action<string> OnUnloadScene
{
add => _sceneServiceImplementation1.OnUnloadScene += value;
remove => _sceneServiceImplementation1.OnUnloadScene -= value;
}
public event Action<string> OnSceneUnloaded
{
add => _sceneServiceImplementation1.OnSceneUnloaded += value;
remove => _sceneServiceImplementation1.OnSceneUnloaded -= value;
}
}
}

View File

@@ -0,0 +1,20 @@
{
"name": "BITKit.Scenes.Editor",
"rootNamespace": "",
"references": [
"GUID:14fe60d984bf9f84eac55c6ea033a8f4",
"GUID:8053c75fd7e91654b965793a9efd931a",
"GUID:045a42f233e479d41adc32d02b99631e"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [
"UNITY_EDITOR"
],
"versionDefines": [],
"noEngineReferences": false
}

View File

@@ -0,0 +1,95 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;
using Object = UnityEngine.Object;
namespace BITKit
{
public class MaterialPaletteWindow : EditorWindow
{
[MenuItem("Tools/Scenes/Material Palette")]
public static void Open()
{
GetWindow<MaterialPaletteWindow>().Show();
}
private Button buildButton;
private Label _titleLabel;
private VisualElement _container;
private MeshRenderer[] _renderers=Array.Empty<MeshRenderer>();
private void OnEnable()
{
UnityEditor.Selection.selectionChanged += OnSelectionChanged;
rootVisualElement.Clear();
_titleLabel = rootVisualElement.Create<Label>();
_container = rootVisualElement.Create<VisualElement>();
_titleLabel.text = "选择一个物体";
}
private void OnDisable()
{
UnityEditor.Selection.selectionChanged -= OnSelectionChanged;
}
private void OnSelectionChanged()
{
var actives = UnityEditor.Selection.gameObjects;
_container.Clear();
_renderers = actives.SelectMany(x => x.GetComponentsInChildren<MeshRenderer>()).ToArray();
var materials = _renderers.SelectMany(x => x.sharedMaterials).Distinct().ToArray();
_titleLabel.text = actives is not {Length:0} ?$"选择了{actives.Length }个物体,{materials.Length}个材质" : "未选择物体";
foreach (var material in materials)
{
var filed = _container.Create<ObjectField>();
filed.label = material.name;
filed.objectType = typeof(Material);
filed.allowSceneObjects = false;
filed.value = material;
filed.RegisterValueChangedCallback(OnChanged);
}
}
private void OnChanged(ChangeEvent<Object> evt)
{
if(evt.newValue is not Material value) return;
var list = new List<Object>();
foreach (var renderer in _renderers)
{
var sharedMaterials = renderer.sharedMaterials;
var isDirty = false;
for (var i = 0; i < sharedMaterials.Length; i++)
{
var current = sharedMaterials[i];
if(current != evt.previousValue) continue;
sharedMaterials[i] = value;
isDirty = true;
}
if (!isDirty) continue;
renderer.sharedMaterials = sharedMaterials;
list.Add(renderer);
EditorUtility.SetDirty(renderer);
}
if (list.Count > 0)
{
OnSelectionChanged();
}
}
}
}

View File

@@ -0,0 +1,32 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
namespace BITKit.SceneManagement.Editor
{
public class SceneServiceEditorWindow : EditorWindow
{
[MenuItem("Tools/Scenes/SceneService")]
public static void Open()
{
GetWindow<SceneServiceEditorWindow>("SceneService").Show();
}
private Toggle allowInitializeToggle;
private void OnEnable()
{
allowInitializeToggle = rootVisualElement.Create<Toggle>();
allowInitializeToggle.label = "Allow Initialize";
allowInitializeToggle.SetValueWithoutNotify(SceneService.AllowInitialize);
allowInitializeToggle.RegisterValueChangedCallback(evt =>
{
SceneService.AllowInitialize = evt.newValue;
});
}
}
}

View File

@@ -0,0 +1,286 @@
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using BITKit.IO;
using Cysharp.Threading.Tasks;
using UnityEngine;
using UnityEngine.SceneManagement;
using YooAsset;
using Debug = UnityEngine.Debug;
using Object = UnityEngine.Object;
// ReSharper disable Unity.LoadSceneWrongIndex
namespace BITKit.SceneManagement
{
[Serializable]
public class SceneServiceSingleton : SceneServiceImplement
{
protected override ISceneService _sceneServiceImplementation => SceneService.Singleton;
}
[Serializable]
public class SceneServiceSingletonProxy:ISceneService
{
private ISceneService _sceneServiceImplementation => SceneService.Singleton;
public bool InitializeMainSceneOnLoad=>SceneService.Singleton.InitializeMainSceneOnLoad;
public string[] GetScenes(params string[] tags)
{
return SceneService.Singleton.GetScenes(tags);
}
public UniTask LoadSceneAsync(string sceneName, CancellationToken cancellationToken,
LoadSceneMode loadSceneMode = LoadSceneMode.Additive, bool activateOnLoad = true)=>SceneService.Singleton.LoadSceneAsync(sceneName,cancellationToken,loadSceneMode,activateOnLoad);
public UniTask UnloadSceneAsync(string sceneName, CancellationToken cancellationToken)
{
return _sceneServiceImplementation.UnloadSceneAsync(sceneName, cancellationToken);
}
public event Action<string> OnLoadScene
{
add => SceneService.OnLoadScene += value;
remove => SceneService.OnLoadScene -= value;
}
public event Action<string, float> OnSceneLoadProgress
{
add => SceneService.OnSceneLoadProgress += value;
remove => SceneService.OnSceneLoadProgress -= value;
}
public event Action<string> OnSceneLoaded
{
add => SceneService.OnSceneLoaded += value;
remove => SceneService.OnSceneLoaded -= value;
}
public void RegisterLoadTaskAsync(Func<UniTask> task)
{
_sceneServiceImplementation.RegisterLoadTaskAsync(task);
}
public void UnRegisterLoadTaskAsync(Func<UniTask> task)
{
_sceneServiceImplementation.UnRegisterLoadTaskAsync(task);
}
public event Action<string> OnUnloadScene
{
add => _sceneServiceImplementation.OnUnloadScene += value;
remove => _sceneServiceImplementation.OnUnloadScene -= value;
}
public event Action<string> OnSceneUnloaded
{
add => _sceneServiceImplementation.OnSceneUnloaded += value;
remove => _sceneServiceImplementation.OnSceneUnloaded -= value;
}
}
public class SceneService : MonoBehaviour,ISceneService
{
[BITCommand]
public static async void Map(string mapName)
{
await UniTask.SwitchToMainThread(Singleton.destroyCancellationToken);
Singleton.LoadSceneAsync(mapName,Singleton.destroyCancellationToken).Forget();
}
#if UNITY_EDITOR
public static bool AllowInitialize=true;
[RuntimeInitializeOnLoadMethod]
private static void Initialize()
{
OnLoadScene =null;
OnSceneLoadProgress = null;
OnSceneLoaded = null;
if (AllowInitialize && SceneManager.sceneCount is not 0)
{
SceneManager.LoadSceneAsync(0);
}
}
#endif
public static event Action<string> OnLoadScene;
public static event Action<string, float> OnSceneLoadProgress;
public static event Action<string> OnSceneLoaded;
internal static SceneService Singleton;
#if UNITY_EDITOR
[SerializeField] private Optional<float> allowLoadDelay;
#endif
[SerializeField] private Optional<string> allowLoadMainScene;
[SerializeField] private Optional<string> allowMenuScene;
private readonly Dictionary<string, Scene> LoadedObjects = new();
private CancellationToken _cancellationToken;
private readonly ConcurrentDictionary<string,ResourcePackage> _packages=new();
private void Awake()
{
Singleton = this;
_cancellationToken = gameObject.GetCancellationTokenOnDestroy();
}
private void Start()
{
if (allowMenuScene.Allow)
{
YooAssets
.LoadSceneAsync(allowMenuScene.Value).ToUniTask(cancellationToken: _cancellationToken)
.Forget();
}
if (allowLoadMainScene.Allow is false) return;
LoadSceneAsync(allowLoadMainScene.Value,_cancellationToken,LoadSceneMode.Single,false).Forget();
}
public bool InitializeMainSceneOnLoad => true;
public string[] GetScenes(params string[] tags)
{
try
{
_packages.Clear();
var list = new List<string>();
foreach (var package in YooAssetUtils.RegisteredResourcePackages)
{
foreach (var assetInfo in package.GetAssetInfos(tags))
{
list.Add(assetInfo.Address);
_packages.TryAdd(assetInfo.Address,package);
}
}
return list.ToArray();
}
catch (Exception e)
{
BIT4Log.Warning<ISceneService>(JsonHelper.Get(YooAssetUtils.RegisteredPackages) );
throw;
}
}
public async UniTask LoadSceneAsync(string sceneName, CancellationToken cancellationToken,
LoadSceneMode loadSceneMode = LoadSceneMode.Additive,
bool activateOnLoad = true)
{
try
{
var stopwatchWatcher = new Stopwatch();
BIT4Log.Log<SceneService>($"正在加载场景:{sceneName}");
OnLoadScene?.Invoke(sceneName);
await Task.Delay(100, destroyCancellationToken);
stopwatchWatcher.Start();
#if UNITY_EDITOR
if (allowLoadDelay.Allow)
{
var progress = 0f;
while (progress < allowLoadDelay.Value)
{
OnSceneLoadProgress?.Invoke(sceneName, progress += 1 / allowLoadDelay.Value * Time.deltaTime);
cancellationToken.ThrowIfCancellationRequested();
await UniTask.NextFrame(cancellationToken);
}
}
#endif
// var asyncOperation = Addressables.LoadSceneAsync(sceneName, loadSceneMode, activateOnLoad);
// while (asyncOperation.IsDone is false)
// {
// await UniTask.NextFrame(cancellationToken);
// var progress = asyncOperation.PercentComplete;
// OnSceneLoadProgress?.Invoke(sceneName,progress);
// }
var sceneMode = UnityEngine.SceneManagement.LoadSceneMode.Single;
var package = _packages[sceneName];
var handle = package.LoadSceneAsync(sceneName, sceneMode);
while (handle.IsDone is false)
{
var progress = handle.Progress;
await UniTask.NextFrame(cancellationToken);
OnSceneLoadProgress?.Invoke(sceneName, progress);
}
LoadedObjects.Add(sceneName, handle.SceneObject);
OnSceneLoadProgress?.Invoke(sceneName, 1);
await Task.Delay(384, cancellationToken);
foreach (var x in _onSceneLoadedAsyncList.ToArray())
{
await x.Invoke();
if (destroyCancellationToken.IsCancellationRequested) return;
}
OnSceneLoaded?.Invoke(sceneName);
stopwatchWatcher.Stop();
// if (activateOnLoad is false)
// {
// asyncOperation.Result.ActivateAsync().ToUniTask(cancellationToken: cancellationToken).Forget();
// _loadedObjects.Add(asyncOperation.Result);
// }
BIT4Log.Log<SceneService>($"场景:{sceneName}加载完成,耗时:{stopwatchWatcher.ElapsedMilliseconds}ms");
}
catch (OperationCanceledException)
{
}
}
public async UniTask UnloadSceneAsync(string sceneName, CancellationToken cancellationToken)
{
await UniTask.SwitchToMainThread();
OnUnloadScene?.Invoke(sceneName);
await Task.Delay(100, destroyCancellationToken);
await UniTask.SwitchToMainThread();
if (LoadedObjects.TryRemove(sceneName) is false) return;
//await SceneManager.UnloadSceneAsync(scene);
SceneManager.LoadScene(1);
destroyCancellationToken.ThrowIfCancellationRequested();
await UniTask.SwitchToMainThread();
OnSceneUnloaded?.Invoke(sceneName);
}
event Action<string> ISceneService.OnLoadScene
{
add=>OnLoadScene+=value;
remove=>OnLoadScene-=value;
}
event Action<string, float> ISceneService.OnSceneLoadProgress
{
add=>OnSceneLoadProgress+=value;
remove => OnSceneLoadProgress -= value;
}
event Action<string> ISceneService.OnSceneLoaded
{
add=>OnSceneLoaded+=value;
remove => OnSceneLoaded -= value;
}
private readonly List<Func<UniTask>> _onSceneLoadedAsyncList=new();
public void RegisterLoadTaskAsync(Func<UniTask> task)
{
_onSceneLoadedAsyncList.Add(task);
}
public void UnRegisterLoadTaskAsync(Func<UniTask> task)
{
_onSceneLoadedAsyncList.Remove(task);
}
public event Action<string> OnUnloadScene;
public event Action<string> OnSceneUnloaded;
}
}

View File

@@ -0,0 +1,21 @@
{
"name": "BITKit.Scenes.UX",
"rootNamespace": "",
"references": [
"GUID:14fe60d984bf9f84eac55c6ea033a8f4",
"GUID:6ef4ed8ff60a7aa4bb60a8030e6f4008",
"GUID:045a42f233e479d41adc32d02b99631e",
"GUID:d525ad6bd40672747bde77962f1c401e",
"GUID:49b49c76ee64f6b41bf28ef951cb0e50",
"GUID:f51ebe6a0ceec4240a699833d6309b23"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}