This commit is contained in:
CortexCore 2023-10-06 23:43:19 +08:00
parent ebf9c1f526
commit 2c4710bc5d
184 changed files with 111782 additions and 744 deletions

View File

@ -15,39 +15,17 @@
<Compile Remove="Packages\Tests\**" />
<Compile Remove="Packages\Runtime~\Unity\**" />
<Compile Remove="Packages\Runtime~\UnityPluginsSupport\**" />
<Compile Remove="Src\Unity\**" />
<Compile Remove="Src\UnityPluginsSupport\**" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Remove="Packages\Common~\**" />
<EmbeddedResource Remove="Packages\Editor\**" />
<EmbeddedResource Remove="Packages\Runtime\**" />
<EmbeddedResource Remove="Packages\Core\Cache\**" />
<EmbeddedResource Remove="Packages\Tests\**" />
<EmbeddedResource Remove="Packages\Runtime~\Unity\**" />
<EmbeddedResource Remove="Packages\Runtime~\UnityPluginsSupport\**" />
</ItemGroup>
<ItemGroup>
<None Remove="Packages\Common~\**" />
<None Remove="Packages\Editor\**" />
<None Remove="Packages\Runtime\**" />
<None Remove="Packages\Core\Assets\**" />
<None Remove="Packages\Core\Cache\**" />
<None Remove="Packages\Tests\**" />
<None Remove="Packages\Runtime~\Unity\**" />
<None Remove="Packages\Runtime~\UnityPluginsSupport\**" />
<None Remove="Packages\Runtime~\BITKit.asmdef" />
<None Remove="Packages\Runtime~\BITKit.asmdef.meta" />
<None Remove="Packages\Runtime~\Core.meta" />
<None Remove="Packages\Runtime~\NetSupport.meta" />
<None Remove="Packages\Runtime~\Unity.meta" />
<None Remove="Packages\Runtime~\UnityPluginsSupport.meta" />
<None Remove="Packages\Editor.meta" />
<None Remove="Packages\kcp2k.meta" />
<None Remove="Packages\package.json" />
<None Remove="Packages\package.json.meta" />
<None Remove="Packages\Plugins.meta" />
<None Remove="Packages\Tests.meta" />
<!-- 排除Unity文件 -->
<None Remove="**\*.meta"/>
<None Remove="**\*.asmdef"/>
<None Remove="Src\Unity\**" />
<None Remove="Src\UnityPluginsSupport\**" />
</ItemGroup>
<ItemGroup>
@ -57,16 +35,33 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Kcp" Version="2.6.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.9" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0-preview.4.23259.5" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="7.0.0" />
<PackageReference Include="MySql.EntityFrameworkCore" Version="6.0.13" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Newtonsoft.Json.Bson" Version="1.0.3-beta1" />
<PackageReference Include="System.Data.SqlClient" Version="4.8.5" />
<PackageReference Include="UniTask" Version="2.3.3" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Remove="Src\Unity\**" />
<EmbeddedResource Remove="Src\UnityPluginsSupport\**" />
</ItemGroup>
</Project>

View File

@ -17,7 +17,7 @@
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"allowUnsafeCode": true,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,

View File

@ -7,6 +7,7 @@ using Cysharp.Threading.Tasks;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
// ReSharper disable StringLiteralTypo
#if NET5_0_OR_GREATER
using Microsoft.Extensions.DependencyInjection;
#endif
@ -19,6 +20,10 @@ namespace BITKit
}
public class BITApp
{
public static async UniTask SwitchToMainThread()
{
await UniTask.SwitchToSynchronizationContext(SynchronizationContext);
}
public static class Time
{
public static float DeltaTime { get; internal set; }
@ -59,7 +64,89 @@ namespace BITKit
"TextCopy",
"Blazored",
"TextCopy",
"mattatz"
"mattatz",
"TrailsFX",
"Knife",
"Needle",
"NiceIO",
"AndroidPlayerBuildProgram",
"DocCodeExamples",
"System",
"UnityEngine",
"Unity",
"Microsoft",
"UnityEditor",
"Google",
"Mono",
"ZXing",
"ImmersiveVRTools",
"MonKey",
"FLib",
"Kcp",
"Udx",
"Sirenix",
"TMPro",
"RotaryHeart",
"Cinemachine",
"ParadoxNotion",
"Net",
"VSCodeEditor",
"AOT",
"UnityEditorInternal",
"UnityEngineInternal",
"JetBrains",
"Bee",
"NotInvited",
"HighlightPlus",
"DG",
"Hierarchy2",
"Cysharp",
"JetBrains",
"Packages",
"Newtonsoft_X",
"Binding",
"NodeCanvas",
"SaveDuringPlay",
"LimWorks",
"MagicaCloth2",
"FastScriptReload",
"ParrelSync",
"KinematicCharacterController",
"LimWorksEditor",
"BuildComponent",
"dnlib",
"BigIntegerLibrary",
"Ionic",
"log4net",
"ImmersiveVrToolsCommon",
"NUnit",
"HarmonyLib",
"MonoMod",
"WebDav",
"PlasticGui",
"Codice",
"GluonGui",
"PlasticPipe",
"XDiffGui",
"MacFsWatcher",
"MacUI",
"PlayerBuildProgramLibrary",
"ExCSS",
"ScriptCompilationBuildProgram",
"BeeBuildProgramCommon",
"Accessibility",
"CodiceApp",
"Newtonsoft",
"MergetoolGui",
"TreeEditor",
"MackySoft",
"FullscreenEditor",
"mattatz",
"AYellowpaper",
"kcp2k",
"MeshCombineStudio",
"AmazingAssets",
"Utilities"
};
}
#if NET5_0_OR_GREATER
@ -144,7 +231,8 @@ namespace BITKit
public static InitializationState State;
public static Assembly[] Assemblies;
public static AppSettings Settings { get; protected set; }
public static async void Start(string appName = nameof(BITApp),AppSettings settings=default)
private static DateTime InitialTime { get; set; }=DateTime.Now;
public static async UniTask Start(string appName = nameof(BITApp),AppSettings settings=default)
{
Time.TimeAsDouble = 0;
Time.DeltaTime = 1 / 60f;
@ -153,7 +241,7 @@ namespace BITKit
CancellationTokenSource = new CancellationTokenSource();
AppName = appName;
ThreadHelper.LogCurrentThread();
InitialTime = DateTime.Now;
await Init();
}
private static async Task Init()
@ -182,10 +270,16 @@ namespace BITKit
reflectionHelperWatch.Start();
await ReflectionHelper.Init();
reflectionHelperWatch.Stop();
Stopwatch commandWatch = new();
await BITCommands.InitializeAsync();
commandWatch.Stop();
stopwatch.Stop();
State = InitializationState.Initialized;
BIT4Log.Log<BITApp>($"已完成初始化,耗时:{stopwatch.ElapsedMilliseconds}ms");
BIT4Log.Log<BITApp>($"反射初始化耗时:{reflectionHelperWatch.ElapsedMilliseconds}ms");
}
catch (System.Exception e)
{
@ -196,11 +290,18 @@ namespace BITKit
}
public static void Stop()
{
var runTime = DateTime.Now - InitialTime;
BIT4Log.Log<BITApp>($"正在停止{nameof(BITApp)}");
CancellationTokenSource.Cancel();
State = InitializationState.None;
BITCommands.Dispose();
BIT4Log.Log<BITApp>($"已停止{nameof(BITApp)}");
BIT4Log.Log<BITApp>($"运行时间:{runTime}");
BIT4Log.Log<BITApp>("Exit Code:0");
}
public static void Run(string path, string WorkingDirectory = "")
{

View File

@ -1,8 +1,8 @@
#if NETCOREAPP
using System;
using Cysharp.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace BITKit;
public class BITAppForNet
@ -18,7 +18,7 @@ public class BITAppForNet
BIT4Log.OnSetConsoleColor += color => Console.ForegroundColor = color;
BIT4Log.OnNextLine += Console.WriteLine;
BITApp.Start(name);
await BITApp.Start(name);
await BITBinary.Start();
}
public static UniTask DisposeAsync()

View File

@ -9,4 +9,14 @@ namespace BITKit
{
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = true, Inherited = true)]
public class CustomTypeAttribute : System.Attribute
{
public readonly Type Type;
public CustomTypeAttribute(Type type)
{
Type = type;
}
}
}

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 647f1c92db6d9b5438a81bdb9bfc11bd
guid: ef5795e833a88cd4b8c1485d4b50ebfd
folderAsset: yes
DefaultImporter:
externalObjects: {}

