This commit is contained in:
parent
c1273357de
commit
d8b8ddb8b6
|
@ -39,6 +39,7 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Kcp" Version="2.6.3" />
|
<PackageReference Include="Kcp" Version="2.6.3" />
|
||||||
|
<PackageReference Include="LiteDB" Version="5.0.21" />
|
||||||
<PackageReference Include="MemoryPack" Version="1.21.3" />
|
<PackageReference Include="MemoryPack" Version="1.21.3" />
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.12.0" />
|
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.12.0" />
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.Scripting.Common" Version="4.12.0" />
|
<PackageReference Include="Microsoft.CodeAnalysis.Scripting.Common" Version="4.12.0" />
|
||||||
|
|
|
@ -7,4 +7,9 @@ namespace BITKit.Entities
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class OwnedByLocalPlayer
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,20 +22,18 @@ namespace BITKit.Entities
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public unsafe class EntitiesService : IEntitiesService, IDisposable
|
public class EntitiesService : IEntitiesService, IDisposable
|
||||||
{
|
{
|
||||||
private static int _count;
|
private static int _count;
|
||||||
|
|
||||||
|
|
||||||
private readonly ILogger<EntitiesService> _logger;
|
private readonly ILogger<EntitiesService> _logger;
|
||||||
private readonly ITicker _ticker;
|
private readonly ITicker _ticker;
|
||||||
|
|
||||||
private readonly ConcurrentQueue<IEntity> _onAddQueue = new();
|
private readonly ConcurrentQueue<IEntity> _onAddQueue = new();
|
||||||
|
private readonly HashSet<IEntity> _addingEntities = new();
|
||||||
private readonly Dictionary<int, HashSet<int>> _typeCaches = new();
|
private readonly Dictionary<int, HashSet<int>> _typeCaches = new();
|
||||||
private readonly Dictionary<int, ConcurrentDictionary<int, object>> _typeInstances = new();
|
private readonly Dictionary<int, ConcurrentDictionary<int, object>> _typeInstances = new();
|
||||||
|
|
||||||
private readonly ConcurrentDictionary<int, object> _staticCaches = new();
|
|
||||||
|
|
||||||
public EntitiesService(ILogger<EntitiesService> logger, ITicker ticker)
|
public EntitiesService(ILogger<EntitiesService> logger, ITicker ticker)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
@ -48,35 +46,17 @@ namespace BITKit.Entities
|
||||||
logger.LogInformation($"已创建EntitiesService,当前有:{_count}个实例");
|
logger.LogInformation($"已创建EntitiesService,当前有:{_count}个实例");
|
||||||
|
|
||||||
_ticker?.Add(OnTick);
|
_ticker?.Add(OnTick);
|
||||||
|
|
||||||
OnAdd += ClearCache;
|
|
||||||
OnRemove += ClearCache;
|
|
||||||
OnRemove += UnRegisterEntity;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UnRegisterEntity(IEntity entity)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
private void ClearCache(IEntity obj)
|
|
||||||
{
|
|
||||||
foreach (var id in _cachedIdCollection)
|
|
||||||
{
|
|
||||||
var hashSet = _typeCaches[id];
|
|
||||||
_pool.Return(hashSet);
|
|
||||||
_typeCaches.Remove(id);
|
|
||||||
}
|
|
||||||
_cachedIdCollection.Clear();
|
|
||||||
_staticCaches.Clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnTick(float obj)
|
private void OnTick(float obj)
|
||||||
{
|
{
|
||||||
while (_onAddQueue.TryDequeue(out var entity))
|
while (_onAddQueue.TryDequeue(out var entity))
|
||||||
{
|
{
|
||||||
|
if(_addingEntities.Remove(entity) is false)continue;
|
||||||
OnAdd?.Invoke(entity);
|
OnAdd?.Invoke(entity);
|
||||||
_staticCaches.Clear();
|
|
||||||
MakeCache(entity);
|
MakeCache(entity);
|
||||||
}
|
}
|
||||||
|
_addingEntities.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MakeCache(IEntity entity)
|
private void MakeCache(IEntity entity)
|
||||||
|
@ -94,7 +74,6 @@ namespace BITKit.Entities
|
||||||
public event Action<IEntity> OnRemove;
|
public event Action<IEntity> OnRemove;
|
||||||
IReadOnlyDictionary<int, IEntity> IEntitiesService.Entities => _entitiesInternal;
|
IReadOnlyDictionary<int, IEntity> IEntitiesService.Entities => _entitiesInternal;
|
||||||
private readonly Pool<HashSet<int>> _pool;
|
private readonly Pool<HashSet<int>> _pool;
|
||||||
private readonly HashSet<int> _cachedIdCollection = new();
|
|
||||||
|
|
||||||
private HashSet<int> ObjectGenerator()
|
private HashSet<int> ObjectGenerator()
|
||||||
{
|
{
|
||||||
|
@ -106,24 +85,23 @@ namespace BITKit.Entities
|
||||||
if (!_entitiesInternal.TryAdd(entity.Id, entity)) return false;
|
if (!_entitiesInternal.TryAdd(entity.Id, entity)) return false;
|
||||||
if (_ticker is not null)
|
if (_ticker is not null)
|
||||||
{
|
{
|
||||||
_onAddQueue.Enqueue(entity);
|
_addingEntities.Add(entity);
|
||||||
|
_onAddQueue.Enqueue(entity);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_staticCaches.Clear();
|
|
||||||
OnAdd?.Invoke(entity);
|
OnAdd?.Invoke(entity);
|
||||||
MakeCache(entity);
|
MakeCache(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool UnRegister(IEntity entity)
|
public bool UnRegister(IEntity entity)
|
||||||
{
|
{
|
||||||
if (!_entitiesInternal.TryRemove(entity.Id)) return false;
|
if (!_entitiesInternal.TryRemove(entity.Id)) return false;
|
||||||
OnRemove?.Invoke(entity);
|
|
||||||
|
_addingEntities.Remove(entity);
|
||||||
|
|
||||||
foreach (var serviceDescriptor in entity.ServiceCollection)
|
foreach (var serviceDescriptor in entity.ServiceCollection)
|
||||||
{
|
{
|
||||||
|
@ -134,7 +112,7 @@ namespace BITKit.Entities
|
||||||
|
|
||||||
_typeInstances.TryRemove(entity.Id);
|
_typeInstances.TryRemove(entity.Id);
|
||||||
|
|
||||||
_staticCaches.Clear();
|
OnRemove?.Invoke(entity);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -379,36 +357,24 @@ namespace BITKit.Entities
|
||||||
where T3 : class
|
where T3 : class
|
||||||
where T4 : class
|
where T4 : class
|
||||||
{
|
{
|
||||||
var combinedHash = typeof(T).GetHashCode() +
|
var pool = ArrayPool<(T, T1, T2, T3,T4)>.Shared;
|
||||||
typeof(T1).GetHashCode() +
|
|
||||||
typeof(T2).GetHashCode() +
|
|
||||||
typeof(T3).GetHashCode() +
|
|
||||||
typeof(T4).GetHashCode();
|
|
||||||
if (_typeCaches.TryGetValue(combinedHash, out var collection) is false)
|
|
||||||
{
|
|
||||||
var hashset = _typeCaches.GetOrCreate(typeof(T).GetHashCode());
|
|
||||||
var t1Set = _typeCaches.GetOrCreate(typeof(T1).GetHashCode());
|
|
||||||
var t2Set = _typeCaches.GetOrCreate(typeof(T2).GetHashCode());
|
|
||||||
var t3Set = _typeCaches.GetOrCreate(typeof(T3).GetHashCode());
|
|
||||||
var t4Set = _typeCaches.GetOrCreate(typeof(T4).GetHashCode());
|
|
||||||
|
|
||||||
collection = _pool.Take();
|
var hashset = _typeCaches.GetOrCreate(typeof(T).GetHashCode());
|
||||||
collection.Clear();
|
var t1Set = _typeCaches.GetOrCreate(typeof(T1).GetHashCode());
|
||||||
|
var t2Set = _typeCaches.GetOrCreate(typeof(T2).GetHashCode());
|
||||||
|
var t3Set = _typeCaches.GetOrCreate(typeof(T3).GetHashCode());
|
||||||
|
var t4Set = _typeCaches.GetOrCreate(typeof(T4).GetHashCode());
|
||||||
|
|
||||||
collection.UnionWith(hashset);
|
var count = math.max(hashset.Count, math.max(t1Set.Count, math.max(t2Set.Count,math.max(t3Set.Count,t4Set.Count))));
|
||||||
collection.IntersectWith(t1Set);
|
|
||||||
collection.IntersectWith(t2Set);
|
|
||||||
collection.IntersectWith(t3Set);
|
|
||||||
collection.IntersectWith(t4Set);
|
|
||||||
|
|
||||||
_typeCaches[combinedHash] = collection;
|
var array = pool.Rent(count);
|
||||||
|
var collection = _pool.Take();
|
||||||
_cachedIdCollection.Add(combinedHash);
|
collection.Clear();
|
||||||
}
|
|
||||||
|
|
||||||
var pool = ArrayPool<(T, T1, T2, T3, T4)>.Shared;
|
|
||||||
var array = pool.Rent(math.ceilpow2(collection.Count));
|
|
||||||
|
|
||||||
|
collection.UnionWith(hashset);
|
||||||
|
collection.IntersectWith(t1Set);
|
||||||
|
collection.IntersectWith(t2Set);
|
||||||
|
collection.IntersectWith(t3Set);
|
||||||
|
|
||||||
var i = 0;
|
var i = 0;
|
||||||
foreach (var id in collection)
|
foreach (var id in collection)
|
||||||
|
@ -446,18 +412,18 @@ namespace BITKit.Entities
|
||||||
instances[h4] = v4 = _entitiesInternal[id].ServiceProvider.GetRequiredService<T4>();
|
instances[h4] = v4 = _entitiesInternal[id].ServiceProvider.GetRequiredService<T4>();
|
||||||
}
|
}
|
||||||
|
|
||||||
array[i] = (Unsafe.As<T>(v0), Unsafe.As<T1>(v1), Unsafe.As<T2>(v2), Unsafe.As<T3>(v3),
|
array[i] = (Unsafe.As<T>(v0), Unsafe.As<T1>(v1), Unsafe.As<T2>(v2), Unsafe.As<T3>(v3),Unsafe.As<T4>(v4));
|
||||||
Unsafe.As<T4>(v4));
|
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return new Span<(T, T1, T2, T3, T4)>(array, 0, i);
|
return new Span<(T, T1, T2, T3,T4)>(array, 0, i);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
pool.Return(array);
|
pool.Return(array);
|
||||||
|
_pool.Return(collection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -541,6 +507,8 @@ namespace BITKit.Entities
|
||||||
}
|
}
|
||||||
|
|
||||||
pool.Return(array);
|
pool.Return(array);
|
||||||
|
_pool.Return(collection);
|
||||||
|
|
||||||
return new Span<(T, T1, T2, T3, T4, T5)>(array, 0, i);
|
return new Span<(T, T1, T2, T3, T4, T5)>(array, 0, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -154,12 +154,7 @@ namespace BITKit
|
||||||
}
|
}
|
||||||
public static bool TryRemove<TKey, TValue>(this IDictionary<TKey, TValue> self, TKey t)
|
public static bool TryRemove<TKey, TValue>(this IDictionary<TKey, TValue> self, TKey t)
|
||||||
{
|
{
|
||||||
if (self.ContainsKey(t))
|
return self.ContainsKey(t) && self.Remove(t);
|
||||||
{
|
|
||||||
self.Remove(t);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
public static void Set<TKey, TValue>(this IDictionary<TKey, TValue> self, TKey key, TValue value)
|
public static void Set<TKey, TValue>(this IDictionary<TKey, TValue> self, TKey key, TValue value)
|
||||||
{
|
{
|
||||||
|
|
|
@ -27,6 +27,7 @@ namespace BITKit
|
||||||
/// 获取所有Item的只读副本
|
/// 获取所有Item的只读副本
|
||||||
/// </summary>
|
/// </summary>
|
||||||
IRuntimeItem[] GetItems();
|
IRuntimeItem[] GetItems();
|
||||||
|
IReadOnlyDictionary<int,IRuntimeItem> ItemDictionary { get; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 添加物品的接口
|
/// 添加物品的接口
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -104,6 +105,7 @@ namespace BITKit
|
||||||
public ValidHandle IsBusy { get; } = new();
|
public ValidHandle IsBusy { get; } = new();
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
public IRuntimeItem[] GetItems()=>Items.Values.ToArray();
|
public IRuntimeItem[] GetItems()=>Items.Values.ToArray();
|
||||||
|
public IReadOnlyDictionary<int, IRuntimeItem> ItemDictionary => Items;
|
||||||
|
|
||||||
public bool Add(IRuntimeItem item)
|
public bool Add(IRuntimeItem item)
|
||||||
{
|
{
|
||||||
|
|
|
@ -43,7 +43,14 @@ namespace BITKit.Tween
|
||||||
{
|
{
|
||||||
from = func(from, to, delta*BITApp.Time.DeltaTime);
|
from = func(from, to, delta*BITApp.Time.DeltaTime);
|
||||||
#if UNITY_5_3_OR_NEWER
|
#if UNITY_5_3_OR_NEWER
|
||||||
await UniTask.NextFrame(PlayerLoopTiming.FixedUpdate,cancellationToken);
|
try
|
||||||
|
{
|
||||||
|
await UniTask.NextFrame(PlayerLoopTiming.FixedUpdate, cancellationToken);
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
|
|
||||||
await UniTask.Yield();
|
await UniTask.Yield();
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f598b42cec79b814dbb8f6e886878f2d
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
|
@ -0,0 +1,157 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using LiteDB;
|
||||||
|
|
||||||
|
namespace Net.BITKit.Database
|
||||||
|
{
|
||||||
|
public class LiteDbDictionary<TKey, TValue> : IDictionary<TKey, TValue>, IDisposable where TKey : notnull
|
||||||
|
{
|
||||||
|
// 内部的 LiteDB 数据库实例
|
||||||
|
private readonly LiteDatabase _db;
|
||||||
|
|
||||||
|
// LiteDB 集合名称可以自定义,默认为 "kv"
|
||||||
|
private readonly ILiteCollection<KeyValueItem> _collection;
|
||||||
|
|
||||||
|
// 内部使用的键值项(POCO类)
|
||||||
|
private class KeyValueItem
|
||||||
|
{
|
||||||
|
// LiteDB 将此字段作为文档的 _id(主键)
|
||||||
|
[BsonId] public TKey Key { get; set; }
|
||||||
|
public TValue Value { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public LiteDbDictionary()
|
||||||
|
{
|
||||||
|
_db = new LiteDatabase(":memory:");
|
||||||
|
_collection = _db.GetCollection<KeyValueItem>(typeof(TValue).Name);
|
||||||
|
_collection.EnsureIndex(x => x.Key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 构造函数
|
||||||
|
/// connectionString 可以是磁盘文件(如 "Filename=MyData.db;Mode=Shared")
|
||||||
|
/// 或内存数据库(如 ":memory:")
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="connectionString">数据库连接字符串</param>
|
||||||
|
/// <param name="collectionName">集合名称,默认 "kv"</param>
|
||||||
|
public LiteDbDictionary(string connectionString, string collectionName = "kv")
|
||||||
|
{
|
||||||
|
_db = new LiteDatabase(connectionString);
|
||||||
|
_collection = _db.GetCollection<KeyValueItem>(collectionName);
|
||||||
|
// 确保对键生成索引
|
||||||
|
_collection.EnsureIndex(x => x.Key);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region IDictionary 实现
|
||||||
|
|
||||||
|
public TValue this[TKey key]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var bsonId = _db.Mapper.Serialize(typeof(TKey), key);
|
||||||
|
var item = _collection.FindById(bsonId);
|
||||||
|
if (item == null) throw new KeyNotFoundException($"Key '{key}' not found.");
|
||||||
|
return item.Value;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
var item = new KeyValueItem { Key = key, Value = value };
|
||||||
|
_collection.Upsert(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ICollection<TKey> Keys => _collection.FindAll().Select(x => x.Key).ToList();
|
||||||
|
public ICollection<TValue> Values => _collection.FindAll().Select(x => x.Value).ToList();
|
||||||
|
public int Count => _collection.Count();
|
||||||
|
public bool IsReadOnly => false;
|
||||||
|
|
||||||
|
public void Add(TKey key, TValue value)
|
||||||
|
{
|
||||||
|
if (ContainsKey(key))
|
||||||
|
throw new ArgumentException($"An element with the key '{key}' already exists.");
|
||||||
|
_collection.Insert(new KeyValueItem { Key = key, Value = value });
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ContainsKey(TKey key)
|
||||||
|
{
|
||||||
|
return _collection.Exists(x => x.Key.Equals(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Remove(TKey key)
|
||||||
|
{
|
||||||
|
var bsonKey = _db.Mapper.Serialize(typeof(TKey), key);
|
||||||
|
return _collection.Delete(bsonKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public bool TryGetValue(TKey key, out TValue value)
|
||||||
|
{
|
||||||
|
var bsonKey = _db.Mapper.Serialize(typeof(TKey), key);
|
||||||
|
var doc = _collection.FindById(bsonKey);
|
||||||
|
if (doc == null)
|
||||||
|
{
|
||||||
|
value = default;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = doc.Value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void Add(KeyValuePair<TKey, TValue> item)
|
||||||
|
{
|
||||||
|
Add(item.Key, item.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
_collection.DeleteAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Contains(KeyValuePair<TKey, TValue> item)
|
||||||
|
{
|
||||||
|
if (TryGetValue(item.Key, out var val))
|
||||||
|
return EqualityComparer<TValue>.Default.Equals(val, item.Value);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
|
||||||
|
{
|
||||||
|
foreach (var kv in this)
|
||||||
|
{
|
||||||
|
array[arrayIndex++] = kv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Remove(KeyValuePair<TKey, TValue> item)
|
||||||
|
{
|
||||||
|
if (Contains(item))
|
||||||
|
return Remove(item.Key);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
|
||||||
|
{
|
||||||
|
foreach (var item in _collection.FindAll())
|
||||||
|
{
|
||||||
|
yield return new KeyValuePair<TKey, TValue>(item.Key, item.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IDisposable 实现
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_db?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 704fac4166e7def409ff7e678716684f
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"name": "Net.BITKit.LiteDb"
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 13c04078920b9764fb623e4ea90c2407
|
||||||
|
AssemblyDefinitionImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
|
@ -38,7 +38,7 @@ namespace BITKit.Apps
|
||||||
_cancelDownloadButton.clicked+=OnCancelDownload;
|
_cancelDownloadButton.clicked+=OnCancelDownload;
|
||||||
destroyCancellationToken.Register(Dispose);
|
destroyCancellationToken.Register(Dispose);
|
||||||
|
|
||||||
_container.Entry("entry-container");
|
_container.Navigate("entry-container");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Dispose()
|
private void Dispose()
|
||||||
|
@ -50,7 +50,7 @@ namespace BITKit.Apps
|
||||||
}
|
}
|
||||||
private void OnDownloadLatest(string obj)
|
private void OnDownloadLatest(string obj)
|
||||||
{
|
{
|
||||||
_container.Entry("download-container");
|
_container.Navigate("download-container");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ConfirmDownload()
|
private void ConfirmDownload()
|
||||||
|
@ -67,7 +67,7 @@ namespace BITKit.Apps
|
||||||
|
|
||||||
private void OnDownloadComplete(string obj)
|
private void OnDownloadComplete(string obj)
|
||||||
{
|
{
|
||||||
_container.Entry("complete-container");
|
_container.Navigate("complete-container");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnDownloadProgress(float obj)
|
private void OnDownloadProgress(float obj)
|
||||||
|
@ -83,16 +83,16 @@ namespace BITKit.Apps
|
||||||
if (Application.version != obj)
|
if (Application.version != obj)
|
||||||
{
|
{
|
||||||
_latestVersionLabel.text =obj;
|
_latestVersionLabel.text =obj;
|
||||||
_container.Entry("entryDownload-container");
|
_container.Navigate("entryDownload-container");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_container.Entry(null);
|
_container.Navigate(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private void OnCancelDownload()
|
private void OnCancelDownload()
|
||||||
{
|
{
|
||||||
_container.Entry(null);
|
_container.Navigate(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ namespace Net.BITKit.Quadtree
|
||||||
{
|
{
|
||||||
|
|
||||||
private readonly IEntitiesService _entitiesService;
|
private readonly IEntitiesService _entitiesService;
|
||||||
private readonly ConcurrentDictionary<int, Transform> _transforms = new();
|
private readonly Dictionary<int, Transform> _transforms = new();
|
||||||
private readonly ITicker _ticker;
|
private readonly ITicker _ticker;
|
||||||
public QuadTreeService(IEntitiesService entitiesService, ITicker ticker)
|
public QuadTreeService(IEntitiesService entitiesService, ITicker ticker)
|
||||||
{
|
{
|
||||||
|
@ -45,16 +45,16 @@ namespace Net.BITKit.Quadtree
|
||||||
|
|
||||||
private void OnTick(float obj)
|
private void OnTick(float obj)
|
||||||
{
|
{
|
||||||
foreach (var (id,transform) in _transforms)
|
foreach (var (id, transform) in _transforms)
|
||||||
{
|
{
|
||||||
Quadtree.Remove(id);
|
Quadtree.Remove(id);
|
||||||
Quadtree.Insert(id,((float3)transform.position).xz);
|
Quadtree.Insert(id, ((float3)transform.position).xz);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnRemove(IEntity obj)
|
private void OnRemove(IEntity obj)
|
||||||
{
|
{
|
||||||
_transforms.TryRemove(obj.Id,out _);
|
_transforms.TryRemove(obj.Id);
|
||||||
Quadtree.Remove(obj.Id);
|
Quadtree.Remove(obj.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.UIElements;
|
||||||
|
|
||||||
|
namespace Net.BITKit.UX
|
||||||
|
{
|
||||||
|
public class AdaptiveGrid : VisualElement
|
||||||
|
{
|
||||||
|
public new class UxmlFactory : UxmlFactory<AdaptiveGrid, UxmlTraits>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public AdaptiveGrid()
|
||||||
|
{
|
||||||
|
style.flexDirection = FlexDirection.Row;
|
||||||
|
style.flexWrap = Wrap.Wrap;
|
||||||
|
|
||||||
|
RegisterCallback<GeometryChangedEvent>(_ => UpdateLayout());
|
||||||
|
RegisterCallback<AttachToPanelEvent>(_ => UpdateLayout());
|
||||||
|
RegisterCallback<DetachFromPanelEvent>(_ => UpdateLayout());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateLayout()
|
||||||
|
{
|
||||||
|
var width = resolvedStyle.width;
|
||||||
|
|
||||||
|
if (childCount == 0 || width <= 0) return;
|
||||||
|
|
||||||
|
var sampleVisualElement = contentContainer[0];
|
||||||
|
|
||||||
|
var max = sampleVisualElement.resolvedStyle.maxWidth.value;
|
||||||
|
var min = sampleVisualElement.resolvedStyle.minHeight.value;
|
||||||
|
|
||||||
|
if (max == 0)
|
||||||
|
{
|
||||||
|
max = sampleVisualElement.resolvedStyle.width;
|
||||||
|
}
|
||||||
|
if(min == 0)
|
||||||
|
{
|
||||||
|
min = max * 0.8f;
|
||||||
|
}
|
||||||
|
|
||||||
|
var count= Mathf.FloorToInt(width / min);
|
||||||
|
|
||||||
|
var remainder = width % count;
|
||||||
|
var itemWidth = (width - remainder) / count;
|
||||||
|
var itemHeight = itemWidth * 0.8f;
|
||||||
|
|
||||||
|
var spacing = (width - itemWidth * count) / (count - 1);
|
||||||
|
spacing = spacing < 0 ? 0 : spacing;
|
||||||
|
|
||||||
|
for (var i = 0; i < childCount; i++)
|
||||||
|
{
|
||||||
|
var child =contentContainer[i];
|
||||||
|
child.style.width = itemWidth-spacing;
|
||||||
|
child.style.height = itemHeight-spacing;
|
||||||
|
|
||||||
|
if (i % count != 0)
|
||||||
|
{
|
||||||
|
child.style.marginRight = spacing;
|
||||||
|
child.style.marginBottom = spacing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: bc041fa6dfb99954099521c02c33ea1c
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
|
@ -39,10 +39,9 @@ namespace BITKit.UX
|
||||||
{
|
{
|
||||||
UXService = uxService;
|
UXService = uxService;
|
||||||
uxService.Register(this);
|
uxService.Register(this);
|
||||||
InitializeAsync().Forget();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async UniTask InitializeAsync()
|
public override async UniTask InitializeAsync()
|
||||||
{
|
{
|
||||||
await _isBusy;
|
await _isBusy;
|
||||||
using var b = _isBusy.GetHandle();
|
using var b = _isBusy.GetHandle();
|
||||||
|
|
|
@ -33,14 +33,6 @@ namespace BITKit.UX
|
||||||
_windowEntryGroup.OnStateChanged += OnWindowEntry;
|
_windowEntryGroup.OnStateChanged += OnWindowEntry;
|
||||||
_ticker.Add(OnTick);
|
_ticker.Add(OnTick);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnWindowExit(IUXPanel obj)
|
|
||||||
{
|
|
||||||
BITAppForUnity.AllowCursor.RemoveElement(_windowEntryGroup);
|
|
||||||
if (obj.AllowInput is false)
|
|
||||||
BITInputSystem.AllowInput.RemoveDisableElements(_windowEntryGroup);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnWindowEntry(IUXPanel prev, IUXPanel next)
|
private void OnWindowEntry(IUXPanel prev, IUXPanel next)
|
||||||
{
|
{
|
||||||
BITAppForUnity.AllowCursor.SetElements(_windowEntryGroup, next is { AllowCursor: true });
|
BITAppForUnity.AllowCursor.SetElements(_windowEntryGroup, next is { AllowCursor: true });
|
||||||
|
|
|
@ -426,15 +426,6 @@ namespace BITKit
|
||||||
}
|
}
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
public static bool TryGetComponentsInParent<T>(this GameObject self, out T[] components)
|
|
||||||
{
|
|
||||||
return TryGetComponentsInParent(self.transform, out components);
|
|
||||||
}
|
|
||||||
public static bool TryGetComponentsInParent<T>(this Component self, out T[] components)
|
|
||||||
{
|
|
||||||
components = self.GetComponentsInParent<T>();
|
|
||||||
return components.IsValid();
|
|
||||||
}
|
|
||||||
public static bool TryGetComponentAny<T>(this Component self, out T component)
|
public static bool TryGetComponentAny<T>(this Component self, out T component)
|
||||||
{
|
{
|
||||||
component = self.GetComponentInChildren<T>(true);
|
component = self.GetComponentInChildren<T>(true);
|
||||||
|
@ -597,24 +588,60 @@ namespace BITKit
|
||||||
self.Add(clone);
|
self.Add(clone);
|
||||||
return clone;
|
return clone;
|
||||||
}
|
}
|
||||||
public static bool Entry(this VisualElement self, string name,bool visibleOnEmpty=false)
|
|
||||||
|
public static bool Navigate(this VisualElement self, string name)
|
||||||
{
|
{
|
||||||
var result=false;
|
while (true)
|
||||||
foreach (var x in self.Children())
|
|
||||||
{
|
{
|
||||||
if (string.Equals(x.name, name))
|
var result = false;
|
||||||
|
|
||||||
|
var split = name.Split("/");
|
||||||
|
if (split.Length > 1)
|
||||||
{
|
{
|
||||||
x.SetActive(true);
|
var root = self;
|
||||||
result = true;
|
var last = string.Empty;
|
||||||
|
foreach (var path in split)
|
||||||
|
{
|
||||||
|
var ve = root.Q(path);
|
||||||
|
if (ve is not null)
|
||||||
|
{
|
||||||
|
root = ve;
|
||||||
|
last = path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (root != self)
|
||||||
|
{
|
||||||
|
self = root.parent;
|
||||||
|
name = last;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
x.SetActive(false);
|
foreach (var x in self.Children())
|
||||||
|
{
|
||||||
|
if (string.Equals(x.name, name, StringComparison.CurrentCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
x.SetActive(true);
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
x.SetActive(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
self.SetActive(visibleOnEmpty || result);
|
|
||||||
return result;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static T Get<T>(this VisualElement self ,int index = 0) where T : VisualElement => self.Q<T>($"{typeof(T).Name}--{index}");
|
public static T Get<T>(this VisualElement self ,int index = 0) where T : VisualElement => self.Q<T>($"{typeof(T).Name}--{index}");
|
||||||
public static T Create<T>(this VisualElement self, string name = Constant.EmetyString) where T : VisualElement,new()
|
public static T Create<T>(this VisualElement self, string name = Constant.EmetyString) where T : VisualElement,new()
|
||||||
{
|
{
|
||||||
|
@ -649,10 +676,12 @@ namespace BITKit
|
||||||
public static void SetOpacity(this VisualElement self, float value) => self.style.opacity = new(value);
|
public static void SetOpacity(this VisualElement self, float value) => self.style.opacity = new(value);
|
||||||
public static void ScrollToBottom(this ScrollView self)
|
public static void ScrollToBottom(this ScrollView self)
|
||||||
{
|
{
|
||||||
self.verticalScroller.value =
|
self.schedule.Execute(() =>
|
||||||
self.verticalScroller.highValue > 0 ? self.verticalScroller.highValue : 0;
|
{
|
||||||
|
self.scrollOffset = new Vector2(0, float.MaxValue);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
public static async void ScrollToBottomAutomatic(this ScrollView self, float delay = 0.02f)
|
public static void ScrollToBottomAutomatic(this ScrollView self, float delay = 0.02f)
|
||||||
{
|
{
|
||||||
switch (true)
|
switch (true)
|
||||||
{
|
{
|
||||||
|
@ -661,7 +690,6 @@ namespace BITKit
|
||||||
case true when Math.Abs(self.verticalScroller.value - self.verticalScroller.highValue) < 0.01f:
|
case true when Math.Abs(self.verticalScroller.value - self.verticalScroller.highValue) < 0.01f:
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await Task.Delay(TimeSpan.FromSeconds(delay), BITApp.CancellationToken);
|
|
||||||
ScrollToBottom(self);
|
ScrollToBottom(self);
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException)
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace BITKit
|
||||||
|
{
|
||||||
|
|
||||||
|
public class GetWindowsWallPaper
|
||||||
|
{
|
||||||
|
[DllImport("user32.dll", SetLastError = true)]
|
||||||
|
static extern bool SystemParametersInfo(int uAction, int uParam, StringBuilder lpvParam, int fuWinIni);
|
||||||
|
|
||||||
|
const int SPI_GETDESKWALLPAPER = 0x0073;
|
||||||
|
const int MAX_PATH = 260;
|
||||||
|
|
||||||
|
public static string GetWallpaperPath()
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder(MAX_PATH);
|
||||||
|
if (SystemParametersInfo(SPI_GETDESKWALLPAPER, sb.Capacity, sb, 0))
|
||||||
|
{
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 45155c6ffea0e34428dd2cfabd1b7deb
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
|
@ -1,11 +1,11 @@
|
||||||
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" editor-extension-mode="False">
|
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" editor-extension-mode="False">
|
||||||
<Style src="project://database/Assets/BITKit/Unity/UX/Common/Common.uss?fileID=7433441132597879392&guid=a3a69d3518fd02b489e721f3c5b0b539&type=3#Common" />
|
<Style src="project://database/Assets/BITKit/Unity/UX/Common/Common.uss?fileID=7433441132597879392&guid=a3a69d3518fd02b489e721f3c5b0b539&type=3#Common" />
|
||||||
<Style src="project://database/Assets/BITKit/Unity/UX/BITQuest.uss?fileID=7433441132597879392&guid=5c2d746d52de8e340b788034994ee23e&type=3#BITQuest" />
|
<Style src="project://database/Assets/BITKit/Unity/UX/BITQuest.uss?fileID=7433441132597879392&guid=5c2d746d52de8e340b788034994ee23e&type=3#BITQuest" />
|
||||||
<Kamgam.UIToolkitBlurredBackground.BlurredBackground name="quest-element" Blur-Tint="#000000C8" class="quest" style="padding-top: 4px; padding-right: 8px; padding-bottom: 4px; padding-left: 8px; margin-top: 4px; margin-right: 8px; margin-bottom: 4px; margin-left: 8px;">
|
<ui:VisualElement name="quest-element" Blur-Tint="#000000C8" class="quest" style="padding-top: 4px; padding-right: 8px; padding-bottom: 4px; padding-left: 8px; margin-top: 4px; margin-right: 8px; margin-bottom: 4px; margin-left: 8px;">
|
||||||
<ui:VisualElement name="Header" class="flex-horizontal">
|
<ui:VisualElement name="Header" class="flex-horizontal">
|
||||||
<ui:VisualElement name="VisualElement--0" class="quest-icon game-icon" />
|
<ui:VisualElement name="VisualElement--0" class="quest-icon game-icon" />
|
||||||
<ui:Label text="NewQuest" display-tooltip-when-elided="true" name="Label--0" class="quest-title" />
|
<ui:Label text="NewQuest" display-tooltip-when-elided="true" name="Label--0" class="quest-title" />
|
||||||
</ui:VisualElement>
|
</ui:VisualElement>
|
||||||
<ui:Label text="Fnish This Quest" display-tooltip-when-elided="true" name="Label--1" class="quest-description" />
|
<ui:Label text="Fnish This Quest" display-tooltip-when-elided="true" name="Label--1" class="quest-description" />
|
||||||
</Kamgam.UIToolkitBlurredBackground.BlurredBackground>
|
</ui:VisualElement>
|
||||||
</ui:UXML>
|
</ui:UXML>
|
||||||
|
|
|
@ -7,6 +7,14 @@ ScrollView {
|
||||||
--unity-metrics-single_line-height: 500px;
|
--unity-metrics-single_line-height: 500px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ScrollView Scroller.unity-scroller{
|
||||||
|
width: 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScrollView Scroller.unity-scroller * {
|
||||||
|
width: 8;
|
||||||
|
}
|
||||||
|
|
||||||
TabBar Button:disabled {
|
TabBar Button:disabled {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ Slider.material {
|
||||||
}
|
}
|
||||||
|
|
||||||
.material Button {
|
.material Button {
|
||||||
background-color: rgba(26, 115, 232, 0.06);
|
background-color: rgba(26, 115, 232, 0.13);
|
||||||
border-left-width: 0;
|
border-left-width: 0;
|
||||||
border-right-width: 0;
|
border-right-width: 0;
|
||||||
border-top-width: 0;
|
border-top-width: 0;
|
||||||
|
@ -219,3 +219,23 @@ Slider.material {
|
||||||
min-width: 128px;
|
min-width: 128px;
|
||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.unity-base-field.variant-text #unity-text-input {
|
||||||
|
background-color: rgba(0, 0, 0, 0);
|
||||||
|
border-top-width: 0;
|
||||||
|
border-right-width: 0;
|
||||||
|
border-bottom-width: 0;
|
||||||
|
border-left-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.material TabBar.variable-square Button {
|
||||||
|
width: 64px;
|
||||||
|
height: 64px;
|
||||||
|
max-width: 64px;
|
||||||
|
max-height: 64px;
|
||||||
|
min-width: 64px;
|
||||||
|
border-top-left-radius: 10px;
|
||||||
|
border-top-right-radius: 10px;
|
||||||
|
border-bottom-right-radius: 10px;
|
||||||
|
border-bottom-left-radius: 10px;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue