This commit is contained in:
CortexCore 2024-11-03 16:38:17 +08:00
parent 056e2cada5
commit 4ba741408d
4682 changed files with 2343 additions and 5341 deletions

View File

@ -7,6 +7,8 @@ using Cysharp.Threading.Tasks;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
// ReSharper disable StringLiteralTypo
#if NET5_0_OR_GREATER
using Microsoft.Extensions.DependencyInjection;
@ -18,10 +20,9 @@ namespace BITKit
{
public override string Message => "Application Is Not Playing";
}
// ReSharper disable once InconsistentNaming
public class BITApp
{
public static int Count => _count++;
private static int _count;
public static async UniTask SwitchToMainThread()
{
#if UNITY_5_3_OR_NEWER
@ -168,7 +169,6 @@ namespace BITKit
"MySql",
};
}
#if NET5_0_OR_GREATER
/// <summary>
/// 依赖服务集合
/// </summary>
@ -176,13 +176,18 @@ namespace BITKit
/// <summary>
/// 依赖服务提供接口
/// </summary>
public static ServiceProvider ServiceProvider { get; internal set; }
public static ServiceProvider ServiceProvider { get; private set; }
public static ServiceProvider BuildServiceProvider()
{
var value = ServiceProvider = ServiceCollection.BuildServiceProvider();
OnServiceProviderBuild?.Invoke(value);
return value;
}
/// <summary>
/// 服务创建后的回调
/// </summary>
public static Action<ServiceProvider> OnServiceProviderBuilded;
#endif
public static Action<ServiceProvider> OnServiceProviderBuild;
/// <summary>
/// 主线程
/// </summary>
@ -254,7 +259,6 @@ namespace BITKit
private static DateTime InitialTime { get; set; }=DateTime.Now;
public static async UniTask Start(string appName = nameof(BITApp),AppSettings settings=default)
{
_count = 0;
Time.TimeAsDouble = 0;
Time.DeltaTime = 1 / 60f;

View File

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

View File

@ -2,7 +2,7 @@
{
public static class BITMapper
{
public static void Map<T>(T source, T target) where T : class
public static T Map<T>(object source, T target) where T : class
{
foreach (var info in source.GetType().GetProperties(ReflectionHelper.Flags))
{
@ -23,6 +23,7 @@
targetInfo?.SetValue(target, value);
}
}
return target;
}
}
}

View File

@ -137,50 +137,58 @@ namespace BITKit
}
public static void Write(BinaryWriter writer, object value)
{
if (value is not string && value is IList enumerable)
try
{
var pars = enumerable.Cast<object>().ToArray();
writer.Write(true);
writer.Write(value.GetType().GetElementType()!.FullName!);
writer.Write(pars.Length);
foreach (var obj in pars)
if (value is not string && value is IList enumerable)
{
WriteInterel(writer, obj);
}
}
else
{
writer.Write(false);
WriteInterel(writer,value);
}
return;
void WriteInterel(BinaryWriter writer, object value)
{
var typeName = value.GetType().FullName;
writer.Write(typeName!);
if (netReaders.TryGetValue(typeName, out var netReader))
{
netReader.WriteBinaryAsObject(writer,value);
}
else if (value is IBinarySerialize serialize)
{
serialize.Write(writer);
var pars = enumerable.Cast<object>().ToArray();
writer.Write(true);
writer.Write(value.GetType().GetElementType()!.FullName!);
writer.Write(pars.Length);
foreach (var obj in pars)
{
WriteInterel(writer, obj);
}
}
else
{
try
{
writer.Write(JsonConvert.SerializeObject(value));
}
catch (Exception)
{
BIT4Log.Warning<BITBinary>(typeName);
throw;
}
writer.Write(false);
WriteInterel(writer,value);
}
return;
void WriteInterel(BinaryWriter writer, object value)
{
var typeName = value.GetType().FullName;
writer.Write(typeName!);
if (netReaders.TryGetValue(typeName, out var netReader))
{
netReader.WriteBinaryAsObject(writer,value);
}
else if (value is IBinarySerialize serialize)
{
serialize.Write(writer);
}
else
{
try
{
writer.Write(JsonConvert.SerializeObject(value));
}
catch (Exception)
{
BIT4Log.Warning<BITBinary>(typeName);
throw;
}
}
}
}
catch (Exception e)
{
throw;
}
}
public static bool IsSupport(object obj) => IsSupport(obj.GetType().FullName);
public static bool IsSupport(Type type) => IsSupport(type.FullName);

View File

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

View File

@ -28,7 +28,7 @@ namespace BITKit.CommandPattern
void Release();
}
public sealed class CommandSequence:List<ICommand>,IBinarySerialize
public sealed class CommandSequence:List<ICommand>,Microsoft.SqlServer.Server.IBinarySerialize
{
public void Read(BinaryReader r)
{

View File

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

View File

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

View File

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

View File

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

View File

@ -3,5 +3,6 @@ namespace BITKit
public interface IDescription
{
public string Name { get; }
public string Description { get; }
}
}

View File

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

View File

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

View File

@ -54,79 +54,87 @@ namespace BITKit.Entities
public T[] QueryComponents<T>()
{
return _queryCache.GetOrAdd(typeof(T), type =>
{
return _entities.Values.Where(entity => entity.TryGetComponent(out T component)).ToArray();
}).Cast<T>().ToArray();
throw new NotImplementedException();
// return _queryCache.GetOrAdd(typeof(T), type =>
// {
// return _entities.Values.Where(entity => entity.TryGetComponent(out T component)).ToArray();
// }).Cast<T>().ToArray();
}
public (T, T1)[] QueryComponents<T, T1>()
{
List<(T, T1)> list = new();
foreach (var entity in _entities.Values)
{
if (entity.TryGetComponent(out T t) && entity.TryGetComponent(out T1 t1))
list.Add((t, t1));
}
return list.ToArray();
throw new NotImplementedException();
// List<(T, T1)> list = new();
// foreach (var entity in _entities.Values)
// {
// if (entity.TryGetComponent(out T t) && entity.TryGetComponent(out T1 t1))
// list.Add((t, t1));
// }
// return list.ToArray();
}
public (T, T1, T2)[] QueryComponents<T, T1, T2>()
{
List<(T, T1, T2)> list = new();
foreach (var entity in _entities.Values)
{
if (entity.TryGetComponent(out T t) && entity.TryGetComponent(out T1 t1) && entity.TryGetComponent(out T2 t2))
list.Add((t, t1, t2));
}
return list.ToArray();
throw new NotImplementedException();
// List<(T, T1, T2)> list = new();
// foreach (var entity in _entities.Values)
// {
// if (entity.TryGetComponent(out T t) && entity.TryGetComponent(out T1 t1) && entity.TryGetComponent(out T2 t2))
// list.Add((t, t1, t2));
// }
// return list.ToArray();
}
public (T, T1, T2, T3)[] QueryComponents<T, T1, T2, T3>()
{
List<(T, T1, T2, T3)> list = new();
foreach (var entity in _entities.Values)
{
if (entity.TryGetComponent(out T t) && entity.TryGetComponent(out T1 t1) && entity.TryGetComponent(out T2 t2) && entity.TryGetComponent(out T3 t3))
list.Add((t, t1, t2, t3));
}
return list.ToArray();
throw new NotImplementedException();
// List<(T, T1, T2, T3)> list = new();
// foreach (var entity in _entities.Values)
// {
// if (entity.TryGetComponent(out T t) && entity.TryGetComponent(out T1 t1) && entity.TryGetComponent(out T2 t2) && entity.TryGetComponent(out T3 t3))
// list.Add((t, t1, t2, t3));
// }
// return list.ToArray();
}
public (T, T1, T2, T3, T4)[] QueryComponents<T, T1, T2, T3, T4>()
{
List<(T, T1, T2, T3, T4)> list = new();
foreach (var entity in _entities.Values)
{
if (entity.TryGetComponent(out T t) && entity.TryGetComponent(out T1 t1) && entity.TryGetComponent(out T2 t2) && entity.TryGetComponent(out T3 t3) && entity.TryGetComponent(out T4 t4))
list.Add((t, t1, t2, t3, t4));
}
return list.ToArray();
throw new NotImplementedException();
// List<(T, T1, T2, T3, T4)> list = new();
// foreach (var entity in _entities.Values)
// {
// if (entity.TryGetComponent(out T t) && entity.TryGetComponent(out T1 t1) && entity.TryGetComponent(out T2 t2) && entity.TryGetComponent(out T3 t3) && entity.TryGetComponent(out T4 t4))
// list.Add((t, t1, t2, t3, t4));
// }
// return list.ToArray();
}
public (T, T1, T2, T3, T4, T5)[] QueryComponents<T, T1, T2, T3, T4, T5>()
{
List<(T, T1, T2, T3, T4, T5)> list = new();
foreach (var entity in _entities.Values)
{
if (entity.TryGetComponent(out T t) && entity.TryGetComponent(out T1 t1) && entity.TryGetComponent(out T2 t2) && entity.TryGetComponent(out T3 t3) && entity.TryGetComponent(out T4 t4) && entity.TryGetComponent(out T5 t5))
list.Add((t, t1, t2, t3, t4, t5));
}
return list.ToArray();
throw new NotImplementedException();
// List<(T, T1, T2, T3, T4, T5)> list = new();
// foreach (var entity in _entities.Values)
// {
// if (entity.TryGetComponent(out T t) && entity.TryGetComponent(out T1 t1) && entity.TryGetComponent(out T2 t2) && entity.TryGetComponent(out T3 t3) && entity.TryGetComponent(out T4 t4) && entity.TryGetComponent(out T5 t5))
// list.Add((t, t1, t2, t3, t4, t5));
// }
// return list.ToArray();
}
public (T, T1, T2, T3, T4, T5, T6)[] QueryComponents<T, T1, T2, T3, T4, T5, T6>()
{
List<(T, T1, T2, T3, T4, T5, T6)> list = new();
foreach (var entity in _entities.Values)
{
if (entity.TryGetComponent(out T t) && entity.TryGetComponent(out T1 t1) && entity.TryGetComponent(out T2 t2) && entity.TryGetComponent(out T3 t3) && entity.TryGetComponent(out T4 t4) && entity.TryGetComponent(out T5 t5) && entity.TryGetComponent(out T6 t6))
list.Add((t, t1, t2, t3, t4, t5, t6));
}
return list.ToArray();
throw new NotImplementedException();
// List<(T, T1, T2, T3, T4, T5, T6)> list = new();
// foreach (var entity in _entities.Values)
// {
// if (entity.TryGetComponent(out T t) && entity.TryGetComponent(out T1 t1) && entity.TryGetComponent(out T2 t2) && entity.TryGetComponent(out T3 t3) && entity.TryGetComponent(out T4 t4) && entity.TryGetComponent(out T5 t5) && entity.TryGetComponent(out T6 t6))
// list.Add((t, t1, t2, t3, t4, t5, t6));
// }
// return list.ToArray();
}
public ValueTuple<T, T1, T2, T3, T4, T5, T6, TRest>[] QueryComponents<T, T1, T2, T3, T4, T5, T6, TRest>() where TRest : struct
{
throw new NotImplementedException();
// throw new NotImplementedException();
}
}
}