8
Src/Core/Auth/Core.meta Normal file
View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b869357f0380e864eb445105d35c68b7
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,87 @@
using System;
using Cysharp.Threading.Tasks;
namespace BITKit.Auth
{
/// <summary>
/// 授权服务
/// </summary>
public interface IAuthService
{
/// <summary>
/// 是否已授权
/// </summary>
bool IsAuthorized { get; }
/// <summary>
/// 是否正在授权
/// </summary>
bool IsAuthorizing { get; }
/// <summary>
/// 异步开始授权
/// </summary>
/// <param name="token">令牌</param>
UniTask AuthorizeAsync(string token);
/// <summary>
/// 异步取消授权
/// </summary>
/// <returns></returns>
UniTask CancelAuthorizationAsync();
/// <summary>
/// 开始授权的回调
/// </summary>
event Action<string> OnAuthorize;
/// <summary>
/// 已授权的回调
/// </summary>
event Action<string> OnAuthorized;
/// <summary>
/// 取消授权的回调
/// </summary>
event Action<string> UnAuthorize;
/// <summary>
/// 授权失败的回调
/// </summary>
event Action<string> OnAuthorizeFailure;
}
public abstract class AuthServiceImplement:IAuthService
{
protected abstract IAuthService service { get; }
bool IAuthService.IsAuthorized => service.IsAuthorized;
bool IAuthService.IsAuthorizing => service.IsAuthorizing;
UniTask IAuthService.AuthorizeAsync(string token)
{
return service.AuthorizeAsync(token);
}
UniTask IAuthService.CancelAuthorizationAsync()
{
return service.CancelAuthorizationAsync();
}
event Action<string> IAuthService.OnAuthorize
{
add => service.OnAuthorize += value;
remove => service.OnAuthorize -= value;
}
event Action<string> IAuthService.OnAuthorized
{
add => service.OnAuthorized += value;
remove => service.OnAuthorized -= value;
}
event Action<string> IAuthService.UnAuthorize
{
add => service.UnAuthorize += value;
remove => service.UnAuthorize -= value;
}
event Action<string> IAuthService.OnAuthorizeFailure
{
add => service.OnAuthorizeFailure += value;
remove => service.OnAuthorizeFailure -= value;
}
}
}

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: dd4b17361e28d304bbc1dd6d568e9a3c
guid: df16dad99b7205a40b655489e7f19076
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@ -1,4 +1,5 @@
#if UNITY
#if NET5_0_OR_GREATER
#else
using UnityEngine;
#endif
using System;
@ -6,7 +7,9 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using Cysharp.Threading.Tasks;
#if NET5_0_OR_GREATER
using Microsoft.SqlServer.Server;
#endif
using Newtonsoft.Json;
namespace BITKit
@ -14,27 +17,37 @@ namespace BITKit
public class BITBinary
{
private static readonly Dictionary<string, INetMessageReader> netReaders = new();
private static readonly List<Type> serializableTypes = new();
#if NET5_0_OR_GREATER
public static readonly List<Type> serializableTypes = new();
#endif
public static async UniTask Start()
{
netReaders.Clear();
#if NET5_0_OR_GREATER
serializableTypes.Clear();
#endif
foreach (var x in await ReflectionHelper.GetInstances<INetMessageReader>())
{
var typeName = x.GetMessageType().FullName;
if (typeName == null) continue;
netReaders.Add(typeName, x);
BIT4Log.Log<BITBinary>($"已注册类型:{typeName}");
}
#if NET5_0_OR_GREATER
var serializes = await ReflectionHelper.GetInstances<IBinarySerialize>();
#if UNITY
serializes = serializes.Where(x => x is not UnityEngine.Object);
#else
#endif
foreach (var x in serializes)
{
serializableTypes.Add(x.GetType());
BIT4Log.Log<BITBinary>($"已注册类型:{x.GetType().FullName}");
}
// #if NET5_0_OR_GREATER
// #else
// serializes = serializes.Where(x => x is not UnityEngine.Object);
// #endif
// foreach (var x in serializes)
// {
// serializableTypes.Add(x.GetType());
// BIT4Log.Log<BITBinary>($"已注册类型:{x.GetType().FullName}");
// }
}
public static object Read<T>(byte[] buffer) => (T)ReadAsValue(buffer);
@ -60,26 +73,22 @@ namespace BITKit
var typeName = reader.ReadString();
if (netReaders.TryGetValue(typeName, out var netReader))
{
return netReader.ReadBinaryAsObject(reader);
}
var json = reader.ReadString();
json = reader.ReadString();
if (string.IsNullOrEmpty(json))
{
throw new Exception($"从二进制中读取的json值为空");
}
try
{
if (BITSharp.TryGetTypeFromFullName(typeName, out var type))
{
return JsonConvert.DeserializeObject(json, type);
}
}
catch (Exception)
catch (Exception e)
{
BIT4Log.Warning<BITBinary>($"反序列化失败,类型:{typeName},值:\n{json}");
throw;
BIT4Log.LogException(e);
}
throw new Exception("未找到读取该二进制的BinaryReader");
}
@ -119,14 +128,8 @@ namespace BITKit
{
netReader.WriteBinaryAsObject(writer,value);
}
else if( value is IBinarySerialize serialize)
{
serialize.Write(writer);
}
else
{
//throw new Exception($"没有找到{value.GetType().Name}的Binary写入方法");
writer.Write(value!.GetType().FullName!);
writer.Write(JsonConvert.SerializeObject(value));
}
}
@ -139,10 +142,12 @@ namespace BITKit
{
return true;
}
else if (serializableTypes.Any(x => x.FullName == typeName))
#if NET5_0_OR_GREATER
else if (serializableTypes.Any(x => x.FullName == typeName))
{
return true;
}
#endif
return false;
}

View File

@ -54,6 +54,19 @@ namespace BITKit
}
public static async void Excute(string cmd)
{
var cmdSplit = cmd.Split("|");
if (cmdSplit.Length is 1 or 0)
{
cmdSplit = cmd.Split("\n");
}
if (cmdSplit.Length > 1)
{
foreach (var x in cmdSplit)
{
Excute(x);
}
return;
}
await UniTask.SwitchToThreadPool();
await TaskHelper.WaitUntil(() => state is InitializationState.Initialized);
var split = cmd.Split(" ").ToList();
@ -87,27 +100,24 @@ namespace BITKit
}
static Dictionary<string, MethodInfo> methodInfos = new();
static InitializationState state;
[ExcuteOnStart]
public static void Start()
public static async UniTask InitializeAsync()
{
try
{
Init();
await Init();
}
catch (System.Exception e)
{
BIT4Log.LogException(e);
}
}
[ExcuteOnStop]
public static void Stop()
public static void Dispose()
{
state = 0;
methodInfos.Clear();
}
static async void Init()
private static async UniTask Init()
{
state = InitializationState.Initializing;
await UniTask.SwitchToThreadPool();

8
Src/Core/Crypto.meta Normal file
View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 47446028359168843813e0d48fa10de5
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 6c3b8ff8ac3fe6f45bb8f4690a0a15e1
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,20 @@
using System;
using System.Security.Cryptography;
namespace BITKit.Crypto
{
public class BITCrypto:ICryptography
{
public string Salt { get; set; } = "2196F3";
public string Hash(string password)
{
var data = System.Text.Encoding.UTF8.GetBytes(password + Salt);
return Convert.ToBase64String(data);
}
public bool Verify(string password, string hash)
{
return Hash(password) == hash;
}
}
}

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 259562ab3c5f28243819c92d2db08104
guid: d015706f3749b334ab81c82b23a1575a
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@ -0,0 +1,26 @@
namespace BITKit.Crypto
{
/// <summary>
/// 加密接口
/// </summary>
public interface ICryptography
{
/// <summary>
/// 盐
/// </summary>
public string Salt { get; set; }
/// <summary>
/// 获取Hash
/// </summary>
/// <param name="password"></param>
/// <returns></returns>
public string Hash(string password);
/// <summary>
/// 验证密码是否有效
/// </summary>
/// <param name="password">明文密码</param>
/// <param name="hash"></param>
/// <returns></returns>
public bool Verify(string password, string hash);
}
}

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 3db000849b712bf4ea543570c2ea0f43
guid: e6da82a831307d145bac6bdf73a852c9
MonoImporter:
externalObjects: {}
serializedVersion: 2

Binary file not shown.

View File

@ -1,33 +0,0 @@
fileFormatVersion: 2
guid: 681d142aa31302548a110f6824493c32
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Any:
second:
enabled: 1
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
- first:
Windows Store Apps: WindowsStoreApps
second:
enabled: 0
settings:
CPU: AnyCPU
userData:
assetBundleName:
assetBundleVariant:

View File

@ -2,8 +2,5 @@ using System;
namespace BITKit
{
public interface IServiceRegister
{
Type BaseType { get; }
}
}

View File

@ -3,7 +3,10 @@ using System.Collections.Generic;
namespace BITKit
{
/// <summary>
/// 双缓冲区
/// </summary>
/// <typeparam name="T"></typeparam>
public interface IDoubleBuffer<T>
{
T Current { get; }
@ -11,7 +14,10 @@ namespace BITKit
event Action<T> OnRelease;
bool TryGetRelease(out T result);
}
/// <summary>
/// <see cref="IDoubleBuffer{T}"/>
/// </summary>
/// <typeparam name="T"></typeparam>
public class DoubleBuffer<T> : IDoubleBuffer<T>
{
public T Current
@ -25,14 +31,18 @@ namespace BITKit
{
Current = newValue;
OnRelease?.Invoke(newValue);
_release.SetValueThenAllow(newValue);
}
public event Action<T> OnRelease;
private readonly Queue<T> _releases = new();
private readonly Optional<T> _release=new();
public bool TryGetRelease(out T result)
{
return _releases.TryDequeue(out result);
result = _release.Value;
if (!_release.Allow) return _release.Allow;
_release.Clear();
return true;
}
}
}

View File

@ -1,5 +1,9 @@
using System.Threading;
using System;
using System.ComponentModel.Design;
#if NET5_0_OR_GREATER
using Microsoft.Extensions.DependencyInjection;
#endif
namespace BITKit.Core.Entites
{
/// <summary>
@ -8,14 +12,11 @@ namespace BITKit.Core.Entites
public interface IEntity
{
ulong Id { get; }
#if NET5_0_OR_GREATER
bool TryGetComponent<T>(out T component) where T : IEntityComponent;
CancellationToken CancellationToken { get; }
bool TryGetComponent<T>(out T component);
IEntityComponent[] Components { get; }
bool RegisterComponent<T>(T component) where T : IEntityComponent;
#else
#endif
bool RegisterComponent<T>(T component);
IServiceProvider ServiceProvider { get; }
}
/// <summary>
/// 基本实体组件
@ -24,6 +25,9 @@ namespace BITKit.Core.Entites
{
Type BaseType { get; }
IEntity Entity { get; set; }
#if NET5_0_OR_GREATER
void BuildService(IServiceCollection serviceCollection);
#endif
}
/// <summary>
/// 基本实体服务
@ -61,24 +65,28 @@ namespace BITKit.Core.Entites
/// <param name="id"></param>
/// <returns></returns>
IEntity Get(ulong id);
/// <summary>
/// 查询Entity,例如
/// </summary>
/// <para>var rotationEntities=EntitiesService.Query&lt;RotationComponent&gt;</para>
IEntity[] Query<T>() where T : IEntityComponent;
IEntity[] Query<T>();
/// <summary>
/// 查询1个组件
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
T[] QueryComponents<T>() where T : IEntityComponent;
T[] QueryComponents<T>();
/// <summary>
/// 查询2个组件
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="T1"></typeparam>
/// <returns></returns>
ValueTuple<T,T1>[] QueryComponents<T,T1>()where T : IEntityComponent where T1 : IEntityComponent;
ValueTuple<T, T1>[] QueryComponents<T, T1>();
/// <summary>
/// 查询3个组件
/// </summary>
@ -86,7 +94,7 @@ namespace BITKit.Core.Entites
/// <typeparam name="T1"></typeparam>
/// <typeparam name="T2"></typeparam>
/// <returns></returns>
ValueTuple<T,T1,T2>[] QueryComponents<T,T1,T2>() where T : IEntityComponent where T1 : IEntityComponent where T2 : IEntityComponent;
ValueTuple<T, T1, T2>[] QueryComponents<T, T1, T2>();
}
}

