diff --git a/Src/Core/ECS/EntitiesService.cs b/Src/Core/ECS/EntitiesService.cs index 5301443..eb390ee 100644 --- a/Src/Core/ECS/EntitiesService.cs +++ b/Src/Core/ECS/EntitiesService.cs @@ -161,7 +161,17 @@ namespace BITKit.Entities if (instances.TryGetValue(h0, out var v0) is false) { - instances[h0] = v0 = _entitiesInternal[id].ServiceProvider.GetRequiredService(); + try + { + instances[h0] = v0 = _entitiesInternal[id].ServiceProvider.GetRequiredService(); + } + catch (KeyNotFoundException) + { + _logger.LogWarning($"Missing Entity {id},Ignore for now"); + + hashset.Remove(id); + break; + } } array[i] = Unsafe.As(v0); diff --git a/Src/Core/ECS/Entity.cs b/Src/Core/ECS/Entity.cs index 4ea0f8b..53608cd 100644 --- a/Src/Core/ECS/Entity.cs +++ b/Src/Core/ECS/Entity.cs @@ -39,7 +39,7 @@ namespace BITKit.Entities public void Dispose() { - _serviceProvider.Dispose(); + _serviceProvider?.Dispose(); } } } \ No newline at end of file diff --git a/Src/Core/Extensions/IEnumerable.cs b/Src/Core/Extensions/IEnumerable.cs index b330fa4..512dd50 100644 --- a/Src/Core/Extensions/IEnumerable.cs +++ b/Src/Core/Extensions/IEnumerable.cs @@ -152,20 +152,11 @@ namespace BITKit list.Remove(t); return list.ToArray(); } - public static bool TryRemove(this IDictionary self, TKey t) - { - return self.ContainsKey(t) && self.Remove(t); - } + + public static bool TryRemove(this IDictionary self, TKey t) => self.Remove(t); public static void Set(this IDictionary self, TKey key, TValue value) { - if (self.ContainsKey(key)) - { - self[key] = value; - } - else - { - self.Add(key, value); - } + self[key] = value; } public static TValue Get(this IDictionary self) { diff --git a/Src/Core/UX/IUXSnackBar.cs b/Src/Core/UX/IUXSnackBar.cs new file mode 100644 index 0000000..97903df --- /dev/null +++ b/Src/Core/UX/IUXSnackBar.cs @@ -0,0 +1,16 @@ + +namespace Net.BITKit.UX.SnackBar +{ + public enum Severity + { + Normal, + Info, + Success, + Warning, + Error + } + public interface ISnackBar + { + void Add(string message, Severity severity = Severity.Normal); + } +} diff --git a/Src/Core/UX/IUXSnackBar.cs.meta b/Src/Core/UX/IUXSnackBar.cs.meta new file mode 100644 index 0000000..6fd44a5 --- /dev/null +++ b/Src/Core/UX/IUXSnackBar.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c47bfae1d8985004181217f413fa6c64 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Src/Unity/Art/Backgrounds/BG_Gradient_Half_Linear.png b/Src/Unity/Art/Backgrounds/BG_Gradient_Half_Linear.png new file mode 100644 index 0000000..abd23da Binary files /dev/null and b/Src/Unity/Art/Backgrounds/BG_Gradient_Half_Linear.png differ diff --git a/Src/Unity/Art/Backgrounds/BG_Gradient_Half_Linear.png.meta b/Src/Unity/Art/Backgrounds/BG_Gradient_Half_Linear.png.meta new file mode 100644 index 0000000..5697b94 --- /dev/null +++ b/Src/Unity/Art/Backgrounds/BG_Gradient_Half_Linear.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: c528f3cd94a7aa0498af5e2f149e6908 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Src/Unity/Art/Backgrounds/textyre_gradient_oval.png b/Src/Unity/Art/Backgrounds/textyre_gradient_oval.png new file mode 100644 index 0000000..6e52746 Binary files /dev/null and b/Src/Unity/Art/Backgrounds/textyre_gradient_oval.png differ diff --git a/Src/Unity/Art/Backgrounds/textyre_gradient_oval.png.meta b/Src/Unity/Art/Backgrounds/textyre_gradient_oval.png.meta new file mode 100644 index 0000000..10d544e --- /dev/null +++ b/Src/Unity/Art/Backgrounds/textyre_gradient_oval.png.meta @@ -0,0 +1,140 @@ +fileFormatVersion: 2 +guid: 37f923d9a5ec87146bfb5cef8c989fdb +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Src/Unity/Scripts/AudioClip.meta b/Src/Unity/Scripts/AudioClip.meta new file mode 100644 index 0000000..b8c83ac --- /dev/null +++ b/Src/Unity/Scripts/AudioClip.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c4516b33dd9aebc408726bd560ff2c46 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Src/Unity/Scripts/AudioClip/AudioClipUtils.cs b/Src/Unity/Scripts/AudioClip/AudioClipUtils.cs new file mode 100644 index 0000000..17db49e --- /dev/null +++ b/Src/Unity/Scripts/AudioClip/AudioClipUtils.cs @@ -0,0 +1,64 @@ +using System.IO; +using UnityEngine; + +namespace Net.BITKit +{ + public static class AudioClipUtils + { + public static byte[] AudioClipToWavBytes(AudioClip clip) + { + var samples = new float[clip.samples * clip.channels]; + clip.GetData(samples, 0); + + var wavData = ConvertToWav(samples, clip.channels, clip.frequency); + return wavData; + } + + private static byte[] ConvertToWav(float[] samples, int channels, int sampleRate) + { + var stream = new MemoryStream(); + var writer = new BinaryWriter(stream); + + var byteRate = sampleRate * channels * 2; + + // 写入 WAV 文件头 + writer.Write(System.Text.Encoding.ASCII.GetBytes("RIFF")); + writer.Write(0); // placeholder for total file size + writer.Write(System.Text.Encoding.ASCII.GetBytes("WAVE")); + + // fmt 块 + writer.Write(System.Text.Encoding.ASCII.GetBytes("fmt ")); + writer.Write(16); // PCM + writer.Write((short)1); // AudioFormat = PCM + writer.Write((short)channels); + writer.Write(sampleRate); + writer.Write(byteRate); + writer.Write((short)(channels * 2)); // Block align + writer.Write((short)16); // Bits per sample + + // data 块 + writer.Write(System.Text.Encoding.ASCII.GetBytes("data")); + writer.Write(0); // placeholder for data chunk size + + // 写入样本 + var sampleCount = samples.Length; + for (var i = 0; i < sampleCount; i++) + { + var intData = (short)(samples[i] * short.MaxValue); + writer.Write(intData); + } + + // 回写文件长度 + writer.Seek(4, SeekOrigin.Begin); + writer.Write((int)(stream.Length - 8)); // RIFF size + + writer.Seek(40, SeekOrigin.Begin); + writer.Write((int)(stream.Length - 44)); // data chunk size + + writer.Flush(); + return stream.ToArray(); + } + } + + +} \ No newline at end of file diff --git a/Src/Unity/Scripts/AudioClip/AudioClipUtils.cs.meta b/Src/Unity/Scripts/AudioClip/AudioClipUtils.cs.meta new file mode 100644 index 0000000..515a09e --- /dev/null +++ b/Src/Unity/Scripts/AudioClip/AudioClipUtils.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 44ed748c8c7007445b81b479b5607388 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Src/Unity/Scripts/UX/Alert/UXAlert.cs b/Src/Unity/Scripts/UX/Alert/UXAlert.cs index 7e60204..6895543 100644 --- a/Src/Unity/Scripts/UX/Alert/UXAlert.cs +++ b/Src/Unity/Scripts/UX/Alert/UXAlert.cs @@ -134,6 +134,8 @@ namespace BITKit.UX _confirmButton.clicked += Close; _cancelButton.clicked += Close; + BITInputSystem.AllowInput.AddDisableElements(this); + if (message.OnConfirm is not null) { @@ -156,6 +158,7 @@ namespace BITKit.UX } private void Close() { + BITInputSystem.AllowInput.RemoveDisableElements(this); Dispose(); BITAppForUnity.AllowCursor.RemoveElement(this); } diff --git a/Src/Unity/Scripts/UX/Localization/UXLocalization.cs b/Src/Unity/Scripts/UX/Localization/UXLocalization.cs index 96d9112..2dce4de 100644 --- a/Src/Unity/Scripts/UX/Localization/UXLocalization.cs +++ b/Src/Unity/Scripts/UX/Localization/UXLocalization.cs @@ -41,6 +41,12 @@ namespace Net.BITKit.UX x.text = _localizationService.GetLocalizedString('#'+x.viewDataKey); } + foreach (var x in visualElement.Query(className:USS).ToList()) + { + if(string.IsNullOrEmpty(x.viewDataKey))continue; + x.title = _localizationService.GetLocalizedString('#'+x.viewDataKey); + } + foreach (var x in visualElement.Query(className:USS).ToList()) { if(string.IsNullOrEmpty(x.viewDataKey))continue; diff --git a/Src/Unity/Scripts/UX/Service/UI Toolkit/UIToolKitPanel.cs b/Src/Unity/Scripts/UX/Service/UI Toolkit/UIToolKitPanel.cs index a8281b4..89f6be3 100644 --- a/Src/Unity/Scripts/UX/Service/UI Toolkit/UIToolKitPanel.cs +++ b/Src/Unity/Scripts/UX/Service/UI Toolkit/UIToolKitPanel.cs @@ -239,7 +239,7 @@ namespace BITKit.UX await UniTask.NextFrame(); await OnExitAsync.UniTaskFunc(); - + try { var cts = new CancellationTokenSource(); @@ -249,6 +249,10 @@ namespace BITKit.UX catch (OperationCanceledException) { } + finally + { + await UniTask.NextFrame(); + } RootVisualElement?.RemoveFromClassList(USSExit); RootVisualElement?.RemoveFromClassList(USSExitAsync); diff --git a/Src/Unity/Scripts/UX/SnackBar.meta b/Src/Unity/Scripts/UX/SnackBar.meta new file mode 100644 index 0000000..2152bd9 --- /dev/null +++ b/Src/Unity/Scripts/UX/SnackBar.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8133ef90cc55fcd47b52169ff7a8acab +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Src/Unity/Scripts/UX/SnackBar/UXSnackBar.cs b/Src/Unity/Scripts/UX/SnackBar/UXSnackBar.cs new file mode 100644 index 0000000..0063e69 --- /dev/null +++ b/Src/Unity/Scripts/UX/SnackBar/UXSnackBar.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using BITKit; +using BITKit.Tween; +using BITKit.UX; +using Cysharp.Threading.Tasks; +using UnityEngine; +using UnityEngine.UIElements; + +namespace Net.BITKit.UX.SnackBar +{ + public class UXSnackBar : UIToolkitSubPanel,ISnackBar where TPanel :IUXPanel + { + [UXBindPath("snack_bar-container")] private VisualElement _snackBarContainer; + + private VisualTreeAsset _template; + + private readonly ValidHandle _waitHandle = new ValidHandle(); + + public UXSnackBar(IServiceProvider serviceProvider) : base(serviceProvider) + { + } + + protected override void OnInitiated() + { + base.OnInitiated(); + _template = _snackBarContainer.Q().templateSource; + + _snackBarContainer.Clear(); + + BITAppForUnity.AllowCursor.AddListener(OnAllowCursor); + } + + private void OnAllowCursor(bool obj) + { + if (obj) + { + _waitHandle.AddElement(this); + } + else + { + _waitHandle.RemoveElement(this); + } + } + + public async void Add(string message, Severity severity = Severity.Normal) + { + var ve = _snackBarContainer.Create(_template); + + ve.AddToClassList($"severity-{severity.ToString().ToLower()}"); + + ve.Get