View File

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Microsoft.Extensions.DependencyInjection;
@ -7,9 +8,25 @@ namespace BITKit.Entities
{
public class Entity : IEntity, IDisposable
{
private class EntityServiceProvider : IServiceProvider
{
public ServiceProvider ServiceProvider;
public readonly List<Object> Services = new();
public object GetService(Type serviceType)
{
var value = ServiceProvider.GetService(serviceType);
if (value != null)
{
Services.TryAdd(value);
}
return value;
}
}
public Entity()
{
RegisterComponent<IEntity>(this);
ServiceCollection.AddSingleton<IEntity>(this);
}
public void WaitForInitializationComplete()
{
@ -19,51 +36,26 @@ namespace BITKit.Entities
public CancellationToken CancellationToken => _cancellationTokenSource.Token;
private readonly CancellationTokenSource _cancellationTokenSource = new();
public bool TryGetComponent<T>(out T component)
public IServiceProvider ServiceProvider
{
var value = ServiceProvider.GetService<T>();
if (value != null)
get
{
component = value;
return true;
if (_serviceProvider is not null)
{
return _serviceProvider;
}
var value = new EntityServiceProvider()
{
ServiceProvider = ServiceCollection.BuildServiceProvider()
};
_serviceProvider = value;
return _serviceProvider;
}
component = default!;
return false;
}
public bool TryGetComponent(Type type, out IEntityComponent component)
{
var value = ServiceProvider.GetService(type);
if (value != null)
{
component = (IEntityComponent)value;
return true;
}
component = default!;
return false;
}
public IEntityComponent[] Components => ServiceCollection.OfType<IEntityComponent>().ToArray();
public bool RegisterComponent<T>(T component)
{
_services.Add(component);
ServiceCollection.AddSingleton(typeof(T), component);
return true;
}
public IServiceProvider ServiceProvider => _serviceProvider ??= ServiceCollection.BuildServiceProvider();
public IServiceCollection ServiceCollection { get; } = new ServiceCollection();
private IServiceProvider _serviceProvider;
private readonly CacheList<object> _services = new();
public object[] GetServices()
{
return _services.ToArray();
}
private EntityServiceProvider _serviceProvider;
public object[] GetServices()=> _serviceProvider.Services.ToArray();
public void Inject(object obj)
{
foreach (var fieldInfo in obj.GetType().GetFields(ReflectionHelper.Flags))
@ -78,14 +70,10 @@ namespace BITKit.Entities
public void Dispose()
{
_cancellationTokenSource.Cancel();
_cancellationTokenSource.Dispose();
foreach (var service in _services)
_serviceProvider.ServiceProvider.Dispose();
foreach (var x in GetServices().OfType<IDisposable>())
{
if (service is IDisposable disposable)
{
disposable.Dispose();
}
x.Dispose();
}
}
}

View File

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

View File

@ -1,6 +1,7 @@
using System.Threading;
using System;
using System.ComponentModel.Design;
using Microsoft.Extensions.DependencyInjection;
#if NET5_0_OR_GREATER
using Microsoft.Extensions.DependencyInjection;
#endif
@ -11,44 +12,14 @@ namespace BITKit.Entities
/// </summary>
public interface IEntity
{
/// <summary>
/// 等待初始化完成,通常用于其他系统需要等待实体初始化完成
/// </summary>
void WaitForInitializationComplete();
int Id { get; }
CancellationToken CancellationToken { get; }
bool TryGetComponent<T>(out T component);
bool TryGetComponent(Type type, out IEntityComponent component);
IEntityComponent[] Components { get; }
bool RegisterComponent<T>(T component);
IServiceProvider ServiceProvider { get; }
#if NET5_0_OR_GREATER
IServiceCollection ServiceCollection { get; }
object[] GetServices();
#endif
void Inject(object obj);
}
/// <summary>
/// 基本实体组件
/// </summary>
public interface IEntityComponent
{
IEntity Entity { get; set; }
#if NET5_0_OR_GREATER
void BuildService(IServiceCollection serviceCollection);
#endif
}
public interface IEntityBehavior:IEntityComponent
{
void Initialize(IEntity _entity);
void OnAwake();
void OnStart();
void OnUpdate(float deltaTime);
void OnFixedUpdate(float deltaTime);
void OnLateUpdate(float deltaTime);
void OnDestroyComponent();
}
/// <summary>
/// 基本实体服务
/// </summary>
public interface IEntitiesService

View File

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

View File

@ -8,7 +8,8 @@ namespace BITKit
{
public static IEnumerable<Func<T>> CastAsFunc<T>(this Func<T> self)
{
return self is null ? Array.Empty<Func<T>>() : self?.GetInvocationList().Cast<Func<T>>();
var value = self;
return value is null? Array.Empty<Func<T>>() : self?.GetInvocationList().Cast<Func<T>>();
}
public static IEnumerable<Func<T0, T1>> CastAsFunc<T0, T1>(this Func<T0, T1> self)
{

View File

@ -1,4 +1,5 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
@ -186,6 +187,10 @@ namespace BITKit
self.Add(key, value);
}
}
public static TValue Get<TKey,TValue>(this IDictionary<Type,TValue> self)
{
return self[typeof(TKey)];
}
public static TValue Get<TKey, TValue>(this IDictionary<TKey, TValue> self, TKey key) where TValue : new()
{
lock (self)

View File

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

View File

@ -31,7 +31,7 @@ namespace BITKit.StateMachine
void OnStateExit(IState old, IState newState);
}
public interface IStateMachine<T>
public interface IStateMachine<T> where T:IState
{
bool Enabled { get; set; }
T CurrentState { get; set; }
@ -53,7 +53,7 @@ namespace BITKit.StateMachine
public static class StateMachineUtils
{
public static void Register<T>(IStateMachine<T> stateMachine, T newState) where T : IState
public static void Register<T>(this IStateMachine<T> stateMachine, T newState) where T : IState
{
if (stateMachine.StateDictionary.ContainsKey(newState.GetType()))
{

View File

@ -1,155 +1,161 @@
using System;
using System.IO;
using System.Collections.Generic;
namespace BITKit
{
#region
public enum ItemQuality
{
/// <summary>
/// 常见的
/// </summary>
Common,
/// <summary>
/// 罕见的
/// </summary>
Uncommon,
/// <summary>
/// 稀有的
/// </summary>
Rare,
/// <summary>
/// 史诗的
/// </summary>
Epic,
/// <summary>
/// 传奇的
/// </summary>
Legendary,
/// <summary>
/// 神话的
/// </summary>
Mythical,
/// <summary>
/// 开发者
/// </summary>
Develop,
}
#endregion
#region
/// <summary>
/// 物品属性
/// </summary>
public interface IScriptableItemProperty
{
}
/// <summary>
/// 基础物品
/// </summary>
public interface IBasicItem :IPropertable,ICloneable
public interface IScriptableItem
{
/// <summary>
/// 唯一Id
/// </summary>
int Id { get; }
/// <summary>
/// 物品名,一般用于查找物品的主键
/// </summary>
string Name { get; }
// /// <summary>
// /// 可寻址路径,该路径用于查找物品
// /// </summary>
// string AddressablePath { get; }
/// <summary>
/// 物品描述
/// </summary>
string Description { get; }
/// <summary>
/// 最大堆叠数量
/// </summary>
public int MaxStack { get; }
/// <summary>
/// 物品品质
/// </summary>
ItemQuality Quality { get; }
bool CopyItemsFrom(IBasicItem item);
/// <summary>
/// 属性
/// </summary>
IReadOnlyDictionary<Type, IScriptableItemProperty> Properties { get; }
/// <summary>
/// 价值
/// </summary>
/// <returns></returns>
int Value=>10;
int Value => 10;
}
/// <summary>
/// 可配置化物品,通常用于配置
/// </summary>
public interface IAssetableItem: IBasicItem
public interface IRuntimeItem : ICloneable
{
/// <summary>
/// 运行时Id
/// </summary>
public int Id { get; }
/// <summary>
/// 配置Id
/// </summary>
public int ScriptableId { get; }
/// <summary>
/// 数量
/// </summary>
public int Amount { get; }
/// <summary>
/// 运行时属性
/// </summary>
IDictionary<Type, IScriptableItemProperty> RuntimeProperties { get; }
/// <summary>
/// 当运行时属性改变时
/// </summary>
// ReSharper disable once EventNeverInvoked.Global
event Action<IRuntimeItem> OnRuntimePropertiesChanged;
}
#endregion
#region
/// <summary>
/// 被托管的物品
/// </summary>
[Serializable]
public class ManagedItem : IBasicItem
public record RuntimeItem : IRuntimeItem
{
#region
public int Id;
public string Name;
public string AddressablePath { get; set; }
public string Description;
public ItemQuality Quality;
public int Value { get; set; }
/// <summary>
/// 本地属性
/// </summary>
private Property property = new();
#endregion
#region
int IBasicItem.Id => Id;
string IBasicItem.Name => Name;
string IBasicItem.Description => Description;
ItemQuality IBasicItem.Quality => Quality;
#endregion
#region
public bool Contains<T>() => property.Contains<T>();
public int Id { get; set; } = new Random().Next();
public int ScriptableId { get; set; }
public int Amount { get; set; }
public T GetOrAddProperty<T>(Func<T> addFactory) => property.GetOrAddProperty<T>(addFactory);
public IDictionary<Type, IScriptableItemProperty> RuntimeProperties { get; set; } =
new Dictionary<Type, IScriptableItemProperty>();
public T GetOrCreateProperty<T>() => property.GetOrCreateProperty<T>();
public event Action<IRuntimeItem> OnRuntimePropertiesChanged;
public object[] GetProperties() => property.GetProperties();
public bool TryGetProperty<T>(out T value) => property.TryGetProperty<T>(out value);
public bool TryRemoveProperty<T>() => property.TryRemoveProperty<T>();
public bool TrySetProperty<T>(T value) => property.TrySetProperty(value);
public void Read(BinaryReader r)
object ICloneable.Clone()
{
throw new NotImplementedException();
}
public void Write(BinaryWriter w)
{
throw new NotImplementedException();
}
public bool CopyItemsFrom(IBasicItem item)
{
Value = item.Value;
Id=item.Id;
Name = item.Name;
//AddressablePath = item.AddressablePath;
Description = item.Description;
Quality=item.Quality;
CopyPropertiesFrom(item);
return true;
}
public bool ClearProperties()=>property.ClearProperties();
public bool CopyPropertiesFrom(IPropertable propertable)
{
return property.CopyPropertiesFrom(propertable);
}
#endregion
public object Clone()
{
var item = MemberwiseClone() as ManagedItem;
item!.Id = Id;
return item;
return new RuntimeItem
{
Id = new Random().Next(),
ScriptableId = ScriptableId,
Amount = Amount,
RuntimeProperties = new Dictionary<Type, IScriptableItemProperty>(RuntimeProperties),
OnRuntimePropertiesChanged = null,
};
}
}
#endregion
}

View File

@ -1,4 +1,5 @@
using System;
using Microsoft.SqlServer.Server;
namespace BITKit
{
@ -7,89 +8,63 @@ namespace BITKit
/// 支持属性
/// 支持回调
/// </summary>
public interface IBasicItemContainer
public interface IRuntimeItemContainer:IBinarySerialize
{
/// <summary>
/// 物品容器的唯一Id
/// </summary>
int Id { get; }
/// <summary>
/// 尝试获取指定Item
/// </summary>
bool TryGetItem(Func<IBasicItem, bool> func, out IBasicItem item);
/// <summary>
/// 获取所有Item的只读副本
/// </summary>
IBasicItem[] GetItems();
IRuntimeItem[] GetItems();
/// <summary>
/// 添加物品的接口
/// </summary>
bool Add(IBasicItem item);
/// <summary>
/// 通过Item本身进行移除
/// </summary>
bool Remove(IBasicItem item);
bool Add(IRuntimeItem item);
/// <summary>
/// 通过Id移除物品(推荐)
/// </summary>
bool Remove(int id);
/// <summary>
/// 通过工厂方法移除物品
/// </summary>
bool Remove(Func<IBasicItem, bool> removeFactory);
/// <summary>
/// 通过通过Id丢下物品
/// </summary>
bool Drop(int Id);
bool DropOrSpawn(IBasicItem item);
bool Drop(int id);
/// <summary>
/// 注册添加物品的工厂方法,
/// </summary>
event Func<IBasicItem, bool> AddFactory;
event Func<IRuntimeItem, bool> AddFactory;
/// <summary>
/// 注册移除物品的工厂方法
/// </summary>
event Func<IBasicItem, bool> RemoveFactory;
event Func<IRuntimeItem, bool> RemoveFactory;
/// <summary>
/// 注册丢下物品的工厂方法
/// </summary>
event Func<IBasicItem, bool> DropFactory;
event Func<IRuntimeItem, bool> DropFactory;
/// <summary>
/// 已添加Item的回调
/// </summary>
event Action<IBasicItem> OnAdd;
event Action<IRuntimeItem> OnAdd;
/// <summary>
/// 已移除Item的回调
/// </summary>
event Action<IBasicItem> OnRemove;
event Action<IRuntimeItem> OnRemove;
/// <summary>
/// 已设置Item的回调
/// </summary>
event Action<IBasicItem> OnSet;
event Action<IRuntimeItem> OnSet;
/// <summary>
/// 已丢下Item的回调
/// </summary>
event Action<IBasicItem> OnDrop;
event Action<IRuntimeItem> OnDrop;
/// <summary>
/// 已重构Items的回调
/// </summary>
event Action<IBasicItemContainer> OnRebuild;
event Action<IRuntimeItemContainer> OnRebuild;
/// <summary>
/// 是否已完成物品交换,例如false就是开始交换物品true就是已完成交换物品,可以处理物品了
/// </summary>
event Action<bool> OnRelease;
/// <summary>
/// 添加挂起句柄
/// </summary>
/// <param name="id"></param>
void AddHandle(int id);
/// <summary>
/// 移除挂起句柄
/// </summary>
/// <param name="id"></param>
void RemoveHandle(int id);
}
}

View File

@ -1,13 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
namespace BITKit
{
public interface IWorldItemObject
{
public IBasicItem Item { get; set; }
public event Action<IBasicItem> OnSetItem;
}
}

View File

@ -14,6 +14,7 @@ using System.Numerics;
using System.Reflection;
using System.Text;
using BITKit.Net.Examples;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Unity.Mathematics;
@ -21,6 +22,26 @@ namespace BITKit.Net
{
public class KcpNetClient:INetClient,INetProvider
{
private readonly ILogger<KcpNetClient> _logger;
public KcpNetClient(ILogger<KcpNetClient> logger)
{
_logger = logger;
_client = new KcpClient(
OnConnectedInternal,
OnData,
OnDisconnectInternal,
OnError,
KCPNet.Config
);
_timer.Elapsed += Tick;
_logger.LogInformation("已创建KCP客户端");
AddCommandListener<NetClientAllocateIdCommand>(x =>
{
Id = x.Id;
});
_isConnected.AddListener(ConnectionCallback);
}
public event Action OnStartConnect;
public event Action OnConnected;
public event Action OnDisconnected;
@ -29,14 +50,14 @@ namespace BITKit.Net
public bool IsConnecting { get; private set; }
public double RpcTimeOut { get; set; } = 5;
public bool AutoReconnect { get; set; } = true;
public float2 Traffic { get; set; }
public float2 Traffic { get; private set; }
public bool ManualTick { get; set; }
private readonly IntervalUpdate _reconnectInterval = new(1);
public int Ping { get; private set; }
public int Id { get; private set; } = -1;
private readonly KcpClient client;
private readonly KcpClient _client;
private readonly ConcurrentQueue<byte[]> _commandQueue = new();
@ -50,7 +71,7 @@ namespace BITKit.Net
private readonly GenericEvent _events = new();
private readonly ValidHandle _isConnected = new();
private bool _userConnected;
private int _index = int.MinValue;
private readonly ConcurrentDictionary<int, object> _p2p = new();
private readonly ConcurrentDictionary<string,Func<object,UniTask<object>>> _rpc = new();
@ -64,23 +85,7 @@ namespace BITKit.Net
private ushort _connectedPort = 27014;
private readonly byte[] _heartBeat = new byte[] { (byte)NetCommandType.Heartbeat };
public KcpNetClient()
{
client = new KcpClient(
OnConnectedInternal,
OnData,
OnDisconnectInternal,
OnError,
KCPNet.Config
);
_timer.Elapsed += Tick;
BIT4Log.Log<KcpNetClient>("已创建KCP客户端");
AddCommandListener<NetClientAllocateIdCommand>(x =>
{
Id = x.Id;
});
_isConnected.AddListener(ConnectionCallback);
}
private async void ConnectionCallback(bool x)
{
@ -88,12 +93,12 @@ namespace BITKit.Net
if (x)
{
OnConnected?.Invoke();
BIT4Log.Log<KcpNetClient>("连接成功");
_logger.LogInformation("连接成功");
}
else
{
OnDisconnected?.Invoke();
BIT4Log.Log<KcpNetClient>("连接已断开");
_logger.LogInformation("连接已断开");
}
}
@ -104,9 +109,14 @@ namespace BITKit.Net
}
public async void Disconnect()
{
_userConnected = false;
DisconnectInternal();
}
private async void DisconnectInternal()
{
IsConnecting = false;
client.Disconnect();
_client.Disconnect();
_isConnected.RemoveElement(this);
_timer.Stop();
try
@ -117,6 +127,7 @@ namespace BITKit.Net
catch (OperationCanceledException){}
}
private string _lastHostName;
public async UniTask<bool> Connect(string address = "127.0.0.1", ushort port = 27014)
{
if (IsConnecting)
@ -124,7 +135,7 @@ namespace BITKit.Net
BIT4Log.Warning<KcpNetClient>("正在连接中");
return false;
}
_userConnected = true;
//如果address是域名,解析为Ip
if (address.Contains("."))
{
@ -132,7 +143,11 @@ namespace BITKit.Net
if (ip.Length > 0)
{
address = ip[0].ToString();
BIT4Log.Log<KcpNetClient>($"解析域名:{address}");
if (_lastHostName != address)
{
_logger.LogInformation($"解析域名:{address},IP:{ip}");
_lastHostName = address;
}
}
}
@ -143,7 +158,7 @@ namespace BITKit.Net
IsConnecting = true;
if (client.connected) return false;
if (_client.connected) return false;
await BITApp.SwitchToMainThread();
OnStartConnect?.Invoke();
await UniTask.SwitchToThreadPool();
@ -151,7 +166,7 @@ namespace BITKit.Net
{
_lastHeartbeat = DateTime.Now;
client.Connect(address, port);
_client.Connect(address, port);
_timer.Start();
_interval = TimeSpan.FromMilliseconds(_timer.Interval);
@ -163,13 +178,13 @@ namespace BITKit.Net
for (var i = 0; i < 5; i++)
{
client.Send(new[] { (byte)NetCommandType.Heartbeat }, KcpChannel.Reliable);
_client.Send(new[] { (byte)NetCommandType.Heartbeat }, KcpChannel.Reliable);
Traffic += new float2(1, 0);
client.Tick();
_client.Tick();
await Task.Delay(100);
}
if (client.connected)
if (_client.connected)
{
SendServerMessage(Environment.MachineName);
@ -177,11 +192,11 @@ namespace BITKit.Net
_connectedAddress = address;
_connectedPort = port;
return client.connected;
return _client.connected;
}
OnConnectedFailed?.Invoke();
Disconnect();
DisconnectInternal();
IsConnecting = false;
return false;
@ -220,7 +235,7 @@ namespace BITKit.Net
switch (type)
{
case NetCommandType.Message:
BIT4Log.Log<KcpNetClient>($"已收到消息:{reader.ReadString()}");
_logger.LogInformation($"已收到消息:{reader.ReadString()}");
break;
case NetCommandType.AllClientCommand:
case NetCommandType.Command:
@ -424,7 +439,7 @@ namespace BITKit.Net
if (eventDelegate is null)
{
BIT4Log.Warning<KcpNetClient>($"未找到对应的事件:{rpcName}");
//BIT4Log.Warning<KcpNetClient>($"未找到对应的事件:{rpcName}");
}
else
{
@ -443,9 +458,9 @@ namespace BITKit.Net
}
break;
default:
BIT4Log.Log<KcpNetClient>($"未知消息类型:{type},字节:{(byte)type}");
_logger.LogInformation($"未知消息类型:{type},字节:{(byte)type}");
if (bytes.Array != null)
BIT4Log.Log<KcpNetClient>(
_logger.LogInformation(
$"已收到:({Id}, {BitConverter.ToString(bytes.Array, bytes.Offset, bytes.Count)} @ {channel})");
break;
}
@ -456,17 +471,17 @@ namespace BITKit.Net
// if (BITApp.SynchronizationContext is not null)
// await UniTask.SwitchToSynchronizationContext(BITApp.SynchronizationContext);
// OnConnected?.Invoke();
// BIT4Log.Log<KcpNetClient>("已连接");
// _logger.LogInformation("已连接");
}
private async void OnDisconnectInternal()
{
//BIT4Log.Log<KcpNetClient>("连接被断开");
Disconnect();
// _logger.LogInformation("连接被断开");
DisconnectInternal();
}
private void OnError(ErrorCode errorCode, string message)
{
BIT4Log.Log<KcpNetClient>($"{client.remoteEndPoint}异常:{errorCode},{message}");
_logger.LogInformation($"{_client.remoteEndPoint}异常:{errorCode},{message}");
}
public void ServerCommand<T>(T command = default)
@ -500,6 +515,10 @@ namespace BITKit.Net
public async UniTask<T> GetFromServer<T>(string path = default,params object[] pars)
{
if (IsConnected is false)
{
throw new NetOfflineException();
}
//await UniTask.SwitchToThreadPool();
var id = _index++;
var ms = new MemoryStream();
@ -528,6 +547,10 @@ namespace BITKit.Net
while (true)
{
if (IsConnected is false)
{
throw new NetOfflineException();
}
if ((_now - startTime).TotalSeconds > RpcTimeOut)
{
await BITApp.SwitchToMainThread();
@ -573,24 +596,25 @@ namespace BITKit.Net
foreach (var methodInfo in rpcHandle.GetType().GetMethods())
{
var att = methodInfo.GetCustomAttribute<NetRpcAttribute>();
if(att is null)continue;
if (att is null) continue;
_rpcMethods.AddOrUpdate(methodInfo.Name, methodInfo, (s, info) => methodInfo);
_rpcHandles.AddOrUpdate(methodInfo.Name, rpcHandle, (s, o) => rpcHandle);
reportBuilder.AppendLine($"Add [{methodInfo.Name}] as MethodInfo");
}
foreach (var eventInfo in rpcHandle.GetType().GetEvents())
{
var att = eventInfo.GetCustomAttribute<NetRpcAttribute>();
if(att is null)continue;
if (att is null) continue;
_rpcEvents.TryAdd(eventInfo.Name, eventInfo);
_rpcHandles.TryAdd(eventInfo.Name, rpcHandle);
reportBuilder.AppendLine($"Add [{eventInfo.Name}] as EventInfo");
}
BIT4Log.Log<KcpNetClient>(reportBuilder);
_logger.LogInformation(reportBuilder.ToString());
}
public void AddCommandListener<T>(Action<T> handle)
@ -621,6 +645,10 @@ namespace BITKit.Net
public void SendRT(string rpcName, params object[] pars)
{
if (IsConnected is false)
{
throw new NetOfflineException();
}
using var ms = new MemoryStream();
using var writer = new BinaryWriter(ms);
writer.Write((byte)NetCommandType.GetFromServer);
@ -650,36 +678,36 @@ namespace BITKit.Net
.Write(message)
.Build();
Traffic+=new float2(bytes.Length,0);
client.Send(bytes, KcpChannel.Reliable);
_client.Send(bytes, KcpChannel.Reliable);
}
#if UNITY_EDITOR
private readonly IntervalUpdate _pingInterval = new(1);
#endif
#endif
public void Tick()
{
_now = DateTime.Now;
if(_userConnected is false)return;
try
{
_now = DateTime.UtcNow;
if (client.connected)
if (_client.connected)
{
if (DateTime.Now - _lastHeartbeat > TimeSpan.FromSeconds(5))
{
BIT4Log.Warning<KcpNetClient>("心跳超时,自动断开");
Disconnect();
DisconnectInternal();
_commandQueue.Clear();
return;
}
while (_commandQueue.TryDequeue(out var bytes))
{
Traffic += new float2(bytes.Length, 0);
client.Send(bytes, KcpChannel.Reliable);
_client.Send(bytes, KcpChannel.Reliable);
}
Traffic+=new float2(1,0);
client.Send(_heartBeat, KcpChannel.Unreliable);
_client.Send(_heartBeat, KcpChannel.Unreliable);
}
else
{
@ -696,16 +724,7 @@ namespace BITKit.Net
//BIT4Log.Warning<KcpNetClient>("连接已断开,清空指令队列");
}
}
#if UNITY_EDITOR
if (_pingInterval.AllowUpdate)
{
_lastPingTime = DateTime.Now;
client.Send(new[] { (byte)NetCommandType.Ping }, KcpChannel.Reliable);
}
#endif
client.Tick();
_client.Tick();
}
catch (Exception e)
{
@ -718,7 +737,7 @@ namespace BITKit.Net
{
// send client to server
Traffic+=new float2(2,0);
client.Send(new byte[]{0x01, 0x02}, KcpChannel.Reliable);
_client.Send(new byte[]{0x01, 0x02}, KcpChannel.Reliable);
}
}
}

View File

@ -101,7 +101,7 @@ namespace BITKit.Net
BIT4Log.Log<KCPNetServer>($"{Name}:链接{id}超时,已断开");
}
if (server.IsActive() is false || ManualTick) return;
if (server.IsActive() is false) return;
server.Tick();
@ -150,9 +150,11 @@ namespace BITKit.Net
_timer.Interval = 1000f / TickRate;
_interval = TimeSpan.FromSeconds(1.0 / TickRate);
}
OnStartServer?.Invoke();
server.Start(port);
_timer.Start();
if (ManualTick is false)
_timer.Start();
_isStarted = true;
BIT4Log.Log<KCPNetServer>($"已启动KCP服务器:{port}");
}
@ -551,14 +553,14 @@ namespace BITKit.Net
{
foreach (var methodInfo in rpcHandle.GetType().GetMethods())
{
var att = methodInfo.GetCustomAttribute<NetRpcAttribute>();
var att = methodInfo.GetCustomAttribute<NetRpcAttribute>(true);
if(att is null)continue;
_rpcMethods.TryAdd(methodInfo.Name, methodInfo);
_rpcHandles.TryAdd(methodInfo.Name, rpcHandle);
}
foreach (var eventInfo in rpcHandle.GetType().GetEvents())
{
var att = eventInfo.GetCustomAttribute<NetRpcAttribute>();
var att = eventInfo.GetCustomAttribute<NetRpcAttribute>(true);
if(att is null)continue;
_rpcEvents.TryAdd(eventInfo.Name, eventInfo);

View File

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

View File

@ -147,6 +147,21 @@ namespace BITKit
}
}
public static IEnumerable<T> SelectManyPro<T>(this IEnumerable<T> self, Func<T, IEnumerable<T>> factory)
{
return Get(self);
IEnumerable<T> Get(IEnumerable<T> list)
{
var newList = new List<T>();
foreach (var x in list)
{
newList.Add(x);
newList.AddRange(Get(factory.Invoke(x)));
}
return newList.Distinct();
}
}
/// <summary>
/// 获取集合中所有的组合,每个组合中的元素个数为输入集合的元素个数,每个元素只出现一次
/// </summary>

View File

@ -126,7 +126,7 @@ namespace BITKit.Mod
}
}
public class ModService
public partial class ModService
{
public static async UniTask<ModPackage[]> SearchPackages()
{

View File

@ -0,0 +1,26 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Cysharp.Threading.Tasks;
namespace BITKit.Mod
{
public partial class ModService
{
public static Func<string, UniTask<object>> LoadAssetAsyncFactory;
public static async UniTask<T> LoadAsset<T>(string location) where T : class
{
foreach (var func in LoadAssetAsyncFactory.CastAsFunc())
{
var value = await func.Invoke(location);
if (value is T value1)
{
return value1;
}
}
throw new Exception($"Asset not found: {location}");
}
}
}

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: e0adbb35ce4784342a0ed37ac4a56200
guid: c63d2ab8d0ff2304e980bb1e0585c903
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@ -1,5 +1,7 @@
using System;
using System.IO;
using System.Net.Http;
using Microsoft.SqlServer.Server;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
@ -7,84 +9,103 @@ using Newtonsoft.Json.Linq;
namespace BITKit
// ReSharper restore CheckNamespace
{
public record ContextModel
public record ContextModel:IBinarySerialize
{
public static ContextModel Get(object data)
public static ContextModel Get(object data)
{
return new ContextModel()
{
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)
{
BIT4Log.Warning(json);
throw;
}
}
public static implicit operator string(ContextModel self)
{
return self.ToString();
}
#if NET5_0_OR_GREATER
public static implicit operator HttpContent(ContextModel self)
{
return new StringContent(self, System.Text.Encoding.UTF8, "application/json");
}
#endif
StatusCode = 200,
Message = "success",
Data = data
};
}
public override string ToString()
public static ContextModel Error(string message)
{
return new ContextModel()
{
return JsonConvert.SerializeObject(this);
}
StatusCode = 500,
Message = message,
Data = false
};
}
[JsonProperty("status_code")]
public int StatusCode=200;
[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)
public static ContextModel GetFromJson(string json)
{
try
{
switch (Data)
{
case T t:
value = t;
return true;
case JToken jToken:
value = jToken.ToObject<T>();
return true;
default:
value = default;
return false;
}
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)
{
BIT4Log.Warning(json);
throw;
}
}
public static implicit operator string(ContextModel self)
{
return self.ToString();
}
#if NET5_0_OR_GREATER
public static implicit operator HttpContent(ContextModel self)
{
return new StringContent(self, System.Text.Encoding.UTF8, "application/json");
}
#endif
public override string ToString()
{
return JsonConvert.SerializeObject(this);
}
[JsonProperty("status_code")] public int StatusCode = 200;
[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;
}
}
public void Read(BinaryReader r)
{
StatusCode = r.ReadInt32();
Message = r.ReadString();
Data = r.ReadBoolean() ? BITBinary.Read(r) : null;
}
public void Write(BinaryWriter w)
{
w.Write(StatusCode);
w.Write(Message);
w.Write(Data is not null);
if (Data is not null)
{
BITBinary.Write(w, Data);
}
}
}
}

24
Src/Core/Net/Exception.cs Normal file
View File

@ -0,0 +1,24 @@
namespace BITKit
{
public class NetOfflineException : System.Exception
{
public NetOfflineException() : base("Client is not connected") { }
}
public class NetAuthorizeException : System.Exception
{
public NetAuthorizeException() : base("Client is not authorized") { }
}
public abstract class NetAuthorityException : System.Exception
{
protected NetAuthorityException(string message =null) : base(string.IsNullOrEmpty(message)?"Authority is not valid":message) { }
}
public class NetClientOnlyException : NetAuthorityException
{
public NetClientOnlyException() : base("This method is only available on client") { }
}
public class NetServerOnlyException : NetAuthorityException
{
public NetServerOnlyException() : base("This method is only available on server") { }
}
}

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 618a48f7c780dd148ae1fa0fba95b583
guid: d38fad9bff7582b4b8287df7c47a47b7
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@ -18,7 +18,14 @@ namespace BITKit
[AttributeUsage(AttributeTargets.Method|AttributeTargets.Event)]
public sealed class NetRpcAttribute : Attribute
{
public readonly bool AddTypeNamePrefix;
public NetRpcAttribute()
{
}
public NetRpcAttribute(bool addTypeNamePrefix)
{
AddTypeNamePrefix = addTypeNamePrefix;
}
}
/// <summary>
/// 帮助类
@ -84,7 +91,6 @@ namespace BITKit
/// </summary>
public interface INetProvider
{
/// <summary>
/// 向服务端发送指令
/// </summary>
@ -192,6 +198,10 @@ namespace BITKit
/// </summary>
public interface INetServer
{
/// <summary>
/// 通信接口
/// </summary>
public INetProvider NetProvider=>this as INetProvider;
/// <summary>
/// 源物体,用于通过代理直接访问
/// </summary>
@ -274,6 +284,10 @@ namespace BITKit
/// </summary>
public interface INetClient
{
/// <summary>
/// 通讯接口
/// </summary>
public INetProvider NetProvider=>this as INetProvider;
/// <summary>
/// 源物体,用于通过代理直接访问
/// </summary>
@ -318,85 +332,4 @@ namespace BITKit
/// <param name="message">消息</param>
void SendServerMessage(string message);
}
#if UNITY
/// <summary>
/// 有关NetProvider的Unity代理
/// </summary>
[Serializable]
public class NetProviderProxy : INetProvider
{
[SerializeField] private MonoBehaviour monoBehaviour;
INetProvider netProvider => monoBehaviour as INetProvider;
void INetProvider.ServerCommand<T>(T command) => netProvider.ServerCommand(command);
void INetProvider.RpcClientCommand<T>(T command) => netProvider.RpcClientCommand(command);
void INetProvider.ClientCommand<T>(int id, T command) => netProvider.ClientCommand(id, command);
async UniTask<T> INetProvider.GetFromServer<T>(string addressablePath) =>
await netProvider.GetFromServer<T>(addressablePath);
UniTask<T> INetProvider.GetFromClient<T>(int id, string addressablePath) =>
netProvider.GetFromClient<T>(id, addressablePath);
void INetProvider.AddRpcHandle(object rpcHandle) => netProvider.AddRpcHandle(rpcHandle);
void INetProvider.AddCommandListener<T>(Action<T> handle) => netProvider.AddCommandListener<T>(handle);
void INetProvider.RemoveCommandListener<T>(Action<T> handle) => netProvider.RemoveCommandListener<T>(handle);
void INetProvider.SendRT(string rpcName, params object[] pars) => netProvider.SendRT(rpcName, pars);
void INetProvider.SendTargetRT(int id, string rpcName, params object[] pars) =>
netProvider.SendTargetRT(id, rpcName, pars);
void INetProvider.SendAllRT(string rpcName, params object[] pars) => netProvider.SendAllRT(rpcName, pars);
}
/// <summary>
/// 有关Unity的NetClient的代理
/// </summary>
[Serializable]
public class GDNetClientProxy : INetClient
{
[SerializeField] private MonoBehaviour monoBehaviour;
private INetClient _netClientImplementation=>monoBehaviour as INetClient;
event Action INetClient.OnStartConnect
{
add => _netClientImplementation.OnStartConnect += value;
remove => _netClientImplementation.OnStartConnect -= value;
}
event Action INetClient.OnConnected
{
add => _netClientImplementation.OnConnected += value;
remove => _netClientImplementation.OnConnected -= value;
}
event Action INetClient.OnDisconnected
{
add => _netClientImplementation.OnDisconnected += value;
remove => _netClientImplementation.OnDisconnected -= value;
}
event Action INetClient.OnConnectedFailed
{
add => _netClientImplementation.OnConnectedFailed += value;
remove => _netClientImplementation.OnConnectedFailed -= value;
}
UniTask<bool> INetClient.Connect(string address, ushort port)
{
return _netClientImplementation.Connect(address, port);
}
bool INetClient.IsConnected => _netClientImplementation.IsConnected;
int INetClient.Ping => _netClientImplementation.Ping;
public int Id => _netClientImplementation.Id;
void INetClient.Disconnect()
{
_netClientImplementation.Disconnect();
}
}
#endif
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,178 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
namespace BITKit
{
/// <summary>
/// 属性接口,用于序列化引用
/// </summary>
public interface IProperty
{
}
/// <summary>
/// 属性接口
/// GetOrCreate(√)
/// GetOrAdd(√)
/// TryGet(√)
/// TryRemove(√)
/// TrySet(√)
/// GetProperties(√)
/// </summary>
public interface IPropertable
{
/// <summary>
/// 是否拥有属性
/// </summary>
bool Contains<T>();
/// <summary>
/// 获取或创建属性
/// </summary>
T GetOrCreateProperty<T>();
/// <summary>
/// 获取或通过工厂方法添加属性
/// </summary>
T GetOrAddProperty<T>(Func<T> addFactory);
/// <summary>
/// 尝试获取属性
/// </summary>
bool TryGetProperty<T>(out T value);
/// <summary>
/// 尝试移除属性
/// </summary>
bool TryRemoveProperty<T>();
/// <summary>
/// 尝试设置属性
/// </summary>
bool TrySetProperty<T>(T value);
/// <summary>
/// 获取所有属性
/// </summary>
object[] GetProperties();
/// <summary>
/// 清除所有属性
/// </summary>
/// <returns></returns>
bool ClearProperties();
/// <summary>
/// 从其他对象复制属性
/// </summary>
/// <param name="propertable"></param>
/// <returns></returns>
bool CopyPropertiesFrom(IPropertable propertable);
}
public class Property : IPropertable
{
public Property() { }
public Property(IEnumerable<object> factory)
{
foreach (var x in factory)
{
properties.Add(x);
}
}
private readonly List<object> properties=new();
public T GetProperty<T>()
{
return properties.OfType<T>().First();
}
public void SetProperty<T>(T value)
{
for (var i = 0; i < properties.Count; i++)
{
if (properties[i] is T)
properties[i] = value;
}
}
public bool Contains<T>()
{
return properties.OfType<T>().FirstOrDefault() is not null;
}
public T GetOrCreateProperty<T>()
{
return GetOrAddProperty(Activator.CreateInstance<T>);
}
public T GetOrAddProperty<T>(Func<T> addFactory)
{
foreach (var obj in properties)
{
if (obj is T t) return t;
}
T x;
properties.Add(x = addFactory.Invoke());
return x;
}
public bool TryGetProperty<T>(out T value)
{
try
{
value = properties.OfType<T>().First();
return true;
}
catch (InvalidOperationException)
{
value = default;
return false;
}
}
public bool TryRemoveProperty<T>()
{
var removed=false;
foreach (var value in properties.OfType<T>().ToArray())
{
properties.Remove(value);
removed = true;
}
// if(properties.TryGetValue(typeof(T).FullName, out var x))
// {
// properties.Remove(typeof(T).Name);
// return true;
// }
return removed;
}
public bool TrySetProperty<T>(T value)
{
var current = properties.OfType<T>().FirstOrDefault();
if (current is not null)
{
properties.Remove(current);
return true;
}
properties.Add(value);
return false;
}
public object[] GetProperties() => properties.ToArray();
public void Read(BinaryReader r)
{
foreach (var x in properties)
{
}
}
public void Write(BinaryWriter w)
{
throw new NotImplementedException();
}
public bool ClearProperties()
{
properties.Clear();
return true;
}
public bool CopyPropertiesFrom(IPropertable propertable)
{
ClearProperties();
properties.AddRange( propertable.GetProperties());;
return true;
}
}
}

View File

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

View File

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

View File

@ -1,34 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
namespace BITKit
{
public enum SelectionState
{
None,
Hover,
Active,
Inactive,
Focus,
Selected,
Enabled,
Checked,
Root,
}
public interface ISelectable
{
#if UNITY_5_3_OR_NEWER
UnityEngine.Transform Transform { get; }
#endif
void SetSelectionState(SelectionState state);
event Action OnNone;
event Action OnHover;
event Action OnActive;
event Action OnInactive;
event Action OnFocus;
event Action OnSelected;
event Action OnEnabled;
event Action OnChecked;
event Action OnRoot;
}
}

View File

@ -1,20 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
namespace BITKit.Selection
{
public interface ISelector
{
bool TryGetCurrentSelectable(out ISelectable selectable);
event Action<ISelectable> OnNone;
event Action<ISelectable> OnHover;
event Action<ISelectable> OnActive;
event Action<ISelectable> OnInactive;
event Action<ISelectable> OnFocus;
event Action<ISelectable> OnSelected;
event Action<ISelectable> OnEnabled;
event Action<ISelectable> OnChecked;
event Action<ISelectable> OnRoot;
}
}

View File

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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
namespace BITKit
{
@ -26,6 +27,11 @@ namespace BITKit
/// </summary>
/// <param name="action"></param>
void Remove(Action<float> action);
/// <summary>
/// 手动调用循环
/// </summary>
/// <param name="delta"></param>
void ManualTick(float delta);
}
/// <summary>
/// 主线程循环
@ -35,4 +41,40 @@ namespace BITKit
/// 线程池循环
/// </summary>
public interface IThreadTicker : ITicker { }
#if UNITY_5_3_OR_NEWER
/// <summary>
/// 最后执行的循环,通常用于旋转、位移等
/// </summary>
public interface IAfterTicker : ITicker{}
/// <summary>
/// Unity专用固定循环
/// </summary>
public interface IFixedTicker : ITicker{}
#endif
public class Ticker : ITicker
{
private readonly Queue<Action> _queue = new();
private event Action<float> TickEvents;
public ulong TickCount { get; private set; }
public void Add(Action action)
{
_queue.Enqueue(action);
}
public void Add(Action<float> action)=>TickEvents += action;
public void Remove(Action<float> action)=>TickEvents -= action;
public void ManualTick(float delta)
{
TickCount++;
while (_queue.TryDequeue(out var action))
{
action.Invoke();
}
TickEvents?.Invoke(delta);
}
}
}

View File

@ -0,0 +1,70 @@
using System;
using BITKit;
using Timer = System.Timers.Timer;
namespace BITKit
{
public class TimerTicker:ITicker
{
public TimerTicker()
{
_timer = new Timer();
_timer.Elapsed += (sender, args) =>
{
OnTick();
if (_timer.Enabled && _timer.AutoReset is false)
{
_timer.Start();
}
};
}
public int TickRate { get; set; }
public ulong TickCount { get; private set; }
private readonly Timer _timer;
private float _deltaTime;
private event Action<float> Tick;
public void Add(Action action)
{
throw new NotImplementedException();
}
public void Add(Action<float> action)
{
Tick += action;
}
public void Remove(Action<float> action)
{
Tick -= action;
}
public void ManualTick(float delta)
{
throw new NotImplementedException();
}
public void Start()
{
_deltaTime = 1f / TickRate;
_timer.Interval = TimeSpan.FromSeconds(_deltaTime).TotalMilliseconds;
_timer.Enabled = true;
}
private void OnTick()
{
try
{
TickCount++;
Tick?.Invoke(_deltaTime);
}
catch (Exception e)
{
BIT4Log.LogException(e);
}
}
public void Stop()
{
_timer.Enabled = false;
}
}
}

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: eb2d5a09faa2e9a41858ff98770b423c
guid: e07078010581a9b4481480587c1f6c64
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

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

View File

@ -19,10 +19,6 @@ namespace BITKit.UX
/// </summary>
bool IsWindow { get; }
/// <summary>
/// 该面板是否有效,用于检查该面板是否已经被销毁
/// </summary>
//bool IsValid { get; }
/// <summary>
/// 该面板的索引(入口,Key)
/// </summary>
string Index { get; }
@ -38,77 +34,15 @@ namespace BITKit.UX
/// 事件回调,当面板被打开时触发
/// </summary>
event Action OnEntry;
event Func<UniTask> OnEntryAsync;
event Action OnEntryCompleted;
/// <summary>
/// 事件回调,当面板被关闭时触发
/// </summary>
event Action OnExit;
void OnUpdate(float deltaTime);
}
public abstract class UXPanelImplement:IUXPanel
{
protected abstract IUXPanel service { get; }
private IUXPanel _iuxPanelImplementation => service;
public bool IsWindow=>_iuxPanelImplementation.IsWindow;
//public bool IsValid => _iuxPanelImplementation.IsValid;
public string Index => _iuxPanelImplementation.Index;
public bool AllowCursor => _iuxPanelImplementation.AllowCursor;
public bool AllowInput => _iuxPanelImplementation.AllowInput;
public bool IsEntered
{
get => service.IsEntered;
set => service.IsEntered = value;
}
public void Entry()
{
_iuxPanelImplementation.Entry();
}
public UniTask EntryAsync()
{
return service.EntryAsync();
}
public void Entered()
{
service.Entered();
}
public void Exit()
{
_iuxPanelImplementation.Exit();
}
public UniTask ExitAsync()
{
return service.ExitAsync();
}
public void Exited()
{
service.Exited();
}
public event Action OnEntry
{
add => _iuxPanelImplementation.OnEntry += value;
remove => _iuxPanelImplementation.OnEntry -= value;
}
public event Action OnExit
{
add => _iuxPanelImplementation.OnExit += value;
remove => _iuxPanelImplementation.OnExit -= value;
}
public void OnUpdate(float deltaTime)
{
service.OnUpdate(deltaTime);
}
event Func<UniTask> OnExitAsync;
event Action OnExitCompleted;
void OnTick(float deltaTime);
}
}

View File

@ -1,10 +1,19 @@
using System;
using Cysharp.Threading.Tasks;
namespace BITKit.UX
{
/// <summary>
/// 基本UX服务(GUI管理器),主要通过加载叠加面板实现
/// </summary>
public interface IUXService
public interface IUXService:IDisposable
{
object Root { get; }
/// <summary>
/// 初始化
/// </summary>
/// <returns></returns>
UniTask InitializeAsync();
/// <summary>
/// 注册面板,加入注册队列
/// </summary>

View File

@ -8,7 +8,11 @@ namespace BITKit.UX
{
string Message { get; set; }
object Container { get; }
public void SetMessage(string message)=>Message=message;
public IUXWaitingHandle SetMessage(string message)
{
Message=message;
return this;
}
}
public interface IUXWaiting
{

View File

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

View File

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

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 87bc33909c0bd1c49987c7095fb608c2
guid: 6a9ecef037d512f40886666749c60d48
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@ -1,12 +1,10 @@
{
"name": "BITKit.MotionMatching",
"name": "BITKit.WorldNode",
"rootNamespace": "",
"references": [
"GUID:14fe60d984bf9f84eac55c6ea033a8f4",
"GUID:d525ad6bd40672747bde77962f1c401e",
"GUID:49b49c76ee64f6b41bf28ef951cb0e50",
"GUID:e34a5702dd353724aa315fb8011f08c3",
"GUID:296866320aab85a42a0403bf684bac59"
"GUID:d8b63aba1907145bea998dd612889d6b"
],
"includePlatforms": [],
"excludePlatforms": [],

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 9f93c330bf016d047a49b0c29307ef42
guid: d750d221812bb1d48baff92e6ef73e28
AssemblyDefinitionImporter:
externalObjects: {}
userData:

View File

@ -0,0 +1,19 @@
using System.Collections;
using System.Collections.Generic;
namespace BITKit.WorldNode
{
/// <summary>
/// 世界节点
/// </summary>
public interface IWorldNode
{
public int Id { get; set; }
public object WorldObject { get; set; }
public void Initialize()
{
}
}
}

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 119f6a0b25fc0cc47b6f950cd9902aba
guid: 051c8f58c08cb14449b4da1aca114caf
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@ -0,0 +1,41 @@
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
namespace BITKit.WorldNode
{
/// <summary>
/// 世界节点服务,所有动态世界节点通过此接口注册
/// </summary>
public interface IWorldNodeService
{
public IReadOnlyDictionary<int, IWorldNode> WorldNodes { get; }
public void RegisterNode(IWorldNode node);
public event Action<IWorldNode> OnNodeRegistered;
}
/// <summary>
/// 世界节点默认实现
/// </summary>
[Serializable]
public class WorldNodeService : IWorldNodeService,IDisposable
{
public static event Action<IWorldNode> OnNodeRegistered;
IReadOnlyDictionary<int, IWorldNode> IWorldNodeService.WorldNodes => WorldNodes;
private static readonly ConcurrentDictionary<int, IWorldNode> WorldNodes = new();
public void RegisterNode(IWorldNode node)
{
OnNodeRegistered?.Invoke(node);
WorldNodes.TryAdd(node.Id, node);
}
event Action<IWorldNode> IWorldNodeService.OnNodeRegistered
{
add=>OnNodeRegistered+=value;
remove=>OnNodeRegistered-=value;
}
public void Dispose()
{
WorldNodes.Clear();
}
}
}

View File

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

View File

@ -0,0 +1,53 @@
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
#if UNITY_5_3_OR_NEWER
using UnityEngine;
#endif
namespace BITKit.WorldNode
{
[Serializable]
public struct WorldInfoNode : IWorldNode
{
// ReSharper disable once InconsistentNaming
#if UNITY_5_3_OR_NEWER
[SerializeReference,SubclassSelector]
#endif
private IReference name;
// ReSharper disable once InconsistentNaming
#if UNITY_5_3_OR_NEWER
[SerializeReference,SubclassSelector]
#endif
private IReference description;
public int Id { get; set; }
public object WorldObject { get; set; }
public string Name => name?.Value;
public string Description => description?.Value;
}
public sealed class WorldInfoNodeService : IDisposable
{
public IReadOnlyDictionary<int, WorldInfoNode> WorldInfoNodes => _infoNodes;
private readonly IWorldNodeService _worldNodeService;
private readonly ConcurrentDictionary<int, WorldInfoNode> _infoNodes = new();
public WorldInfoNodeService(IWorldNodeService worldNodeService)
{
_worldNodeService = worldNodeService;
_worldNodeService.OnNodeRegistered += OnNodeRegistered;
}
private void OnNodeRegistered(IWorldNode obj)
{
if (obj is not WorldInfoNode infoNode) return;
_infoNodes.TryAdd(obj.Id, infoNode);
}
public void Dispose()
{
_infoNodes.Clear();
}
}
}

View File

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

View File

@ -0,0 +1,18 @@
using System;
using System.Collections;
using System.Collections.Generic;
namespace BITKit.WorldNode
{
[Serializable]
public struct WorldInfoPlayerStart:IWorldNode
{
public static WorldInfoPlayerStart Current { get; set; }
public int Id { get; set; }
public object WorldObject { get; set; }
public void Initialize()
{
Current = this;
}
}
}

View File

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

View File

@ -0,0 +1,26 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Unity.Mathematics;
#if UNITY_5_3_OR_NEWER
using UnityEngine;
#endif
namespace BITKit.WorldNode
{
[Serializable]
public struct WorldPortalNode:IWorldNode
{
/// <summary>
/// 目标地图名称,为空则保留该地图
/// </summary>
#if UNITY_5_3_OR_NEWER
[SerializeReference,SubclassSelector]
#endif
public IReference MapName;
public float3 Position;
public float3 EulerAngle;
public int Id { get; set; }
public object WorldObject { get; set; }
}
}

View File

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

View File

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

View File

Before

Width:  |  Height:  |  Size: 307 B

After

Width:  |  Height:  |  Size: 307 B

View File

Before

Width:  |  Height:  |  Size: 583 B

After

Width:  |  Height:  |  Size: 583 B

View File

Before

Width:  |  Height:  |  Size: 187 B

After

Width:  |  Height:  |  Size: 187 B

View File

Before

Width:  |  Height:  |  Size: 208 B

After

Width:  |  Height:  |  Size: 208 B

View File

Before

Width:  |  Height:  |  Size: 111 B

After

Width:  |  Height:  |  Size: 111 B

View File

Before

Width:  |  Height:  |  Size: 128 B

After

Width:  |  Height:  |  Size: 128 B

View File

Before

Width:  |  Height:  |  Size: 197 B

After

Width:  |  Height:  |  Size: 197 B

View File

Before

Width:  |  Height:  |  Size: 201 B

After

Width:  |  Height:  |  Size: 201 B

View File

Before

Width:  |  Height:  |  Size: 145 B

After

Width:  |  Height:  |  Size: 145 B

View File

Before

Width:  |  Height:  |  Size: 150 B

After

Width:  |  Height:  |  Size: 150 B

View File

Before

Width:  |  Height:  |  Size: 151 B

After

Width:  |  Height:  |  Size: 151 B

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