View File

@ -0,0 +1,24 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace BITKit
{
public static class FuncExtensions
{
public static IEnumerable<Func<T0,T1>> CastAsFunc<T0,T1>(this Func<T0,T1> self)
{
return self.GetInvocationList().Cast<Func<T0, T1>>();
}
public static IEnumerable<Func<T0,T1,T2>> CastAsFunc<T0,T1,T2>(this Func<T0,T1,T2> self)
{
return self.GetInvocationList().Cast<Func<T0, T1,T2>>();
}
public static IEnumerable<Func<T0,T1,T2,T3>> CastAsFunc<T0,T1,T2,T3>(this Func<T0,T1,T2,T3> self)
{
return self.GetInvocationList().Cast<Func<T0, T1,T2,T3>>();
}
}
}

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: ebbaf967274f9c942bcbfccbea097f28
guid: 8372b15121bd7e4408788d269d22fc20
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@ -0,0 +1,19 @@
using System.Net.Http;
using System.Text;
using System.Threading;
using Cysharp.Threading.Tasks;
using Newtonsoft.Json;
namespace BITKit
{
public static class HttpClientExtensions
{
public static async UniTask<string> PostJsonAsync(this HttpClient self, string requestUrl, object value , CancellationToken cancellationToken=default)
{
var json = JsonConvert.SerializeObject(value);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response =await self.PostAsync(requestUrl, content, cancellationToken);
return await response.Content.ReadAsStringAsync();
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c1610171280cf1d488accdfd46ae59d4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -33,6 +33,8 @@ namespace BITKit.Apps
/// </summary>
event Action<string> OnDownloadComplete;
event Action OnDetectedLatestVersion;
/// <summary>
/// 下载最新版本
/// </summary>

View File

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Timers;
using Cysharp.Threading.Tasks;
using kcp2k;
@ -21,6 +22,9 @@ namespace BITKit.Net
public int Ping => -1;
public int Id { get; private set; } = -1;
private readonly KcpClient client;
private readonly Queue<byte[]> commandQueue = new();
private readonly Timer _timer = new(100)
{
AutoReset = true
@ -44,8 +48,13 @@ namespace BITKit.Net
});
}
private void Tick(object sender, ElapsedEventArgs e)
private async void Tick(object sender, ElapsedEventArgs e)
{
await UniTask.SwitchToThreadPool();
while (commandQueue.TryDequeue(out var bytes))
{
client.Send(bytes, KcpChannel.Reliable);
}
client.Tick();
}
@ -108,8 +117,7 @@ namespace BITKit.Net
case NetCommandType.Command:
var command = BITBinary.Read(reader);
if (command is object[] { Length: 1 } objs) command = objs[0];
// BIT4Log.Log<KcpClient>(
// $"已收到指令:{command},值:\n{JsonConvert.SerializeObject(command, Formatting.Indented)}");
//BIT4Log.Log<KcpClient>($"已收到指令:{command},值:\n{JsonConvert.SerializeObject(command, Formatting.Indented)}");
try
{
if (BITApp.SynchronizationContext is not null)
@ -128,7 +136,7 @@ namespace BITKit.Net
break;
case NetCommandType.Heartbeat:
client.Send(new[] { (byte)NetCommandType.Heartbeat }, KcpChannel.Reliable);
//client.Send(new[] { (byte)NetCommandType.Heartbeat }, KcpChannel.Reliable);
break;
default:
BIT4Log.Log<KcpClient>($"未知消息类型:{type},字节:{(byte)type}");
@ -249,7 +257,8 @@ namespace BITKit.Net
.Write((byte)commandType)
.WriteObject(values)
.Build();
client.Send(bytes, KcpChannel.Reliable);
commandQueue.Enqueue(bytes);
//client.Send(bytes, KcpChannel.Reliable);
}
}

View File

