From 1650126d55b4bb4ebdcfc4b5f4a4d8d74a2f387f Mon Sep 17 00:00:00 2001 From: CortexCore <2630229280@qq.com> Date: Fri, 8 Nov 2024 12:52:09 +0800 Subject: [PATCH] 1 --- Src/Core/Extensions/Func.cs | 24 ++ Src/Core/Extensions/IEnumerable.cs | 7 + Src/Core/Interfaces/IAsset.cs | 8 - Src/Core/Item/Item.cs | 24 +- Src/Core/Item/ItemContainer.cs | 83 ++++++ .../{Interfaces/Storage.meta => Pool.meta} | 2 +- Src/Core/Pool/IPoolService.cs | 32 +++ .../IPoolService.cs.meta} | 2 +- Src/Core/StateMachine.meta | 8 + Src/Core/StateMachine/AsyncStateMachine.cs | 133 ++++++++++ .../StateMachine/AsyncStateMachine.cs.meta | 11 + .../IStateMachine.cs | 14 +- .../IStateMachine.cs.meta | 0 Src/Core/UX/IUXService.cs | 8 + Src/Unity/Scripts/Console/BITConsole.cs | 251 +++++++++--------- .../Physics/UnityCollisionController.cs | 48 ++++ .../Physics/UnityCollisionController.cs.meta | 11 + Src/Unity/Scripts/Pool.meta | 8 + Src/Unity/Scripts/Pool/UnityPoolService.cs | 141 ++++++++++ .../Scripts/Pool/UnityPoolService.cs.meta | 11 + .../DictionaryReferenceScriptableObject.cs | 11 +- .../Scripts/UX/ContextMenu/UXContextMenu.cs | 114 +++++--- Src/Unity/Scripts/UX/Service/UXService.cs | 5 +- Src/Unity/UX/BITConsole.uxml | 12 +- Src/Unity/UX/SubMenu.uss | 9 +- .../MonkeyCommand/QuickFixBoxCollider.cs | 56 ++++ .../MonkeyCommand/QuickFixBoxCollider.cs.meta | 11 + 27 files changed, 851 insertions(+), 193 deletions(-) delete mode 100644 Src/Core/Interfaces/IAsset.cs rename Src/Core/{Interfaces/Storage.meta => Pool.meta} (77%) create mode 100644 Src/Core/Pool/IPoolService.cs rename Src/Core/{Interfaces/IAsset.cs.meta => Pool/IPoolService.cs.meta} (83%) create mode 100644 Src/Core/StateMachine.meta create mode 100644 Src/Core/StateMachine/AsyncStateMachine.cs create mode 100644 Src/Core/StateMachine/AsyncStateMachine.cs.meta rename Src/Core/{Interfaces => StateMachine}/IStateMachine.cs (84%) rename Src/Core/{Interfaces => StateMachine}/IStateMachine.cs.meta (100%) create mode 100644 Src/Unity/Scripts/Physics/UnityCollisionController.cs create mode 100644 Src/Unity/Scripts/Physics/UnityCollisionController.cs.meta create mode 100644 Src/Unity/Scripts/Pool.meta create mode 100644 Src/Unity/Scripts/Pool/UnityPoolService.cs create mode 100644 Src/Unity/Scripts/Pool/UnityPoolService.cs.meta create mode 100644 Src/UnityPluginsSupport/MonkeyCommand/QuickFixBoxCollider.cs create mode 100644 Src/UnityPluginsSupport/MonkeyCommand/QuickFixBoxCollider.cs.meta diff --git a/Src/Core/Extensions/Func.cs b/Src/Core/Extensions/Func.cs index 5e5f2ce..29150b2 100644 --- a/Src/Core/Extensions/Func.cs +++ b/Src/Core/Extensions/Func.cs @@ -39,5 +39,29 @@ namespace BITKit { return self?.GetInvocationList().Cast>(); } + + public static IEnumerable> CastAsFunc( + this Func self) + { + return self?.GetInvocationList().Cast>(); + } + + public static IEnumerable> CastAsFunc( + this Func self) + { + return self?.GetInvocationList().Cast>(); + } + + public static IEnumerable> CastAsFunc( + this Func self) + { + return self?.GetInvocationList().Cast>(); + } + + public static IEnumerable> CastAsFunc( + this Func self) + { + return self?.GetInvocationList().Cast>(); + } } } diff --git a/Src/Core/Extensions/IEnumerable.cs b/Src/Core/Extensions/IEnumerable.cs index 5a9d99a..78c679a 100644 --- a/Src/Core/Extensions/IEnumerable.cs +++ b/Src/Core/Extensions/IEnumerable.cs @@ -167,6 +167,13 @@ namespace BITKit } return false; } + + public static IEnumerable RemoveIn(this IEnumerable self, T t) + { + var list = self.ToList(); + list.Remove(t); + return list.ToArray(); + } public static bool TryRemove(this IDictionary self, TKey t) { if (self.ContainsKey(t)) diff --git a/Src/Core/Interfaces/IAsset.cs b/Src/Core/Interfaces/IAsset.cs deleted file mode 100644 index 7e3a939..0000000 --- a/Src/Core/Interfaces/IAsset.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace BITKit.IO -{ - public interface IAsset - { - string Name { get; set; } - byte[] Buffer{ get; set; } - } -} diff --git a/Src/Core/Item/Item.cs b/Src/Core/Item/Item.cs index e4144c6..cdf279f 100644 --- a/Src/Core/Item/Item.cs +++ b/Src/Core/Item/Item.cs @@ -94,6 +94,11 @@ namespace BITKit /// /// int Value => 10; + /// + /// 创建运行时物品 + /// + /// + IRuntimeItem CreateRuntimeItem(); } public interface IRuntimeItem : ICloneable @@ -101,7 +106,7 @@ namespace BITKit /// /// 运行时Id /// - public int Id { get; } + public int Id { get; set; } /// /// 配置Id @@ -133,14 +138,23 @@ namespace BITKit /// 被托管的物品 /// [Serializable] - public record RuntimeItem : IRuntimeItem + public struct RuntimeItem : IRuntimeItem { - public int Id { get; set; } = new Random().Next(); + public static RuntimeItem Create() + { + var item = new RuntimeItem() + { + Id = new Random().Next(), + RuntimeProperties = + new Dictionary() + }; + return item; + } + public int Id { get; set; } public int ScriptableId { get; set; } public int Amount { get; set; } - public IDictionary RuntimeProperties { get; set; } = - new Dictionary(); + public IDictionary RuntimeProperties { get; set; } public event Action OnRuntimePropertiesChanged; diff --git a/Src/Core/Item/ItemContainer.cs b/Src/Core/Item/ItemContainer.cs index 3107b60..c86fe31 100644 --- a/Src/Core/Item/ItemContainer.cs +++ b/Src/Core/Item/ItemContainer.cs @@ -1,4 +1,8 @@ using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.IO; +using System.Linq; using Microsoft.SqlServer.Server; namespace BITKit @@ -67,4 +71,83 @@ namespace BITKit /// event Action OnRelease; } + + public class RuntimeItemContainer : IRuntimeItemContainer + { + private readonly ConcurrentDictionary _items = new(); + public void Read(BinaryReader r) + { + throw new NotImplementedException(); + } + + public void Write(BinaryWriter w) + { + throw new NotImplementedException(); + } + + public int Id { get; set; } + public IRuntimeItem[] GetItems()=>_items.Values.ToArray(); + + public bool Add(IRuntimeItem item) + { + foreach (var func in AddFactory.CastAsFunc()) + { + if (func.Invoke(item) is false) + { + return false; + } + } + + _items.Set(item.Id,item); + + OnAdd?.Invoke(item); + //BIT4Log.Log($"添加了了:{item.Id}"); + + return true; + } + + public bool Remove(int id) + { + if (_items.TryGetValue(id, out var item) is false) return false; + + foreach (var func in RemoveFactory.CastAsFunc()) + { + if (func.Invoke(item) is false) + { + return false; + } + } + _items.TryRemove(item.Id); + OnRemove?.Invoke(item); + //BIT4Log.Log($"移除了:{id}"); + return true; + } + + public bool Drop(int id) + { + + if (_items.TryGetValue(id, out var item) is false) return false; + foreach (var func in DropFactory.CastAsFunc()) + { + if (func.Invoke(item) is false) + { + return false; + } + } + _items.TryRemove(item.Id); + OnDrop?.Invoke(item); + //BIT4Log.Log($"丢下了:{id}"); + return true; + } + + public event Func AddFactory; + public event Func RemoveFactory; + public event Func DropFactory; + public event Action OnAdd; + public event Action OnRemove; + public event Action OnSet; + public event Action OnDrop; + public event Action OnRebuild; + public event Action OnRelease; + } } \ No newline at end of file diff --git a/Src/Core/Interfaces/Storage.meta b/Src/Core/Pool.meta similarity index 77% rename from Src/Core/Interfaces/Storage.meta rename to Src/Core/Pool.meta index cd87980..20cd685 100644 --- a/Src/Core/Interfaces/Storage.meta +++ b/Src/Core/Pool.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: fe7ae68fb2f193640afdc79aef634c98 +guid: 787baa1105305fb4683a3196b038b1b3 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Src/Core/Pool/IPoolService.cs b/Src/Core/Pool/IPoolService.cs new file mode 100644 index 0000000..bd07ec4 --- /dev/null +++ b/Src/Core/Pool/IPoolService.cs @@ -0,0 +1,32 @@ +using System.Collections; +using System.Collections.Generic; +using Cysharp.Threading.Tasks; + +namespace BITKit.Pool +{ + /// + /// 对象池服务 + /// + public interface IPoolService + { + /// + /// 生成对象 + /// + /// 可寻址路径 + /// 类型 + /// + UniTask Spawn(string path) where T : class; + /// + /// 回收对象 + /// + /// 对象实例 + /// 可寻址路径 + /// 类型 + void Despawn(T obj,string path) where T : class; + /// + /// 初始化,在此提前生成所有对象 + /// + /// + UniTask InitializeAsync(); + } +} diff --git a/Src/Core/Interfaces/IAsset.cs.meta b/Src/Core/Pool/IPoolService.cs.meta similarity index 83% rename from Src/Core/Interfaces/IAsset.cs.meta rename to Src/Core/Pool/IPoolService.cs.meta index fb22ebc..a563474 100644 --- a/Src/Core/Interfaces/IAsset.cs.meta +++ b/Src/Core/Pool/IPoolService.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 3eb498b90aa487048a9fd9a3e9253dd8 +guid: 05f75f7f468db924bb3d58fc4a5aad99 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Src/Core/StateMachine.meta b/Src/Core/StateMachine.meta new file mode 100644 index 0000000..9f72c99 --- /dev/null +++ b/Src/Core/StateMachine.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 08ae9a3e8a64da349961e04bf98471ad +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Src/Core/StateMachine/AsyncStateMachine.cs b/Src/Core/StateMachine/AsyncStateMachine.cs new file mode 100644 index 0000000..61d7f02 --- /dev/null +++ b/Src/Core/StateMachine/AsyncStateMachine.cs @@ -0,0 +1,133 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Cysharp.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; + +namespace BITKit.StateMachine +{ + /// + /// 动态异步状态机 + /// + /// 异步状态 + public class AsyncStateMachine:IStateMachine ,IDisposable where T : IStateAsync + { + private enum AsyncState + { + None, + Initializing, + InEntering, + InExiting, + InUpdating, + } + private readonly IServiceCollection _serviceCollection; + public AsyncStateMachine(IServiceCollection serviceCollection) + { + _serviceCollection = serviceCollection; + } + public bool Enabled { get; set; } + public T CurrentState { get; set; } + private T _nextState; + public event Action OnStateChanging; + public event Action OnStateChanged; + public event Action OnStateRegistered; + public event Action OnStateUnRegistered; + public IDictionary StateDictionary { get; } = new Dictionary(); + private AsyncState _currentState; + private Task _currentTask; + private readonly CancellationTokenSource _cancellationTokenSource=new(); + public async void Initialize() + { + if (_currentState is not AsyncState.None) + { + throw new InvalidOperationException("状态机可能已初始化"); + } + + _currentState = AsyncState.Initializing; + foreach (var (type,value) in StateDictionary) + { + await value.InitializeAsync(); + } + foreach (var (type,value) in StateDictionary) + { + value.Initialize(); + } + _currentState = AsyncState.None; + } + + public void UpdateState(float deltaTime) + { + if(_cancellationTokenSource.IsCancellationRequested)return; + switch (_currentState) + { + case AsyncState.None: + if (_nextState is not null) + { + _currentState = AsyncState.InEntering; + _currentTask = CurrentState.OnStateEntryAsync(CurrentState).AsTask(); + + OnStateChanging?.Invoke(CurrentState,_nextState); + return; + } + _currentState = AsyncState.InUpdating; + if (CurrentState is not null) + { + _currentTask = CurrentState.OnStateUpdateAsync(deltaTime).AsTask(); + } + break; + case AsyncState.InExiting: + if (_currentTask.IsCompleted) + { + _currentState =_nextState is not null ? AsyncState.InEntering : AsyncState.None; + CurrentState.OnStateExit(CurrentState,_nextState); + if (_nextState is not null) + { + _currentTask = _nextState.OnStateEntryAsync(_nextState).AsTask(); + } + } + break; + case AsyncState.InEntering: + if (_currentTask.IsCompleted) + { + _currentState = AsyncState.None; + _nextState.OnStateEntry(CurrentState); + + OnStateChanged?.Invoke(CurrentState,_nextState); + + CurrentState = _nextState; + _nextState = default; + } + break; + case AsyncState.InUpdating: + if (_currentTask.IsCompleted) + { + _currentTask = null; + _currentState = AsyncState.None; + } + break; + } + } + + public void DisposeState() + { + + } + + public void TransitionState() where State : T + { + throw new InvalidOperationException("动态异步状态机不支持,请使用TransitionAsync"); + } + public void TransitionState(T state) + { + } + + public void Dispose() + { + _cancellationTokenSource.Cancel(); + _cancellationTokenSource.Dispose(); + } + } + +} diff --git a/Src/Core/StateMachine/AsyncStateMachine.cs.meta b/Src/Core/StateMachine/AsyncStateMachine.cs.meta new file mode 100644 index 0000000..ae07483 --- /dev/null +++ b/Src/Core/StateMachine/AsyncStateMachine.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0c936e10927235d499efcbbf19c45f90 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Src/Core/Interfaces/IStateMachine.cs b/Src/Core/StateMachine/IStateMachine.cs similarity index 84% rename from Src/Core/Interfaces/IStateMachine.cs rename to Src/Core/StateMachine/IStateMachine.cs index c9b2219..df4849e 100644 --- a/Src/Core/Interfaces/IStateMachine.cs +++ b/Src/Core/StateMachine/IStateMachine.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using Cysharp.Threading.Tasks; namespace BITKit.StateMachine { @@ -31,6 +32,18 @@ namespace BITKit.StateMachine void OnStateExit(IState old, IState newState); } + public interface IStateAsync:IState + { + /// + /// 识别符,用于识别多个相同状态但不同用途的状态机 + /// + int Identifier { get; set; } + UniTask InitializeAsync(); + UniTask OnStateEntryAsync(IState old); + UniTask OnStateUpdateAsync(float deltaTime); + UniTask OnStateExitAsync(IState old, IState newState); + } + public interface IStateMachine where T:IState { bool Enabled { get; set; } @@ -50,7 +63,6 @@ namespace BITKit.StateMachine void InvokeOnStateRegistered(T state){} void InvokeOnStateUnRegistered(T state){} } - public static class StateMachineUtils { public static void Register(this IStateMachine stateMachine, T newState) where T : IState diff --git a/Src/Core/Interfaces/IStateMachine.cs.meta b/Src/Core/StateMachine/IStateMachine.cs.meta similarity index 100% rename from Src/Core/Interfaces/IStateMachine.cs.meta rename to Src/Core/StateMachine/IStateMachine.cs.meta diff --git a/Src/Core/UX/IUXService.cs b/Src/Core/UX/IUXService.cs index e8407b4..74fcaa9 100644 --- a/Src/Core/UX/IUXService.cs +++ b/Src/Core/UX/IUXService.cs @@ -43,6 +43,14 @@ namespace BITKit.UX /// /// 面板名称 void Entry(string panelName); + /// + /// 当前面板 + /// + IUXPanel CurrentPanel { get; } + /// + /// 面板改变回调 + /// + public event Action OnPanelChanged; } } diff --git a/Src/Unity/Scripts/Console/BITConsole.cs b/Src/Unity/Scripts/Console/BITConsole.cs index 893d89c..9c62a2d 100644 --- a/Src/Unity/Scripts/Console/BITConsole.cs +++ b/Src/Unity/Scripts/Console/BITConsole.cs @@ -13,25 +13,82 @@ using System.Text; using System.IO; using System.Reflection; using System.Reflection.Emit; +using BITKit.Mod; using UnityEngine.InputSystem.Interactions; using Label = UnityEngine.UIElements.Label; +using Object = UnityEngine.Object; + // ReSharper disable PossibleMultipleEnumeration namespace BITKit.Console { - public class BITConsole : MonoBehaviour + public class UXConsole:IDisposable { - [RuntimeInitializeOnLoadMethod] - private static void Reload() - { - Application.logMessageReceivedThreaded += EnqueueLog; - } [BITCommand] + // ReSharper disable once UnusedMember.Global public static void Console_Exception_Print_StackTrace(int allow) { - exceptionPrintStackTrace = allow is 1; + _exceptionPrintStackTrace = allow is 1; } - private static bool exceptionPrintStackTrace = false; + + private readonly IMainTicker _ticker; + public UXConsole(IMainTicker ticker) + { + _ticker = ticker; + _singleton = this; + + _ticker.Add(OnTick); + + InitializeAsync(); + + Application.logMessageReceivedThreaded += EnqueueLog; + } + + private async void InitializeAsync() + { + var go = new GameObject("UXConsole"); + Object.DontDestroyOnLoad(go); + var document = go.AddComponent(); + document.sortingOrder = 1; + try + { + var panelSettings =await ModService.LoadAsset("ux_panel_settings"); + document.panelSettings = panelSettings; + } + catch (Exception e) + { + BIT4Log.Warning("未找到ux_panel_settings"); + throw; + } + document.visualTreeAsset = await ModService.LoadAsset("ux_console"); + + _rootVisualElement = document.rootVisualElement; + + UXUtils.Inject(this,_rootVisualElement); + + _commandSelector = new() + { + Container = _commandContainer, + }; + _commandSelector.OnSelected += x => + { + _textField.SetValueWithoutNotify(x.Name); + _textField.Blur(); + _textField.Focus(); + }; + _singleton = this; + + _textField.RegisterValueChangedCallback(OnTextFieldValueChanged); + _textField.RegisterCallback(OnKeyDown); + + _text.text = string.Empty; + + Toggle(false); + } + + private VisualElement _rootVisualElement; + + private static bool _exceptionPrintStackTrace; private class CommandSelector { public VisualElement Container { get; set; } @@ -100,111 +157,58 @@ namespace BITKit.Console public static async void Clear() { await BITApp.SwitchToMainThread(); - singleton.outputString.Clear(); - singleton.text.text = string.Empty; + _singleton._outputString.Clear(); + _singleton._text.text = string.Empty; } - private static BITConsole singleton; - [SerializeField] private UIDocument document; - [SerializeReference] private InputActionReference toggleAction; + private static UXConsole _singleton; - private static ConcurrentQueue<(string condition, string stackTrace, LogType type)> logQueue = new(); + private static readonly ConcurrentQueue<(string condition, string stackTrace, LogType type)> LOGQueue = new(); private static void EnqueueLog(string condition, string stackTrace, LogType type) { - logQueue.Enqueue((condition, stackTrace, type)); + LOGQueue.Enqueue((condition, stackTrace, type)); } - private readonly InputActionGroup _inputActionGroup=new() - { - allowGlobalActivation = false - }; - public int logLineLimit = 64; + private const int LOGLineLimit = 64; + [UXBindPath("commands-container")] - private VisualElement commandContainer; + private VisualElement _commandContainer; [UXBindPath("TextField")] - private TextField textField; + private TextField _textField; [UXBindPath("Text")] - private Label text; + private Label _text; [UXBindPath( "context-scrollview")] - private ScrollView scrollView; + private ScrollView _scrollView; private bool _isRunning; - private List outputString = new(); + private List _outputString = new(); private CommandSelector _commandSelector; - private void Start() - { - UXUtils.Inject(this); - - _commandSelector = new() - { - Container = commandContainer, - }; - _commandSelector.OnSelected += x => - { - textField.SetValueWithoutNotify(x.Name); - textField.Blur(); - textField.Focus(); - }; - - - singleton = this; - - - - textField.RegisterValueChangedCallback(OnTextFieldValueChanged); - textField.RegisterCallback(OnKeyDown); - - - text.text = string.Empty; - - - _inputActionGroup.RegisterCallback(toggleAction,Toggle); - //_inputActionGroup.RegisterCallback(nextOrPreviousAction, OnNextCommand); - - _inputActionGroup.allowInput.AddElement(this); - - Toggle(false); - - BIT4Log.OnNextLine += OnNextLine; - - destroyCancellationToken.Register(() => - { - BIT4Log.OnNextLine -= OnNextLine; - }); - - - } + private void OnNextLine() { - if (outputString.Count is not 0 && outputString.Last() != string.Empty) - outputString.Add(string.Empty); + if (_outputString.Count is not 0 && _outputString.Last() != string.Empty) + _outputString.Add(string.Empty); } - - private void OnDestroy() - { - _inputActionGroup.allowInput.RemoveElement(this); - } - public async void Toggle(bool active) + private void Toggle(bool active) { _commandSelector.SetMethods(null); - document.rootVisualElement.SetActive(active); + _rootVisualElement.SetActive(active); _isRunning = active; BITAppForUnity.AllowCursor.SetElements(this,active); BITInputSystem.AllowInput.SetDisableElements(this,active); - await UniTask.WaitForEndOfFrame(this); if (active) { - textField.SetValueWithoutNotify(string.Empty); + _textField.SetValueWithoutNotify(string.Empty); - textField.Focus(); + _textField.Focus(); - scrollView.ScrollToBottom(); + _scrollView.ScrollToBottom(); } else { - text.Blur(); + _text.Blur(); } } private void OnTextFieldValueChanged(ChangeEvent callback) @@ -215,11 +219,11 @@ namespace BITKit.Console _commandSelector.SetMethods(commands); - commandContainer.SetActive(commands.Length is not 0); + _commandContainer.SetActive(commands.Length is not 0); } else { - commandContainer.SetActive(false); + _commandContainer.SetActive(false); _commandSelector.SetMethods(null); } @@ -230,20 +234,17 @@ namespace BITKit.Console switch (keyDownEvent.keyCode) { case KeyCode.Return: - var cmd = textField.text; + var cmd = _textField.text; LogCallback($">{cmd}", string.Empty, LogType.Log); - textField.SetValueWithoutNotify(string.Empty); + _textField.SetValueWithoutNotify(string.Empty); await UniTask.NextFrame(); - - if (destroyCancellationToken.IsCancellationRequested) return; + _textField.Blur(); - textField.Blur(); - - textField.Focus(); + _textField.Focus(); BITCommands.Excute(cmd); @@ -252,10 +253,10 @@ namespace BITKit.Console break; case KeyCode.Tab: break; - case KeyCode.DownArrow when string.IsNullOrEmpty(textField.text) is false: + case KeyCode.DownArrow when string.IsNullOrEmpty(_textField.text) is false: _commandSelector.Index-=1; break; - case KeyCode.UpArrow when string.IsNullOrEmpty(textField.text) is false: + case KeyCode.UpArrow when string.IsNullOrEmpty(_textField.text) is false: _commandSelector.Index+=1; break; default: @@ -269,16 +270,6 @@ namespace BITKit.Console keyDownEvent.PreventDefault(); } } - private void Toggle(InputAction.CallbackContext context) - { - switch (context) - { - case { interaction: PressInteraction, performed: true }: - Toggle(!_isRunning); - break; - } - } - private async void LogCallback(string condition, string stackTrace, LogType type) { try @@ -286,33 +277,33 @@ namespace BITKit.Console switch (type) { case LogType.Error: - outputString.Add($"{condition}"); + _outputString.Add($"{condition}"); break; case LogType.Warning: - outputString.Add($"{condition}"); + _outputString.Add($"{condition}"); break; case LogType.Exception: - outputString.Add($"{condition}"); - if (exceptionPrintStackTrace) - outputString.Add($"{stackTrace}"); + _outputString.Add($"{condition}"); + if (_exceptionPrintStackTrace) + _outputString.Add($"{stackTrace}"); break; default: - outputString.Add(condition); + _outputString.Add(condition); break; } - var length = outputString.Count; - if (length > logLineLimit) + var length = _outputString.Count; + if (length > LOGLineLimit) { - outputString = outputString.GetRange(length - logLineLimit, logLineLimit); + _outputString = _outputString.GetRange(length - LOGLineLimit, LOGLineLimit); } StringBuilder stringBuilder = new(); - outputString.ForEach(x => stringBuilder.AppendLine(x)); + _outputString.ForEach(x => stringBuilder.AppendLine(x)); try { await BITApp.SwitchToMainThread(); - scrollView.ScrollToBottomAutomatic(); - text.text = stringBuilder.ToString(); + _scrollView.ScrollToBottomAutomatic(); + _text.text = stringBuilder.ToString(); } catch (OperationCanceledException) @@ -325,25 +316,39 @@ namespace BITKit.Console } } - private void Update() + private void OnTick(float delta) { - while (logQueue.TryDequeue(out var log)) + if (_rootVisualElement is null) return; + + if (Keyboard.current is { backquoteKey: { wasPressedThisFrame: true } }) + { + Toggle(_isRunning=!_isRunning); + return; + } + + if(LOGQueue.TryDequeue(out var log)) { LogCallback(log.condition, log.stackTrace, log.type); } if (_isRunning is false) return; - var pos = textField.worldTransform.GetPosition(); - var size = textField.layout.size; + var pos = _textField.worldTransform.GetPosition(); + var size = _textField.layout.size; - commandContainer.style.left = 0; - commandContainer.style.top = 0; + _commandContainer.style.left = 0; + _commandContainer.style.top = 0; pos.y += size.y; - commandContainer.transform.position = pos; + _commandContainer.transform.position = pos; - commandContainer.style.width = size.x; + _commandContainer.style.width = size.x; + } + + public void Dispose() + { + _ticker.Remove(OnTick); + Application.logMessageReceivedThreaded -= EnqueueLog; } } } \ No newline at end of file diff --git a/Src/Unity/Scripts/Physics/UnityCollisionController.cs b/Src/Unity/Scripts/Physics/UnityCollisionController.cs new file mode 100644 index 0000000..eba0319 --- /dev/null +++ b/Src/Unity/Scripts/Physics/UnityCollisionController.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace BITKit.Physics +{ + public class UnityCollisionController : MonoBehaviour + { + public event Action OnUnityCollisionEnter; + public event Action OnUnityCollisionStay; + public event Action OnUnityCollisionExit; + + public event Action OnUnityTriggerEnter; + public event Action OnUnityTriggerExit; + public event Action OnUnityTriggerStay; + + private void OnCollisionEnter(Collision other) + { + OnUnityCollisionEnter?.Invoke(other); + } + + private void OnCollisionStay(Collision other) + { + OnUnityCollisionStay?.Invoke(other); + } + + private void OnCollisionExit(Collision other) + { + OnUnityCollisionExit?.Invoke(other); + } + + private void OnTriggerEnter(Collider other) + { + OnUnityTriggerEnter?.Invoke(other); + } + + private void OnTriggerExit(Collider other) + { + OnUnityTriggerExit?.Invoke(other); + } + + private void OnTriggerStay(Collider other) + { + OnUnityTriggerStay?.Invoke(other); + } + } +} diff --git a/Src/Unity/Scripts/Physics/UnityCollisionController.cs.meta b/Src/Unity/Scripts/Physics/UnityCollisionController.cs.meta new file mode 100644 index 0000000..f0c4647 --- /dev/null +++ b/Src/Unity/Scripts/Physics/UnityCollisionController.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4c7ee9ea9aa58d94b86a980a58c8140a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Src/Unity/Scripts/Pool.meta b/Src/Unity/Scripts/Pool.meta new file mode 100644 index 0000000..0acdc35 --- /dev/null +++ b/Src/Unity/Scripts/Pool.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 10e55a4b52fd0e443a17f5267823bd92 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Src/Unity/Scripts/Pool/UnityPoolService.cs b/Src/Unity/Scripts/Pool/UnityPoolService.cs new file mode 100644 index 0000000..737080f --- /dev/null +++ b/Src/Unity/Scripts/Pool/UnityPoolService.cs @@ -0,0 +1,141 @@ +using System; +using System.Collections; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using BITKit.Mod; +using Cysharp.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using UnityEngine; +using Object = UnityEngine.Object; + +namespace BITKit.Pool +{ + public class UnityPoolService:IPoolService,IDisposable + { + private readonly IServiceProvider _serviceProvider; + + public UnityPoolService(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } + + private static readonly ConcurrentDictionary> Pool = new(); + private static readonly ConcurrentDictionary> UsingPool = new(); + private static readonly ConcurrentDictionary> ReadyPool = new(); + + public void Dispose() + { + var hashset = new HashSet(); + foreach (var (_,list) in Pool) + { + foreach (var obj in list) + { + if (obj is not Component component) continue; + if (!hashset.Add(component.gameObject)) continue; + if (component.gameObject) + Object.Destroy(component.gameObject); + } + } + Pool.Clear(); + UsingPool.Clear(); + ReadyPool.Clear(); + } + + public async UniTask Spawn(string path) where T : class + { + if (Pool.ContainsKey(path)) + { + var readyQueue = ReadyPool[path]; + var usingList = UsingPool[path]; + if (readyQueue.TryDequeue(out var obj)) + { + var value = obj as T; + usingList.Add(value); + return obj as T; + } + + if (usingList.Count>0) + { + obj = usingList[0]; + usingList.RemoveAt(0); + usingList.Add(obj); + +#if UNITY_5_3_OR_NEWER + if (obj is GameObject gameObject) + { + gameObject.SetActive(false); + gameObject.SetActive(true); + } +#endif + + return obj as T; + } + } + + var list = Pool.GetOrCreate(path); + + UsingPool.GetOrCreate(path); + ReadyPool.GetOrCreate(path); + + #if UNITY_5_3_OR_NEWER + if (typeof(Object).IsAssignableFrom(typeof(T))) + { + var asset =await ModService.LoadAsset(path); + if (asset is Object o) + { + var instance = Object.Instantiate(o); + list.Add(instance); + UsingPool.GetOrCreate(path).Add(instance); + ReadyPool.GetOrCreate(path); + return instance as T; + } + } + #endif + + //检查T的构造函数,如果有需要参数的构造函数,就从ServiceProvider中获取,如果没有,则直接通过System.Activator创建 + if (typeof(T).GetConstructors().Any(constructorInfo => constructorInfo.GetParameters().Length is 0)) + { + var value = Activator.CreateInstance(); + list.Add(value); + UsingPool.GetOrCreate(path).Add(value); + ReadyPool.GetOrCreate(path); + return value; + } + { + var value = _serviceProvider.GetRequiredService(); + list.Add(value); + UsingPool.GetOrCreate(path).Add(value); + ReadyPool.GetOrCreate(path); + return value; + } + } + + public void Despawn(T obj, string path) where T : class + { + if (UsingPool.TryGetValue(path, out var value)) + { + value.Remove(obj); + ReadyPool[path].Enqueue(obj); +#if UNITY_5_3_OR_NEWER + if (obj is GameObject gameObject) + { + gameObject.SetActive(false); + } +#endif + return; + } + if (Pool.ContainsKey(path)) return; + Pool.GetOrCreate(path).Add(obj); + ReadyPool.GetOrCreate(path).Enqueue(obj); + + + } + + public UniTask InitializeAsync() + { + return UniTask.CompletedTask; + } + } + +} diff --git a/Src/Unity/Scripts/Pool/UnityPoolService.cs.meta b/Src/Unity/Scripts/Pool/UnityPoolService.cs.meta new file mode 100644 index 0000000..585becc --- /dev/null +++ b/Src/Unity/Scripts/Pool/UnityPoolService.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 58aae7a560a8881468df0f0f3a137f4a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Src/Unity/Scripts/Reference/DictionaryReferenceScriptableObject.cs b/Src/Unity/Scripts/Reference/DictionaryReferenceScriptableObject.cs index fa74396..4047a02 100644 --- a/Src/Unity/Scripts/Reference/DictionaryReferenceScriptableObject.cs +++ b/Src/Unity/Scripts/Reference/DictionaryReferenceScriptableObject.cs @@ -5,6 +5,7 @@ using AYellowpaper.SerializedCollections; #if UNITY_EDITOR using UnityEditor; +using YooAsset; #endif using UnityEngine; @@ -21,7 +22,15 @@ namespace BITKit { if (_singleton == null) { - //_singleton = ScriptableObjectHelper.Get(); +#if UNITY_EDITOR + _singleton = + AssetDatabase.LoadAssetAtPath( + "Assets/Artists/Configs/reference_dictionary.asset"); +#else + var task = YooAssets.LoadAssetAsync("reference_directory"); + task.WaitForAsyncComplete(); + _singleton=task.AssetObject as DictionaryReferenceScriptableObject; +#endif } return _singleton; } diff --git a/Src/Unity/Scripts/UX/ContextMenu/UXContextMenu.cs b/Src/Unity/Scripts/UX/ContextMenu/UXContextMenu.cs index cdeb4b3..5334e8f 100644 --- a/Src/Unity/Scripts/UX/ContextMenu/UXContextMenu.cs +++ b/Src/Unity/Scripts/UX/ContextMenu/UXContextMenu.cs @@ -1,12 +1,12 @@ using System; -using System.Collections; using System.Collections.Generic; -using System.Runtime.Remoting.Contexts; +using System.ComponentModel.Design; using UnityEngine; using UnityEngine.UIElements; using UnityEngine.InputSystem; -using BITKit; -using Cysharp.Threading.Tasks; +using BITKit.Mod; +using Object = UnityEngine.Object; + namespace BITKit.UX.Internal { public class ContextMenu : IContextMenu @@ -20,16 +20,16 @@ namespace BITKit.UX.Internal { public Label(string text) { - this.text = text; + _text = text; } - string text; + private readonly string _text; public override VisualElement GetVisualElement() { - UnityEngine.UIElements.Label label = new(text); + UnityEngine.UIElements.Label label = new(_text); return label; } } - [System.Serializable] + [Serializable] public class TestContextMenu { public void Execute() @@ -45,19 +45,20 @@ namespace BITKit.UX.Internal { public Button(string text, params Action[] actions) { - this.text = text; + _text = text; foreach (var x in actions) { - action += x; + _action += x; } } - string text; - Action action; + + private readonly string _text; + private readonly Action _action; public override VisualElement GetVisualElement() { UnityEngine.UIElements.Button button = new(); - button.clicked += action; - button.text = text; + button.clicked += _action; + button.text = _text; return button; } } @@ -77,14 +78,14 @@ namespace BITKit.UX } public static ContextMenuBuilder BuildAction(this ContextMenuBuilder self, string text, Action action) { - self.Add(new Internal.Button(text, action, self.Excute)); + self.Add(new Internal.Button(text, action, self.Execute)); return self; } } public class ContextMenuBuilder { - readonly List contexts = new(); - public event Action OnExcuted; + private readonly List _contexts = new(); + public event Action OnExecuted; private ContextMenuBuilder() { @@ -97,25 +98,48 @@ namespace BITKit.UX { UXContextMenu.Singleton.Create(this); } - internal void Excute() + internal void Execute() { - OnExcuted?.Invoke(); + OnExecuted?.Invoke(); } - public void Add(IContextMenu x) => contexts.Add(x); - public IEnumerable GetContextMenus() => contexts.ToArray(); + public void Add(IContextMenu x) => _contexts.Add(x); + public IEnumerable GetContextMenus() => _contexts.ToArray(); } - public class UXContextMenu : MonoBehaviour + public class UXContextMenu:IDisposable { internal static UXContextMenu Singleton; - [SerializeField] private UIDocument document; - private VisualElement root; - private VisualElement container; - private void Awake() + private readonly IUXService _uxService; + private VisualElement _root; + private VisualElement _container; + public UXContextMenu(IUXService uxService) { + _uxService = uxService; Singleton = this; - root = document.rootVisualElement; - container = document.rootVisualElement[1]; - root.Q("background-image").RegisterCallback(x => + uxService.OnPanelChanged += OnPanelChanged; + InitializeAsync(); + } + + private async void InitializeAsync() + { + var go = new GameObject("UXConsole"); + Object.DontDestroyOnLoad(go); + var document = go.AddComponent(); + document.sortingOrder = 1; + try + { + var panelSettings =await ModService.LoadAsset("ux_panel_settings"); + document.panelSettings = panelSettings; + } + catch (Exception) + { + BIT4Log.Warning("未找到ux_panel_settings"); + throw; + } + document.visualTreeAsset = await ModService.LoadAsset("ux_context_menu"); + + _root = document.rootVisualElement; + _container = _root.Q("menu-container"); + _root.Q("background-image").RegisterCallback(_ => { Close(); }); @@ -125,25 +149,35 @@ namespace BITKit.UX { var pos = Mouse.current.position.ReadValue(); pos.y = Screen.height - pos.y; - pos = RuntimePanelUtils.ScreenToPanel(root.panel, pos); + pos = RuntimePanelUtils.ScreenToPanel(_root.panel, pos); - container.style.position = Position.Absolute; - container.style.left = pos.x; - container.style.top = pos.y; - container.Clear(); + _container.style.position = Position.Absolute; + _container.style.left = pos.x; + _container.style.top = pos.y; + _container.Clear(); - root.SetActive(true); + _root.SetActive(true); foreach (var context in builder.GetContextMenus()) { - container.Add(context.GetVisualElement()); + _container.Add(context.GetVisualElement()); } - builder.OnExcuted += Close; + builder.OnExecuted += Close; } - void Close() + private void Close() { - container.Clear(); - root.SetActive(false); + _container.Clear(); + _root.SetActive(false); + } + + public void Dispose() + { + _uxService.OnPanelChanged -= OnPanelChanged; + } + + private void OnPanelChanged(IUXPanel arg1, IUXPanel arg2) + { + Close(); } } } diff --git a/Src/Unity/Scripts/UX/Service/UXService.cs b/Src/Unity/Scripts/UX/Service/UXService.cs index 8fb7a98..31ec342 100644 --- a/Src/Unity/Scripts/UX/Service/UXService.cs +++ b/Src/Unity/Scripts/UX/Service/UXService.cs @@ -103,7 +103,9 @@ namespace BITKit.UX public void Entry(IUXPanel panel) => _entryQueue.Push(panel); public void Entry(string panelName) => _entryQueueByName.TryAdd(panelName); - + public IUXPanel CurrentPanel => _currentPanel; + public event Action OnPanelChanged; + public void Return() { if(_windowEntryGroup.TryGetEntried(out _)) @@ -124,6 +126,7 @@ namespace BITKit.UX private void OnEntry(IUXPanel obj) { + OnPanelChanged?.Invoke(_currentPanel,obj); _currentPanel = obj; } private void OnTick(float delta) diff --git a/Src/Unity/UX/BITConsole.uxml b/Src/Unity/UX/BITConsole.uxml index 6478fb8..1e44961 100644 --- a/Src/Unity/UX/BITConsole.uxml +++ b/Src/Unity/UX/BITConsole.uxml @@ -2,15 +2,15 @@