@ -14,7 +14,7 @@ namespace BITKit.Net
{
public class KCPNetServer:INetServer,INetProvider
{
public event Action<int> OnClientConnect;
public event Action<int> OnClientConnected;
public event Action<int> OnClientDisconnected;
public event Action OnStartServer;
public event Action OnStopServer;
@ -74,6 +74,9 @@ namespace BITKit.Net
new Dictionary<int, EndPoint>(
server.connections.Select(x => new KeyValuePair<int, EndPoint>(x.Key, x.Value.remoteEndPoint)
));
public void Tick() => server.Tick();
public void HandShake()
{
@ -85,7 +88,7 @@ namespace BITKit.Net
private void OnConnected(int Id)
{
OnClientConnect?.Invoke(Id);
OnClientConnected?.Invoke(Id);
ClientCommand(Id,new NetClientAllocateIdCommand
{
Id = Id,
@ -105,6 +108,7 @@ namespace BITKit.Net
using var ms = new MemoryStream(bytes.ToArray());
using var reader = new BinaryReader(ms);
BIT4Log.Log<INetServer>(Id);
var type = (NetCommandType)ms.ReadByte();
switch (type)
@ -114,9 +118,12 @@ namespace BITKit.Net
break;
case NetCommandType.Command:
var command = BITBinary.Read(reader);
if (command is object[] objs && objs.Length is 1) command = objs[0];
//BIT4Log.Log<KCPNetServer>($"已收到指令:{command},值:\n{JsonConvert.SerializeObject(command, Formatting.Indented)}");
if (command is object[] { Length: 1 } objs) command = objs[0];
BIT4Log.Log<KCPNetServer>($"已收到指令:{command},值:\n{JsonConvert.SerializeObject(command, Formatting.Indented)}");
_events.Invoke(command.GetType().FullName, command);
(int Id,object Command) tuple = (Id,command);
_events.InvokeDirect(command.GetType().FullName,tuple);
break;
case NetCommandType.Heartbeat:
server.Send(Id,new byte[]{(byte)NetCommandType.Heartbeat}, KcpChannel.Reliable);
@ -179,6 +186,17 @@ namespace BITKit.Net
{
_events.AddListener<T>(handle);
}
public void AddCommandListenerWithId<T>(Action<int, T> handle)
{
_events.AddListenerDirect(typeof(T).FullName, x =>
{
if (x is ValueTuple<int, T> tuple)
{
handle.Invoke(tuple.Item1,tuple.Item2);
}
});
}
public void RemoveCommandListener<T>(Action<T> handle)
{

View File

@ -44,6 +44,19 @@ namespace BITKit
return list;
}
public static bool TryGetIndexOf<T>(this IEnumerable<T> self, Func<T, bool> factory, out int index)
{
index = -1;
var enumerable = self as T[] ?? self.ToArray();
for (var i = 0; i < enumerable.Length; i++)
{
var item = enumerable.ElementAt(i);
if (!factory.Invoke(item)) continue;
index = i;
return true;
}
return false;
}
public static bool Contains<T>(IEnumerable<T> a, IEnumerable<T> b)
{
foreach (var x in b)

View File

@ -0,0 +1,83 @@
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
// ReSharper disable CheckNamespace
namespace BITKit
// ReSharper restore CheckNamespace
{
public record ContextModel
{
public static ContextModel Get(object data)
{
return new ContextModel()
{
StatusCode = 200,
Message = "success",
Data = data
};
}
public static ContextModel Error(string message)
{
return new ContextModel()
{
StatusCode = 500,
Message = message,
Data = false
};
}
public static ContextModel GetFromJson(string json)
{
try
{
var result = new ContextModel();
var jObject = JObject.Parse(json);
if(jObject.TryGetValue("status_code",out var statusCode))
result.StatusCode = statusCode.Value<int>();
if(jObject.TryGetValue("message",out var message))
result.Message = message.Value<string>();
if (jObject.TryGetValue("data", out var data))
result.Data = data;
return JsonConvert.DeserializeObject<ContextModel>(json);
}
catch (Exception e)
{
BIT4Log.Warning(json);
throw;
}
}
public static implicit operator string(ContextModel self)
{
return self.ToString();
}
public override string ToString()
{
return JsonConvert.SerializeObject(this);
}
[JsonProperty("status_code")]
public int StatusCode;
[JsonProperty("message")]
public string Message=string.Empty;
[JsonProperty("data")]
public object Data=string.Empty;
[JsonIgnore]
public bool IsSuccess => StatusCode is 200 or 0;
public bool TryAs<T>(out T value)
{
switch (Data)
{
case T t:
value = t;
return true;
case JToken jToken:
value = jToken.ToObject<T>();
return true;
default:
value = default;
return false;
}
}
}
}

View File

@ -1,34 +0,0 @@
using Newtonsoft.Json;
// ReSharper disable CheckNamespace
namespace BITKit
// ReSharper restore CheckNamespace
{
public record ContextModel
{
public static ContextModel Get(object data)
{
return new ContextModel()
{
code = 200,
message = "success",
data = data
};
}
public static ContextModel Error(object data)
{
return new ContextModel()
{
code = 500,
message = "failed",
data = data
};
}
public static implicit operator string(ContextModel self)
{
return JsonConvert.SerializeObject(self);
}
public int code;
public string message=string.Empty;
public object data=string.Empty;
}
}

View File

@ -1,6 +1,6 @@
#if UNITY
#else
#if NET5_0_OR_GREATER
using System.ComponentModel.DataAnnotations;
#else
#endif
using System;

8
Src/Core/Net/Http.meta Normal file
View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 080bac71709b69c4ca047982932f76f0
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: baf3f1a7c92c3a54ca4fc5c27d09e5aa
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,15 @@
using System;
using System.Net;
using System.Net.Http;
namespace BITKit.Net.Http
{
public interface IHttpListenerService
{
bool IsListening { get; }
int Port { get; set; }
public event Func<HttpListenerRequest,HttpContent> OnRequest;
void Start();
void Stop();
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8480f17d72498ee4a978ca8a4d85440a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,105 @@
using System;
using System.Net;
using System.Net.Http;
using System.Threading;
namespace BITKit.Net.Http
{
public class HttpListenerService:IHttpListenerService
{
public bool IsListening=>_httpListener.IsListening;
public int Port { get; set; }
private readonly HttpListener _httpListener = new();
public event Func<HttpListenerRequest,HttpContent> OnRequest;
private readonly CancellationTokenSource _cancellationTokenSource = new();
private CancellationToken _cancellationToken=>_cancellationTokenSource.Token;
public HttpListenerService()
{
Port = 7001;
}
public HttpListenerService(int port)
{
Port = port;
}
public void Start()
{
if (HttpListener.IsSupported is false)
{
throw new NotImplementedException("HttpListener is not supported this platform");
}
_httpListener.AuthenticationSchemes = AuthenticationSchemes.Anonymous;
//_httpListener.Prefixes.Add($"http://localhost:{Port}/");
#if NET5_0_OR_GREATER
_httpListener.Prefixes.Add($"http://localhost:{Port}/");
#else
_httpListener.Prefixes.Add($"http://*:{Port}/");
#endif
Thread thread = new(Process);
thread.Start();
}
public void Stop()
{
_cancellationTokenSource.Cancel();
_httpListener.Stop();
BIT4Log.Log<IHttpListenerService>("Is Trying To Stop");
}
private void Process()
{
_httpListener.Start();
BIT4Log.Log<IHttpListenerService>($"{Port}\tIs Listening");
while (_cancellationToken.IsCancellationRequested is false)
{
var result = _httpListener.BeginGetContext(ListenerCallback, _httpListener);
result.AsyncWaitHandle.WaitOne();
}
BIT4Log.Log<IHttpListenerService>($"{Port}\tStopped");
}
private void ListenerCallback(IAsyncResult result)
{
if (_cancellationToken.IsCancellationRequested) return;
var context = _httpListener.EndGetContext(result);
var request = context.Request;
var response = context.Response;
var output = response.OutputStream;
if (request.RawUrl is "/favicon.ico")
{
output.Close();
response.Close();
return;
}
// 启用CORS
response.Headers.Add("Access-Control-Allow-Origin", "*"); // 允许任何来源访问,生产环境应更具体设置
response.Headers.Add("Access-Control-Allow-Methods", "*"); // 允许的HTTP方法
response.Headers.Add("Access-Control-Allow-Headers", "*"); // 允许的标头
var content = OnRequest?.Invoke(request);
var buffer = StringHelper.GetBytes(ContextModel.Error("没有注册请求事件"));
if (content is not null)
{
#if NET5_0_OR_GREATER
buffer = content!.ReadAsByteArrayAsync(_cancellationToken).Result;
#else
buffer = content!.ReadAsByteArrayAsync().Result;
#endif
}
response.ContentLength64 = buffer.Length;
output.Write(buffer);
output.Close();
response.Close();
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 55947637fce62c643ba67ab42d72cce8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

8
Src/Core/Net/LAN 1.meta Normal file
View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 7f4804b35f0832940a028f2905294829
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

8
Src/Core/Net/LAN.meta Normal file
View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 9cf6dcf675e5fb74fa0675d39177e1c5
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ef6bc358998385e409414022bd10c876
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,16 @@
using System;
using System.Net;
namespace BITKit.Net.LAN
{
public interface ILANBroadcaster
{
int Port { get; set; }
byte[] Buffer { get; set; }
event Action<EndPoint, string> OnReceive;
void StartBroadcast();
void StopBroadcast();
void StartListen();
void StopListen();
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5874f625a9ef3e24092f070bdce13c9f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,108 @@
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
namespace BITKit.Net.LAN
{
/// <summary>
/// 基于UDP的LAN广播
/// </summary>
public class UdpBasedLanBroadcaster : ILANBroadcaster
{
public int Port { get; set; }
public byte[] Buffer { get; set; } = StringHelper.GetBytes("Hello World");
private bool _isBroadcasting;
private bool _isListening;
public UdpBasedLanBroadcaster()
{
}
public event Action<EndPoint, string> OnReceive;
public void StartBroadcast()
{
_isBroadcasting = true;
Thread thread = new(Process)
{
IsBackground = true
};
thread.Start();
BIT4Log.Log<ILANBroadcaster>($"开始广播端口{Port}");
}
public void StopBroadcast()
{
_isBroadcasting = false;
BIT4Log.Log<ILANBroadcaster>($"停止广播端口 {Port}");
}
public void StartListen()
{
_isListening = true;
var thread = new Thread(ReceiveThread)
{
IsBackground = true
};
thread.Start();
BIT4Log.Log<ILANBroadcaster>($"开始监听端口:{Port}");
}
public void StopListen()
{
_isListening = false;
BIT4Log.Log<ILANBroadcaster>($"停止监听端口{Port}");
}
private void Process()
{
var udpClient = new UdpClient(new IPEndPoint(IPAddress.Any, 0));
var endpoint = new IPEndPoint(IPAddress.Broadcast, Port);
//其实 IPAddress.Broadcast 就是 255.255.255.255
//下面代码与上面有相同的作用
//IPEndPoint endpoint = new IPEndPoint(IPAddress.Parse("255.255.255.255"), 8080);
try
{
while (_isBroadcasting)
{
udpClient.Send(Buffer, Buffer.Length, endpoint);
Thread.Sleep(1000);
}
}
catch (Exception e)
{
BIT4Log.LogException(e);
}
udpClient.Dispose();
}
private void ReceiveThread()
{
try
{
var udpClient = new UdpClient(new IPEndPoint(IPAddress.Any, Port));
var endpoint = new IPEndPoint(IPAddress.Any, 0);
while (_isListening)
{
var buf = udpClient.Receive(ref endpoint);
var msg = Encoding.Default.GetString(buf);
if (OnReceive is not null)
OnReceive(endpoint, msg);
else
BIT4Log.Log<ILANBroadcaster>($"Receive From {endpoint}:\t{msg}");
Thread.Sleep(500);
}
}
catch (Exception e)
{
BIT4Log.LogException(e);
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4822fff0e51bc0a43a98342ea5c1d9d0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -141,7 +141,7 @@ namespace BITKit
/// <summary>
/// 回调:当客户端连接时
/// </summary>
public event Action<int> OnClientConnect;
public event Action<int> OnClientConnected;
/// <summary>
/// 回调:当客户端断开连接时
@ -188,6 +188,13 @@ namespace BITKit
/// 所有已连接的客户端
/// </summary>
public IDictionary<int,EndPoint> Connections { get; }
/// <summary>
/// 添加远程命令监听,包括客户端Id
/// </summary>
/// <param name="handle"></param>
/// <typeparam name="T"></typeparam>
void AddCommandListenerWithId<T>(Action<int,T> handle);
}
/// <summary>
/// 基本网络客户端的接口定义,包括了基本客户端的功能

View File

@ -7,11 +7,11 @@
}
public interface IOptional<T>
{
bool Allow { get; }
T Value { get; }
bool Allow { get; set; }
T Value { get; set; }
}
[System.Serializable]
public record Optional<T> : IOptional<T>
public class Optional<T> : IOptional<T>
{
#if NET5_0_OR_GREATER
bool allow;
@ -23,8 +23,18 @@
T value;
#endif
public bool Allow { get => allow; set => allow = value;}
public T Value { get => value; set => this.value = value; }
public void SetValueThenAllow(T newValue) => value = newValue;
public T Value
{
get => value;
set=>this.value=value;
}
public void SetValueThenAllow(T newValue)
{
value = newValue;
allow = true;
}
public void Clear()
{
Allow = false;

View File

@ -1,9 +1,12 @@
namespace BITKit
using System;
namespace BITKit
{
/// <summary>
/// 订阅者,发布者下发任务给支持并优先级最高的订阅者
/// </summary>
/// <typeparam name="T"></typeparam>
[Obsolete]
public interface TaskSubscriber<in T>
{
/// <summary>
@ -22,6 +25,7 @@
/// 发布接口,向发布者下发任务
/// </summary>
/// <typeparam name="T"></typeparam>
[Obsolete("Use Func Instanced",true)]
public interface TaskPublisher<in T>
{
/// <summary>

View File

@ -1,4 +1,5 @@
using System;
// ReSharper disable UnassignedGetOnlyAutoProperty
namespace BITKit.UX
{
@ -44,7 +45,7 @@ namespace BITKit.UX
}
public abstract class UXPanelImplement:IUXPanel
{
private IUXPanel _iuxPanelImplementation1;
protected virtual IUXPanel _iuxPanelImplementation1 { get; }
protected abstract IUXPanel _iuxPanelImplementation { get; }
public bool IsAnimate => _iuxPanelImplementation.IsAnimate;

View File

@ -11,6 +11,7 @@ namespace BITKit
public const string Status = "Status";
public const string State = "State";
public const string Settings = "Settings";
public const string Services = "Services";
public const string AudioClip = "AudioClip";
public const string AudioSource = "AudioSource";
public const string Paths = "Paths";

View File

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Text;
namespace BITKit
{
/// <summary>泛型事件,简单的事件接口</summary>
@ -39,6 +40,12 @@ namespace BITKit
var list = events.Get(key);
list.Add(action);
}
public void AddListenerDirect(string key, Action<object> action)
{
events.Get(key).Add(action);
}
public void Invoke<T>(string key, T value)
{
key = key.GetType<T>();
@ -52,6 +59,17 @@ namespace BITKit
}
});
}
public void InvokeDirect(string key,object value)
{
var list = events.Get(key);
list.ToArray().ForEach(x =>
{
if (x is Action<object> action)
{
action.Invoke(value);
}
});
}
public void Invoke(string typeName, object value)
{
var key = $"{typeName}.{defaultEventName}";
@ -80,6 +98,7 @@ namespace BITKit
public void Set<T>(T value) => dictionary.Set(Constant.System.Internal.GetType<T>(), value);
public void Set<T>(string key, T value) => dictionary.Set(key.GetType<T>(), value);
public void Set(Type type, object value) => dictionary.Set($"{type.FullName}.{Constant.System.Internal}", value);
public void SetDirect(string key, object value) => dictionary.Set(key, value);
public void RemoveListener<T>(string key, Action<T> action)
{
key = key.GetType<T>();
@ -115,5 +134,10 @@ namespace BITKit
}
public void Invoke<T>() where T : new() => Invoke(new T());
public bool TryGetObjectDirect(string key, out object value)
{
return dictionary.TryGetValue(key, out value);
}
}
}

View File

@ -4,6 +4,7 @@
{
string Get();
string Value => Get();
string Replace(string value) => Get().Replace("{x}",value);
}
public interface IReference<T>
@ -37,9 +38,12 @@
{
this.value = value;
}
#if UNITY_EDITOR
[UnityEngine.TextArea]
#endif
public string value;
public override string Get() => value;
public override string ToString() => value;
}
[System.Serializable]

View File

@ -5,17 +5,12 @@ namespace BITKit
{
public class ValidHandle
{
public ValidHandle() { Init(); }
public ValidHandle() {}
public ValidHandle(Action<bool> boolDelegate)
{
AddListener(boolDelegate);
Init();
EventOnEnableChanged?.Invoke(enableHandle);
}
void Init()
{
AddListener(OnInoke);
}
public static implicit operator bool(ValidHandle validHandle)
{
return validHandle.enableHandle;
@ -24,8 +19,6 @@ namespace BITKit
public bool Allow => this;
private bool enableHandle;
private int enableElementCount;
private int disableElementCount;
private readonly List<object> objs = new List<object>();
private readonly List<object> disableObjs = new List<object>();
private bool tempEnable;
@ -43,7 +36,7 @@ namespace BITKit
}
CheckEnable();
}
protected virtual void CheckEnable()
protected void CheckEnable()
{
tempEnable = objs.Count > 0 && disableObjs.Count == 0;
if (tempEnable != enableHandle)
@ -51,13 +44,8 @@ namespace BITKit
enableHandle = tempEnable;
if (EventOnEnableChanged is not null)
EventOnEnableChanged.Invoke(enableHandle);
OnEnable(enableHandle);
}
enableElementCount = objs.Count;
disableElementCount = disableObjs.Count;
}
protected virtual void OnEnable(bool enable) { }
public virtual void RemoveElement(object obj)
{
if (objs.Contains(obj))
@ -93,7 +81,7 @@ namespace BITKit
}
CheckEnable();
}
public virtual void RemoveDisableElements(object obj)
public void RemoveDisableElements(object obj)
{
if (disableObjs.Contains(obj))
{
@ -104,7 +92,7 @@ namespace BITKit
}
CheckEnable();
}
public virtual void SetElements(object obj, bool add = true)
public void SetElements(object obj, bool add = true)
{
if (add)
{
@ -126,29 +114,33 @@ namespace BITKit
RemoveDisableElements(obj);
}
}
public virtual void Invoke()
public void Invoke()
{
bool enable = disableObjs.Count == 0 && objs.Count > 0;
EventOnEnableChanged.Invoke(enable);
var enable = disableObjs.Count == 0 && objs.Count > 0;
EventOnEnableChanged?.Invoke(enable);
}
public virtual void Invoke(bool value)
public void Invoke(bool value)
{
EventOnEnableChanged.Invoke(value);
EventOnEnableChanged?.Invoke(value);
}
public virtual void OnInoke(bool value)
{
}
public virtual void AddListener(Action<bool> action)
public void AddListener(Action<bool> action)
{
EventOnEnableChanged+= action;
}
public virtual void RemoveListener(Action<bool> action)
public void RemoveListener(Action<bool> action)
{
if(EventOnEnableChanged is not null && action is not null)
{
EventOnEnableChanged -= action;
}
}
public void Clear()
{
objs.Clear();
disableObjs.Clear();
Invoke();
}
}
}

View File

@ -18,7 +18,6 @@ namespace BITKit
[BITCommand]
public static void Set(string key, string value)
{
Data.Set(key, value);
if (Guid.TryParse(value, out var guidResult))
{
Data.Set(key, guidResult);
@ -35,6 +34,10 @@ namespace BITKit
{
Data.Set(key, intResult);
}
else
{
Data.Set(key, value);
}
}
[BITCommand]
public static void SetContainer(string key, string typeName, string json)

View File

@ -32,6 +32,12 @@ namespace BITKit
return GetPath(paths);
}
public static void EnsureDirectoryCreated(string path)
{
path = Path.GetDirectoryName(path);
if (Directory.Exists(path) is true) return;
if (path != null) Directory.CreateDirectory(path);
}
public static string GetFilePath(params string[] paths)
{

8
Src/EntityFramework.meta Normal file
View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b6a022bce79573f4e92be71426b89938
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,16 @@
{
"name": "BITKit.EntityFramework",
"rootNamespace": "",
"references": [],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [
"NET5_0_OR_GREATER"
],
"versionDefines": [],
"noEngineReferences": false
}

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 715ab799293af1942afd9ce5ef57c99b
guid: a3f593891073dfc4c860f7df41ef8e2c
AssemblyDefinitionImporter:
externalObjects: {}
userData:

View File

@ -0,0 +1,54 @@
#if NET5_0_OR_GREATER
using System;
using Cysharp.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
namespace BITKit;
public interface IDatabaseContext<T> where T : class
{
void Add(T entity);
UniTask AddAsync(T entity);
void Remove(T entity);
T[] GetArray();
bool TrySearch(Func<T, bool> searchFactory, out T result);
bool TrySearchArray(Func<T, bool> searchFactory, out T[] result);
}
public abstract class EntityFrameworkContext<T>:DbContext ,IDatabaseContext<T> where T : class
{
protected DbSet<T> context { get; private set; }
public void Add(T entity)
{
context.Add(entity);
SaveChanges();
}
public async UniTask AddAsync(T entity)
{
await context.AddAsync(entity);
await SaveChangesAsync();
}
public void Remove(T entity)
{
throw new NotImplementedException();
}
public T[] GetArray()
{
throw new NotImplementedException();
}
public bool TrySearch(Func<T, bool> searchFactory, out T result)
{
throw new NotImplementedException();
}
public bool TrySearchArray(Func<T, bool> searchFactory, out T[] result)
{
throw new NotImplementedException();
}
}
#endif

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 355b442bac74fd443b42f7f601c5a824
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,19 @@
#if NET5_0_OR_GREATER
using Microsoft.EntityFrameworkCore;
namespace BITKit;
public class MySQLContext<T>:DbContext where T:class
{
protected readonly string _connectSql;
protected DbSet<T> context { get; private set; }
public MySQLContext(string connectSql) : base()
{
_connectSql = connectSql;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseMySQL("_connectSql");
}
}
#endif

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 88296b712b21d1549acf51a95b74e126
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,82 @@
#if NET5_0_OR_GREATER
using System;
using System.Linq;
using Cysharp.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
namespace BITKit;
public class SqlLiteContext<T> : DbContext,IDatabaseContext<T> where T : class
{
public DbSet<T> context { get; private set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
var sql = SQLiteContextHelper.GetConnectionString<T>();
optionsBuilder.UseSqlite(sql);
}
public virtual void Add(T entity)
{
context.Add(entity);
SaveChanges();
}
public UniTask AddAsync(T entity)
{
throw new NotImplementedException();
}
public virtual void Remove(T entity)
{
context.Remove(entity);
SaveChanges();
}
public virtual T[] GetArray()
{
return context.ToArray();
}
public virtual bool TrySearch(Func<T,bool> searchFactory,out T result)
{
result = context.FirstOrDefault(searchFactory);
return result != null;
}
/// <summary>
/// 搜索数组
/// </summary>
/// <param name="searchFactory"></param>
/// <param name="result"></param>
/// <returns></returns>
public virtual bool TrySearchArray(Func<T, bool> searchFactory, out T[] result)
{
result = context.Where(searchFactory).ToArray();
return result.Length > 0;
}
}
public static class SQLiteContextHelper
{
private const string _database = "Database";
public static string GetConnectionString(string key)
{
GetConnectionSqlAndPath(key,out var connectionSql,out var path);
BIT4Log.Log($"已创建数据库链接:{path}");
return connectionSql;
}
public static string GetConnectionString<T>()
{
GetConnectionSqlAndPath(typeof(T).Name,out var connectionSql,out var path);
BIT4Log.Log<T>($"已创建数据库链接:{path}");
return connectionSql;
}
public static void GetConnectionSqlAndPath(string name,out string connectionSql,out string path)
{
PathHelper.GetFolderPath(_database);
path = PathHelper.GetPath(_database, $"{name}.db");
connectionSql = $"Data Source={path}";
}
}
#endif

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 051098367a2e84d4c9ade3bc7ef6eb1e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 17d6f75da2f6aef4491958ba74c65d1e
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -26,6 +26,7 @@ RenderTexture:
m_UseDynamicScale: 0
m_BindMS: 0
m_EnableCompatibleFormat: 1
m_EnableRandomWrite: 0
m_TextureSettings:
serializedVersion: 2
m_FilterMode: 1

View File

@ -76,7 +76,7 @@ Transform:
m_GameObject: {fileID: 4263150313831602955}
serializedVersion: 2
m_LocalRotation: {x: -0, y: 0.99025595, z: -0.1392595, w: 0}
m_LocalPosition: {x: 2.14, y: 1.942205, z: -0.5443456}
m_LocalPosition: {x: 2.1400003, y: 1.942205, z: -0.5443456}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
@ -255,7 +255,7 @@ MonoBehaviour:
m_RotationOrder: 4
cameraDistanceLimit: {x: 1, y: 64}
allowInput:
rid: 6077775057159979015
rid: 8000561620556709889
touchesCount: 0
isParallelVector: 0
lookInput: {x: 0, y: 0, z: 0}
@ -263,8 +263,8 @@ MonoBehaviour:
references:
version: 2
RefIds:
- rid: 6077775057159979015
type: {class: AllowTouchWhenPointerNotOverUI, ns: BITKit.UX, asm: BITKit.UX.OnScreen}
- rid: 8000561620556709889
type: {class: AllowCondition, ns: BITKit, asm: BITKit.Node}
data:
--- !u!1 &4263150314961711450
GameObject:

View File

@ -50,6 +50,8 @@ namespace BITKit
remove => ApplicationService.OnDownloadComplete -= value;
}
public event Action OnDetectedLatestVersion;
public UniTask<string> DownloadLatestVersionAsync()
{
return _applicationServiceImplementation.DownloadLatestVersionAsync();
@ -104,6 +106,12 @@ namespace BITKit
remove => OnDownloadComplete -= value;
}
public event Action OnDetectedLatestVersion
{
add => Singleton.OnDetectedLatestVersion += value;
remove => Singleton.OnDetectedLatestVersion -= value;
}
private UnityWebRequest downloadRequest;
private CancellationTokenSource _cancellationTokenSource;

View File

@ -2,7 +2,6 @@ using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.Remoting.Contexts;
using UnityEngine;
using Cysharp.Threading.Tasks;
using System.Threading.Tasks;
@ -79,10 +78,8 @@ namespace BITKit
BIT4Log.OnLog += Debug.Log;
BIT4Log.OnWarning += Debug.LogWarning;
BIT4Log.OnException += Debug.LogException;
var settings = Addressables.LoadAssetAsync<ScriptableObject>("Assets/BITKit/Unity/Configs/AppSettings.asset").WaitForCompletion() as BITSettingsSO;
//启动BITApp
BITApp.Start(Application.productName, settings!.appSettings);
BITApp.Start(Application.productName, new BITApp.AppSettings()).Forget();
AllowCursor = new();
AllowTouchSupport = new();

View File

@ -1,10 +1,17 @@
using System.Collections;
using System.Collections.Generic;
using Newtonsoft.Json;
using UnityEngine;
namespace BITKit
{
public class BITSettingsSO : ScriptableObject
{
public BITApp.AppSettings appSettings;
[ContextMenu(nameof(Print))]
public void Print()
{
GUIUtility.systemCopyBuffer = JsonConvert.SerializeObject(appSettings.blackList, Formatting.Indented);
}
}
}

View File

@ -196,8 +196,8 @@ namespace BITKit
private void Update()
{
//var debuger = DI.Get<IDebuger>();
var playerConfig = PlayerConfig.singleton;
var sensitivity = playerConfig.touchSensitivity;
var playerConfig = PlayerConfig.Singleton;
var sensitivity = playerConfig.TouchSensitivity;
//debuger.Log(nameof(Touch.activeTouches), Touch.activeTouches.Count.ToString());
touchesCount = Touch.activeTouches.Count;
@ -229,8 +229,8 @@ namespace BITKit
private void OnView(InputAction.CallbackContext context)
{
if (allowInput.OnCheck() is false) return;
var playerConfig = PlayerConfig.singleton;
var sensitivity = playerConfig.sensitivity * playerConfig.m_yaw;
var playerConfig = PlayerConfig.Singleton;
var sensitivity = playerConfig.Sensitivity * playerConfig.M_Yaw;
var delta = context.ReadValue<Vector2>();
switch (context.control.device)
{

View File

@ -1,15 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace BITKit
{
public class ExcuteCommand : MonoBehaviour
{
public string command;
public void Excute()
{
Data.Set("Cmd", command);
}
}
}

View File

@ -0,0 +1,22 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace BITKit
{
public class ExecuteCommand : MonoBehaviour
{
public string command;
[SerializeReference, SubclassSelector] private IReference format;
public void Execute()
{
Data.Set("Cmd", command);
}
public void Execute(string cmd)
{
if(format!=null)
cmd = format.Value.Replace("{x}",cmd);
BITCommands.Excute(cmd);
}
}
}

View File

@ -5,11 +5,10 @@ namespace BITKit
{
public record PlayerConfig
{
[SaveData]
public static PlayerConfig singleton = new();
public float sensitivity = 1.81f;
public float touchSensitivity = 0.22f;
public float m_yaw = 0.022f;
public float fov = 75;
public static readonly PlayerConfig Singleton = new();
public float Sensitivity = 1.81f;
public float TouchSensitivity = 0.22f;
public float M_Yaw = 0.022f;
public float Fov = 75;
}
}

View File

@ -5,7 +5,6 @@ using UnityEngine.SceneManagement;
using System.Linq;
using Newtonsoft.Json;
using UnityEngine.Pool;
using BITModel;
namespace BITKit
{
public class UnityDiagnostics : MonoBehaviour, IDiagnostics

View File

@ -14,7 +14,9 @@
"GUID:28c2d6a6727d47442a24a353f0d37846",
"GUID:14fe60d984bf9f84eac55c6ea033a8f4",
"GUID:d525ad6bd40672747bde77962f1c401e",
"GUID:be17a8778dbfe454890ed8279279e153"
"GUID:be17a8778dbfe454890ed8279279e153",
"GUID:96f476e982d6fb945bfc9140ba094b7f",
"GUID:4307f53044263cf4b835bd812fc161a4"
],
"includePlatforms": [],
"excludePlatforms": [],

View File

@ -0,0 +1,12 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace BITKit.Entities.Movement
{
public sealed class GravityDamage:IDamageType
{
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cdf96f81bc60af44e8233982c2183015
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -5,6 +5,9 @@ using BITKit;
using BITKit.Animations;
using BITKit.StateMachine;
using System.Linq;
using BITFALL.Player.Equip;
using Cinemachine;
namespace BITKit.Entities
{
public interface IEquipBase : IEntryElement, IAwake, IStart, IUpdate
@ -31,10 +34,17 @@ namespace BITKit.Entities
public virtual void EquipEvent(string eventName){}
public virtual void AnimationEvent(string eventName){}
}
public class EntityEquipment : EntityComponent
[CustomType(typeof(IEquipService))]
public class EntityEquipment : EntityComponent,IEquipService
{
public EntryGroup<IEquipBase> equips = new();
public IOptional<float> Zoom { get; } = new Optional<float>(){Value = 1};
public float InitialFov;
[SerializeField] private CinemachineVirtualCamera virtualCamera;
protected IEquipBase entryComplete;
private PlayerConfig playerConfig;
public override void OnStart()
{
base.OnStart();
@ -56,6 +66,13 @@ namespace BITKit.Entities
{
entryComplete.OnUpdate(deltaTime);
}
var current = virtualCamera.m_Lens.FieldOfView;
current= Mathf.Lerp(current,Zoom.Allow ? InitialFov / Zoom.Value : PlayerConfig.Singleton.Fov , deltaTime * 5);
current = Mathf.Clamp(current, 10, PlayerConfig.Singleton.Fov);
virtualCamera.m_Lens.FieldOfView = current;
}
}
}

View File

@ -37,8 +37,18 @@ namespace BITKit.Entities
public interface IHealth
{
/// <summary>
/// 当设置HP时的回调
/// </summary>
public event Action<int> OnSetHealthPoint;
/// <summary>
/// 当设置生存状态时的回调
/// </summary>
public event Action<bool> OnSetAlive;
/// <summary>
/// 当受到伤害时的回调
/// </summary>
public event Func<DamageMessage,int,int> OnDamage;
int HealthPoint { get; set; }
int MaxHealthPoint { get; set; }
bool IsAlive { get; }
@ -50,14 +60,13 @@ namespace BITKit.Entities
[SerializeField] private int healthPoint = 100;
[SerializeField] private int maxHealthPoint = 100;
[Header(Constant.Header.Events)]
[SerializeField] private UnityEvent<bool> onSetAlive = new();
[Header(Constant.Header.Providers)] [SerializeField, SerializeReference, SubclassSelector]
[Obsolete]
private IHealthCallback[] additiveCallback;
public event Action<int> OnSetHealthPoint;
public event Action<bool> OnSetAlive;
public event Func<DamageMessage,int, int> OnDamage;
public int HealthPoint
{
@ -72,7 +81,7 @@ namespace BITKit.Entities
public bool IsAlive { get; private set; }
public override void OnAwake()
{
entity.AddListener<DamageMessage>(OnDamage);
entity.AddListener<DamageMessage>(OnGetDamage);
}
public override void OnStart()
@ -95,11 +104,6 @@ namespace BITKit.Entities
x.OnSetHP(newHP);
}
foreach (var x in additiveCallback)
{
x.OnSetHP(newHP);
}
OnSetHealthPoint?.Invoke(newHP);
}
@ -110,12 +114,11 @@ namespace BITKit.Entities
{
x.OnSetAlive(alive);
}
foreach (var x in additiveCallback)
{
x.OnSetAlive(alive);
}
// foreach (var x in additiveCallback)
// {
// x.OnSetAlive(alive);
// }
OnSetAlive?.Invoke(alive);
onSetAlive.Invoke(alive);
}
private void AddHP(int hp)
@ -123,10 +126,15 @@ namespace BITKit.Entities
OnHealthPointChangedInternal(healthPoint, healthPoint += hp);
}
private void OnDamage(DamageMessage damageMessage)
private void OnGetDamage(DamageMessage damageMessage)
{
if (damageMessage.target == entity)
AddHP(-damageMessage.damage);
if (damageMessage.target != entity) return;
var damage = damageMessage.damage;
foreach (var x in OnDamage.CastAsFunc())
{
damage = x.Invoke(damageMessage,damage);
}
AddHP(-damage);
}
#if UNITY_EDITOR
[BIT]

View File

@ -6,7 +6,10 @@
"GUID:709caf8d7fb6ef24bbba0ab9962a3ad0",
"GUID:f822dbf6fdfd4a5469cccaa2e4eed3b6",
"GUID:f51ebe6a0ceec4240a699833d6309b23",
"GUID:75469ad4d38634e559750d17036d5f7c"
"GUID:75469ad4d38634e559750d17036d5f7c",
"GUID:d525ad6bd40672747bde77962f1c401e",
"GUID:49b49c76ee64f6b41bf28ef951cb0e50",
"GUID:508392158bd966c4d9c21e19661a441d"
],
"includePlatforms": [],
"excludePlatforms": [],

View File

@ -1,3 +1,4 @@
using BITKit.Sensors;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Interactions;
@ -6,24 +7,16 @@ namespace BITKit.Entities.Player
public class EntityInteractive : EntityPlayerComponent
{
[Header(Constant.Header.Settings)]
public float distance;
public LayerMask layerMask;
[Header(Constant.Header.Input)]
public InputActionReference interactiveAction;
private readonly InputActionGroup inputActionGroup = new();
[Header(Constant.Header.Gameobjects)]
[SerializeField] private Transform cameraTransform;
[SerializeReference, SubclassSelector] private ISensor sensor;
[Header(Constant.Header.InternalVariables)]
private ISelectable selected;
private IntervalUpdate cd = new(0.08f);
public override void OnUpdate(float deltaTime)
{
if (Physics.Raycast(cameraTransform.position,cameraTransform.forward, out var raycastHit, distance, layerMask,QueryTriggerInteraction.Collide))
if (sensor.Get().TryGetAny(x=>x.TryGetComponentAny<ISelectable>(out _),out var detected))
{
if (raycastHit.transform.TryGetComponentAny<ISelectable>(out var _detected))
if (detected.TryGetComponentAny<ISelectable>(out var _detected))
{
if (_detected == selected)
{
@ -68,7 +61,7 @@ namespace BITKit.Entities.Player
}
public void Interactive(InputAction.CallbackContext context)
{
if (context.interaction is not PressInteraction || !context.performed) return;
if (context.interaction is not PressInteraction || !context.performed || cd.AllowUpdate is false) return;
var _selected = selected;
if (_selected is not MonoBehaviour monoBehaviour) return;
if (monoBehaviour.TryGetComponentAny<IAction>(out var action))

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e832535d9d9241a4a8f5ce3ca4bdfe10
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 0de6b422fe6534e4c9d6d6cec7812dc1
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

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

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 5a8522cbb18cbd74a847d0fd43c747cb
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,14 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace BITKit.Entities.Value
{
/// <summary>
/// 实体属性接口,通常用于角色的可被数值化的属性
/// </summary>
public interface IEntityValue
{
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cd3c71baeb6c69642b7e53b45eca93e8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using UnityEngine;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using BITKit.Core.Entites;
using Cysharp.Threading.Tasks;
@ -17,30 +18,62 @@ namespace BITKit.Entities
private readonly Processor processor = new();
public IEntityComponent[] entityComponents { get; set; }
public ulong Id { get; private set; }
public CancellationToken CancellationToken => _cancellationToken;
Core.Entites.IEntityComponent[] Core.Entites.IEntity.Components => _components;
bool Core.Entites.IEntity.RegisterComponent<T>(T component)
{
throw new InvalidOperationException("Unity Entity can't register component");
}
IServiceProvider Core.Entites.IEntity.ServiceProvider=> throw new InvalidOperationException("Unity Entity can't register component");
private CancellationToken _cancellationToken;
private bool isInitialized;
private Core.Entites.IEntityComponent[] _components => entityComponents;
private void Awake()
{
Id = (ulong)Guid.NewGuid().GetHashCode();
_cancellationToken = gameObject.GetCancellationTokenOnDestroy();
Set(_cancellationToken);
foreach (var serviceRegister in GetComponentsInChildren<IServiceRegister>(true))
{
genericEvent.Set(serviceRegister.BaseType, serviceRegister);
}
entityComponents = GetComponentsInChildren<IEntityComponent>(true).Distinct().ToArray();
foreach (var x in entityComponents)
{
foreach (var att in x.GetType().GetCustomAttributes<CustomTypeAttribute>())
{
genericEvent.Set(att.Type, x);
}
}
entityComponents.ForEach(x => x.Initialize(this));
UnityEntitiesService.Register(this);
}
private void Start()
{
foreach (var x in entityComponents)
{
foreach (var att in x.GetType().GetCustomAttributes<CustomTypeAttribute>())
{
genericEvent.Set(att.Type,x);
genericEvent.Set(att.Type.FullName, x);
genericEvent.SetDirect(att.Type.FullName,x);
}
}
foreach (var x in GetComponentsInChildren<MonoBehaviour>(true))
{
foreach (var fieldInfo in x
.GetType()
.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
.Where(fieldInfo=>fieldInfo.GetCustomAttribute<InjectAttribute>() is not null))
{
var type = fieldInfo.FieldType;
if(genericEvent.TryGetObjectDirect(type.FullName,out var value))
{
fieldInfo.SetValue(x,value);
}
else
{
BIT4Log.Warning<Entity>($"{name}未找到{type.FullName}");
BIT4Log.Warning<Entity>(genericEvent.GetDiagnostics());
}
}
}
entityComponents.ForEach(x => x.Initialize(this));
entityComponents.ForEach(x => x.OnAwake());
entityComponents.ForEach(x => x.OnStart());
isInitialized = true;

View File

@ -41,22 +41,22 @@ public class UnityEntitiesServiceSingleton:IEntitiesService
public IEntity Get(ulong id) => UnityEntitiesService.Get(id);
public IEntity[] Query<T>() where T : IEntityComponent
public IEntity[] Query<T>()
{
return UnityEntitiesService.Query<T>();
}
public T[] QueryComponents<T>() where T : IEntityComponent
public T[] QueryComponents<T>()
{
return UnityEntitiesService.QueryComponents<T>();
}
public (T, T1)[] QueryComponents<T, T1>() where T : IEntityComponent where T1 : IEntityComponent
public (T, T1)[] QueryComponents<T, T1>()
{
return UnityEntitiesService.QueryComponents<T, T1>();
}
public (T, T1, T2)[] QueryComponents<T, T1, T2>() where T : IEntityComponent where T1 : IEntityComponent where T2 : IEntityComponent
public (T, T1, T2)[] QueryComponents<T, T1, T2>()
{
return UnityEntitiesService.QueryComponents<T, T1, T2>();
}
@ -64,13 +64,12 @@ public class UnityEntitiesServiceSingleton:IEntitiesService
public class UnityEntitiesService : MonoBehaviour,IEntitiesService
{
[RuntimeInitializeOnLoadMethod]
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
private static void Initialize()
{
Dictionary.Clear();
RegisterQueue.Clear();
UnRegisterQueue.Clear();
}
public static bool Register(IEntity entity)
{
@ -127,12 +126,12 @@ public class UnityEntitiesService : MonoBehaviour,IEntitiesService
public static IEntity Get(ulong id)=>Dictionary[id];
IEntity IEntitiesService.Get(ulong id)=>Get(id);
IEntity[] IEntitiesService.Query<T>()=>Query<T>();
public static IEntity[] Query<T>() where T : IEntityComponent
public static IEntity[] Query<T>()
{
return Entities.Where(x => ((Entity)x).TryGetComponentAny<T>(out _)).ToArray();
}
T[] IEntitiesService.QueryComponents<T>()=>QueryComponents<T>();
public static T[] QueryComponents<T>() where T : IEntityComponent
public static T[] QueryComponents<T>()
{
var list = ListPool<T>.Get();
foreach (var iEntity in Entities)
@ -150,7 +149,7 @@ public class UnityEntitiesService : MonoBehaviour,IEntitiesService
return value;
}
(T, T1)[] IEntitiesService.QueryComponents<T,T1>()=>QueryComponents<T,T1>();
public static (T, T1)[] QueryComponents<T, T1>() where T : IEntityComponent where T1 : IEntityComponent
public static (T, T1)[] QueryComponents<T, T1>()
{
var list = ListPool<(T t, T1 t1)>.Get();
foreach (var iEntity in Entities)
@ -168,7 +167,7 @@ public class UnityEntitiesService : MonoBehaviour,IEntitiesService
return value;
}
(T, T1, T2)[] IEntitiesService.QueryComponents<T,T1,T2>()=>QueryComponents<T,T1,T2>();
public static (T, T1, T2)[] QueryComponents<T, T1, T2>() where T : IEntityComponent where T1 : IEntityComponent where T2 : IEntityComponent
public static (T, T1, T2)[] QueryComponents<T, T1, T2>()
{
var list = ListPool<(T t, T1 t1, T2 t2)>.Get();
foreach (var iEntity in Entities)

View File

@ -25,7 +25,6 @@ namespace BITKit.Entities.Editor
rootVisualElement.styleSheets.Add(BITEditorUtils.InspectorStyleSheet);
rootVisualElement.styleSheets.Add(BITEditorUtils.Style);
rootVisualElement.AddToClassList("pa-8");
}
private void Update()

View File

@ -1,27 +0,0 @@
{
"name": "BITFALL.Entities.EquipSelector.Runtime",
"rootNamespace": "",
"references": [
"GUID:14fe60d984bf9f84eac55c6ea033a8f4",
"GUID:709caf8d7fb6ef24bbba0ab9962a3ad0",
"GUID:b355af20142c0c541ba9588ab1d0f64e",
"GUID:75469ad4d38634e559750d17036d5f7c",
"GUID:30cdc242b1ac6a944a460f4ab0b77b88",
"GUID:677cd05ca06c46b4395470200b1acdad",
"GUID:7efac18f239530141802fb139776f333",
"GUID:84d565da37ad40546a118cfb3c3509f3",
"GUID:42a9827d94e00374aa52e51f0a1b035c",
"GUID:d525ad6bd40672747bde77962f1c401e",
"GUID:49b49c76ee64f6b41bf28ef951cb0e50",
"GUID:9354affc93e0f3e4a904785e7d4c0f59"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

@ -1,164 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using BITKit;
using BITKit.Entities;
using UnityEngine.InputSystem;
using static UnityEditor.Progress;
using System.Diagnostics;
using System.Linq;
using BITKit.Entities.Player;
using UnityEngine.InputSystem.Interactions;
using Debug = UnityEngine.Debug;
namespace BITFALL
{
[CustomType(typeof(IPlayerEquipSelector))]
public class PlayerEquipSelector : EntityComponent,TaskSubscriber<IBasicItem>,IEntityInventoryCallback,IPlayerEquipSelector
{
[Header(Constant.Header.Components)]
public EntityEquipment equipment;
[Header(Constant.Header.InternalVariables)]
private readonly Dictionary<int, IBasicItem> equips=new();
private IBasicItemContainer inventory;
public event Action<IBasicItem> OnEquip;
public event Action<IBasicItem> OnDeEquip;
public event Action<IDictionary<int, IBasicItem>> OnUpdateEquip;
private IBasicItem currentEquip;
public override void OnAwake()
{
var health = entity.Get<IHealth>();
health.OnSetAlive += OnSetAlive;
OnDeEquip += DeEquip;
OnEquip += Equip;
}
public override void OnStart()
{
base.OnStart();
entity.RegisterCallback<TaskSubscriber<IBasicItem>>(this);
inventory = entity.Get<IBasicItemContainer>();
}
public void OnPrimary(InputAction.CallbackContext context)
{
if (context is not {interaction:PressInteraction ,performed:true}) return;
Equip(1);
}
public void OnSecondary(InputAction.CallbackContext context)
{
if (context is not {interaction:PressInteraction ,performed:true}) return;
Equip(2);
}
public void OnTertiary(InputAction.CallbackContext context)
{
if (context is not {interaction:PressInteraction ,performed:true}) return;
if (Equip(3) is false)
{
Equip(-1);
}
}
public void OnQuaternary(InputAction.CallbackContext context)
{
if (context is not {interaction:PressInteraction ,performed:true}) return;
Equip(4);
}
public void OnHolster(InputAction.CallbackContext context)
{
if (context is not {interaction:PressInteraction ,performed:true}) return;
Equip(-1);
}
private void OnSetAlive(bool alive)
{
if (alive) return;
foreach (var x in equips.ToArray())
{
inventory.Add(x.Value);
}
equips.Clear();
UpdateEquip();
Equip(-1);
}
int TaskSubscriber<IBasicItem>.Priority => 0;
bool TaskSubscriber<IBasicItem>.TryExecute(IBasicItem value)
{
var asset = value.GetAssetable();
if (IsSupportItem(value) is false) return false;
switch (asset)
{
case var _ when asset.TryGetProperty<EquipmentAsWeapon>(out _):
if (equips.TryAdd(1, value) || equips.TryAdd(2,value))
{
OnEquip?.Invoke(value);
UpdateEquip();
return true;
}
break;
}
return false;
}
public void OnAdd(IBasicItem item)
{
}
public void OnRemove(IBasicItem item)
{
if (IsSupportItem(item) is false)
{
UpdateEquip();
}
}
private bool IsSupportItem(IBasicItem item)
{
return equipment.equips.list.Any(x => x.AddressablePath == item.AddressablePath);
}
private void UpdateEquip()
{
OnUpdateEquip?.Invoke(new Dictionary<int, IBasicItem>(equips));
}
public bool TryDeEquip(IBasicItem item)
{
if (item is null) return false;
if (equips.Any(x => x.Value.AddressablePath == item.AddressablePath) is false) return false;
var index = equips.Single(x=>x.Value.AddressablePath==item.AddressablePath).Key;
if (equips.TryRemove(index) is false) return false;
if (!inventory.Add(item)) return false;
OnDeEquip?.Invoke(item);
UpdateEquip();
return true;
}
private void Equip(IBasicItem item)
{
if (item is null)
{
equipment.equips.Entry(-1);
}
else
{
equipment.equips.Entry(x=>x.AddressablePath == item.AddressablePath);
}
}
private bool Equip(int index)
{
if (!equips.TryGetValue(index, out var x) && index is not -1) return false;
if (index is -1)
{
OnEquip?.Invoke(x);
}
return true;
}
private void DeEquip(IBasicItem item)
{
equipment.equips.Entry(-1);
}
}
}

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 4718485b2b78cbb4b8e3cd04c04ba6f8
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,163 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Newtonsoft.Json;
using UnityEditor.UIElements;
#if UNITY_EDITOR
using Cysharp.Threading.Tasks;
using UnityEditor;
#endif
using UnityEngine;
using UnityEngine.UIElements;
using Object = UnityEngine.Object;
namespace BITKit.Events
{
[Serializable]
public class UnityEventData
{
public Object Target;
public string MethodName;
}
[Serializable]
public class UnityEvent
{
public List<UnityEventData> Targets = new List<UnityEventData>();
public void Invoke(params object[] objects)
{
foreach (var x in Targets)
{
var method =x.Target.GetType().GetMethod(x.MethodName);
try
{
method?.Invoke(x.Target, objects);
}
catch (TargetParameterCountException e)
{
Debug.LogWarning(string.Join(",",method?.GetParameters().Select(x=>x.Name)));
throw;
}
}
}
}
#if UNITY_EDITOR
[CustomPropertyDrawer(typeof(UnityEvent))]
public class UnityEventDataPropertyDrawer:PropertyDrawer
{
private VisualElement root;
private UnityEvent agent;
private SerializedProperty _property;
private static readonly List<string> _unityMethodNames = typeof(MonoBehaviour).GetMethods().Select(x => x.Name).ToList();
public override VisualElement CreatePropertyGUI(SerializedProperty property)
{
_property = property;
agent = property.Get<UnityEvent>();
root = new VisualElement
{
style =
{
paddingLeft = 10,
paddingTop = 10,
paddingRight = 10,
paddingBottom = 10,
}
};
root.styleSheets.Add(BITEditorUtils.InspectorStyleSheet);
Update();
return root;
}
private void Update()
{
root.Clear();
var targets = _property.FindPropertyRelative(nameof(UnityEvent.Targets));
_property.serializedObject.Update();
var label = root.Create<Label>();
label.text = _property.displayName;
var flex = root.Create<VisualElement>();
flex.style.flexDirection = FlexDirection.Row;
var containers = new[] { flex.Create<VisualElement>(), flex.Create<VisualElement>(),flex.Create<VisualElement>() };
containers[1].style.flexGrow = 1;
for (var i = 0; i < targets.arraySize; i++)
{
var x = agent.Targets[i];
var objectField = containers[0].Create<ObjectField>();
var field = containers[1].Create<DropdownField>();
var removeButton = containers[2].Create<Button>();
var data = targets.GetArrayElementAtIndex(i);
var target = data.FindPropertyRelative(nameof(UnityEventData.Target));
objectField.BindProperty(target);
if (x.Target is not null)
{
field.choices = x.Target
.GetType()
.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
.Where(x=>x.IsSpecialName is false)
.Where(x=>x.GetCustomAttribute<ObsoleteAttribute>() is null)
.Select(x => x.Name)
//.Where(x=>_unityMethodNames.Contains(x) is false)
.ToList();
}
field.RegisterValueChangedCallback(changeEvent =>
{
x.MethodName = changeEvent.newValue;
EditorUtility.SetDirty(_property.serializedObject.targetObject);
});
field.value = x.MethodName;
field.style.flexGrow = 1;
removeButton.text = "X";
removeButton.clicked+=()=>{
agent.Targets.Remove(x);
Update();
};
}
var addButton = root.Create<Button>();
addButton.text = "Add";
addButton.clicked += () =>
{
agent.Targets.Add(new());
Update();
};
var invokeButton = root.Create<Button>();
invokeButton.text = "Invoke";
invokeButton.clicked +=()=> agent.Invoke();
}
}
#endif
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 037e8fe9dc2ba9f438112d7a8c3160cb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Some files were not shown because too many files have changed in this diff Show More