This commit is contained in:
parent
41715e4413
commit
8261a458e2
|
@ -1,5 +1,5 @@
|
||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 6d0be10870bf27f4b8b1c97ed8809308
|
guid: 66cea81a8a712d348aded0734f12d2ef
|
||||||
MonoImporter:
|
MonoImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
|
@ -2,13 +2,11 @@ using System.Dynamic;
|
||||||
|
|
||||||
namespace BITKit.Entities
|
namespace BITKit.Entities
|
||||||
{
|
{
|
||||||
public interface IdComponent
|
public class IdComponent
|
||||||
{
|
{
|
||||||
ulong Id { get; set; }
|
public int Id { get; set; }
|
||||||
}
|
public string Name { get; set; }
|
||||||
public interface IdComponent_String
|
public string Group { get; set; }
|
||||||
{
|
|
||||||
string DbId { get; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace BITKit.Entities
|
||||||
|
{
|
||||||
|
public class LocalPlayerComponent
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: b030d336e53d2c646a7b382eb83897bf
|
guid: 46172bbdf3a15d4458646b3e80b6702c
|
||||||
MonoImporter:
|
MonoImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
|
@ -5,28 +5,42 @@ using System.Linq;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Security.AccessControl;
|
using System.Security.AccessControl;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace BITKit.Entities
|
namespace BITKit.Entities
|
||||||
{
|
{
|
||||||
public class EntitiesService:IEntitiesService
|
public class EntitiesService:IEntitiesService,IDisposable
|
||||||
{
|
{
|
||||||
private readonly ConcurrentDictionary<int, IEntity> _entities = new();
|
private readonly ILogger<EntitiesService> _logger;
|
||||||
private readonly ConcurrentDictionary<Type, IEntity[]> _queryCache = new();
|
|
||||||
private readonly ConcurrentDictionary<(Type,Type), IEntity[]> _query2ComponentsCache = new();
|
private static int _count;
|
||||||
private readonly ConcurrentDictionary<(Type,Type,Type), IEntity[]> _query3ComponentsCache = new();
|
public EntitiesService()
|
||||||
|
{
|
||||||
|
_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EntitiesService(ILogger<EntitiesService> logger)
|
||||||
|
{
|
||||||
|
_count++;
|
||||||
|
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly ConcurrentDictionary<int, IEntity> Entities = new();
|
||||||
public event Action<IEntity> OnAdd;
|
public event Action<IEntity> OnAdd;
|
||||||
public event Action<IEntity> OnRemove;
|
public event Action<IEntity> OnRemove;
|
||||||
public IEntity[] Entities => _entities.Values.ToArray();
|
IEntity[] IEntitiesService.Entities => Entities.Values.ToArray();
|
||||||
public bool Register(IEntity entity)
|
public bool Register(IEntity entity)
|
||||||
{
|
{
|
||||||
if (!_entities.TryAdd(entity.Id, entity)) return false;
|
if (!Entities.TryAdd(entity.Id, entity)) return false;
|
||||||
OnAdd?.Invoke(entity);
|
OnAdd?.Invoke(entity);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool UnRegister(IEntity entity)
|
public bool UnRegister(IEntity entity)
|
||||||
{
|
{
|
||||||
if (!_entities.TryRemove(entity.Id, out _)) return false;
|
if (!Entities.TryRemove(entity.Id, out _)) return false;
|
||||||
OnRemove?.Invoke(entity);
|
OnRemove?.Invoke(entity);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -34,17 +48,17 @@ namespace BITKit.Entities
|
||||||
private readonly CancellationTokenSource _cancellationTokenSource = new();
|
private readonly CancellationTokenSource _cancellationTokenSource = new();
|
||||||
public IEntity Get(int id)
|
public IEntity Get(int id)
|
||||||
{
|
{
|
||||||
return _entities[id];
|
return Entities[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryGetEntity(int id, out IEntity entity)
|
public bool TryGetEntity(int id, out IEntity entity)
|
||||||
{
|
{
|
||||||
return _entities.TryGetValue(id, out entity);
|
return Entities.TryGetValue(id, out entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEntity GetOrAdd(int id, Func<int, IEntity> factory)
|
public IEntity GetOrAdd(int id, Func<int, IEntity> factory)
|
||||||
{
|
{
|
||||||
return _entities.GetOrAdd(id, factory);
|
return Entities.GetOrAdd(id, factory);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEntity[] Query<T>()
|
public IEntity[] Query<T>()
|
||||||
|
@ -54,16 +68,36 @@ namespace BITKit.Entities
|
||||||
|
|
||||||
public T[] QueryComponents<T>()
|
public T[] QueryComponents<T>()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
var list = new List<T>();
|
||||||
|
foreach (var entity in Entities.Values)
|
||||||
|
{
|
||||||
|
if (entity.ServiceProvider.GetService<T>() is { } t1)
|
||||||
|
{
|
||||||
|
list.Add(t1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return list.ToArray();
|
||||||
// return _queryCache.GetOrAdd(typeof(T), type =>
|
// return _queryCache.GetOrAdd(typeof(T), type =>
|
||||||
// {
|
// {
|
||||||
// return _entities.Values.Where(entity => entity.TryGetComponent(out T component)).ToArray();
|
// return _entities.Values.Where(entity => entity.TryGetComponent(out T component)).ToArray();
|
||||||
// }).Cast<T>().ToArray();
|
// }).Cast<T>().ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public (T, T1)[] QueryComponents<T, T1>()
|
public (T, T1)[] QueryComponents<T, T1>()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
var list = new List<(T, T1)>();
|
||||||
// List<(T, T1)> list = new();
|
foreach (var entity in Entities.Values)
|
||||||
|
{
|
||||||
|
if (entity.ServiceProvider.GetService<T>() is { } t1 &&
|
||||||
|
entity.ServiceProvider.GetService<T1>() is { } t2)
|
||||||
|
{
|
||||||
|
list.Add((t1, t2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return list.ToArray();
|
||||||
|
// List<(T, T1)> list = new();
|
||||||
// foreach (var entity in _entities.Values)
|
// foreach (var entity in _entities.Values)
|
||||||
// {
|
// {
|
||||||
// if (entity.TryGetComponent(out T t) && entity.TryGetComponent(out T1 t1))
|
// if (entity.TryGetComponent(out T t) && entity.TryGetComponent(out T1 t1))
|
||||||
|
@ -73,7 +107,18 @@ namespace BITKit.Entities
|
||||||
}
|
}
|
||||||
public (T, T1, T2)[] QueryComponents<T, T1, T2>()
|
public (T, T1, T2)[] QueryComponents<T, T1, T2>()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
var list = new List<(T, T1, T2)>();
|
||||||
|
foreach (var entity in Entities.Values)
|
||||||
|
{
|
||||||
|
if (entity.ServiceProvider.GetService<T>() is { } t1 &&
|
||||||
|
entity.ServiceProvider.GetService<T1>() is { } t2 &&
|
||||||
|
entity.ServiceProvider.GetService<T2>() is { } t3)
|
||||||
|
{
|
||||||
|
list.Add((t1, t2, t3));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return list.ToArray();
|
||||||
// List<(T, T1, T2)> list = new();
|
// List<(T, T1, T2)> list = new();
|
||||||
// foreach (var entity in _entities.Values)
|
// foreach (var entity in _entities.Values)
|
||||||
// {
|
// {
|
||||||
|
@ -85,7 +130,19 @@ namespace BITKit.Entities
|
||||||
|
|
||||||
public (T, T1, T2, T3)[] QueryComponents<T, T1, T2, T3>()
|
public (T, T1, T2, T3)[] QueryComponents<T, T1, T2, T3>()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
var list = new List<(T, T1, T2, T3)>();
|
||||||
|
foreach (var entity in Entities.Values)
|
||||||
|
{
|
||||||
|
if (entity.ServiceProvider.GetService<T>() is { } t1 &&
|
||||||
|
entity.ServiceProvider.GetService<T1>() is { } t2 &&
|
||||||
|
entity.ServiceProvider.GetService<T2>() is { } t3 &&
|
||||||
|
entity.ServiceProvider.GetService<T3>() is { } t4)
|
||||||
|
{
|
||||||
|
list.Add((t1, t2, t3, t4));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return list.ToArray();
|
||||||
// List<(T, T1, T2, T3)> list = new();
|
// List<(T, T1, T2, T3)> list = new();
|
||||||
// foreach (var entity in _entities.Values)
|
// foreach (var entity in _entities.Values)
|
||||||
// {
|
// {
|
||||||
|
@ -97,7 +154,20 @@ namespace BITKit.Entities
|
||||||
|
|
||||||
public (T, T1, T2, T3, T4)[] QueryComponents<T, T1, T2, T3, T4>()
|
public (T, T1, T2, T3, T4)[] QueryComponents<T, T1, T2, T3, T4>()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
var list = new List<(T, T1, T2, T3, T4)>();
|
||||||
|
foreach (var entity in Entities.Values)
|
||||||
|
{
|
||||||
|
if (entity.ServiceProvider.GetService<T>() is { } t1 &&
|
||||||
|
entity.ServiceProvider.GetService<T1>() is { } t2 &&
|
||||||
|
entity.ServiceProvider.GetService<T2>() is { } t3 &&
|
||||||
|
entity.ServiceProvider.GetService<T3>() is { } t4 &&
|
||||||
|
entity.ServiceProvider.GetService<T4>() is { } t5)
|
||||||
|
{
|
||||||
|
list.Add((t1, t2, t3, t4, t5));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return list.ToArray();
|
||||||
// List<(T, T1, T2, T3, T4)> list = new();
|
// List<(T, T1, T2, T3, T4)> list = new();
|
||||||
// foreach (var entity in _entities.Values)
|
// foreach (var entity in _entities.Values)
|
||||||
// {
|
// {
|
||||||
|
@ -109,7 +179,21 @@ namespace BITKit.Entities
|
||||||
|
|
||||||
public (T, T1, T2, T3, T4, T5)[] QueryComponents<T, T1, T2, T3, T4, T5>()
|
public (T, T1, T2, T3, T4, T5)[] QueryComponents<T, T1, T2, T3, T4, T5>()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
var list = new List<(T, T1, T2, T3, T4, T5)>();
|
||||||
|
foreach (var entity in Entities.Values)
|
||||||
|
{
|
||||||
|
if (entity.ServiceProvider.GetService<T>() is { } t1 &&
|
||||||
|
entity.ServiceProvider.GetService<T1>() is { } t2 &&
|
||||||
|
entity.ServiceProvider.GetService<T2>() is { } t3 &&
|
||||||
|
entity.ServiceProvider.GetService<T3>() is { } t4 &&
|
||||||
|
entity.ServiceProvider.GetService<T4>() is { } t5 &&
|
||||||
|
entity.ServiceProvider.GetService<T5>() is { } t6)
|
||||||
|
{
|
||||||
|
list.Add((t1, t2, t3, t4, t5, t6));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return list.ToArray();
|
||||||
// List<(T, T1, T2, T3, T4, T5)> list = new();
|
// List<(T, T1, T2, T3, T4, T5)> list = new();
|
||||||
// foreach (var entity in _entities.Values)
|
// foreach (var entity in _entities.Values)
|
||||||
// {
|
// {
|
||||||
|
@ -121,7 +205,22 @@ namespace BITKit.Entities
|
||||||
|
|
||||||
public (T, T1, T2, T3, T4, T5, T6)[] QueryComponents<T, T1, T2, T3, T4, T5, T6>()
|
public (T, T1, T2, T3, T4, T5, T6)[] QueryComponents<T, T1, T2, T3, T4, T5, T6>()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
var list = new List<(T, T1, T2, T3, T4, T5, T6)>();
|
||||||
|
foreach (var entity in Entities.Values)
|
||||||
|
{
|
||||||
|
if (entity.ServiceProvider.GetService<T>() is { } t1 &&
|
||||||
|
entity.ServiceProvider.GetService<T1>() is { } t2 &&
|
||||||
|
entity.ServiceProvider.GetService<T2>() is { } t3 &&
|
||||||
|
entity.ServiceProvider.GetService<T3>() is { } t4 &&
|
||||||
|
entity.ServiceProvider.GetService<T4>() is { } t5 &&
|
||||||
|
entity.ServiceProvider.GetService<T5>() is { } t6 &&
|
||||||
|
entity.ServiceProvider.GetService<T6>() is { } t7)
|
||||||
|
{
|
||||||
|
list.Add((t1, t2, t3, t4, t5, t6, t7));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return list.ToArray();
|
||||||
// List<(T, T1, T2, T3, T4, T5, T6)> list = new();
|
// List<(T, T1, T2, T3, T4, T5, T6)> list = new();
|
||||||
// foreach (var entity in _entities.Values)
|
// foreach (var entity in _entities.Values)
|
||||||
// {
|
// {
|
||||||
|
@ -131,10 +230,38 @@ namespace BITKit.Entities
|
||||||
// return list.ToArray();
|
// 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
|
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();
|
var list = new List<ValueTuple<T, T1, T2, T3, T4, T5, T6, TRest>>();
|
||||||
// throw new NotImplementedException();
|
foreach (var entity in Entities.Values)
|
||||||
|
{
|
||||||
|
if (entity.ServiceProvider.GetService<T>() is { } t1 &&
|
||||||
|
entity.ServiceProvider.GetService<T1>() is { } t2 &&
|
||||||
|
entity.ServiceProvider.GetService<T2>() is { } t3 &&
|
||||||
|
entity.ServiceProvider.GetService<T3>() is { } t4 &&
|
||||||
|
entity.ServiceProvider.GetService<T4>() is { } t5 &&
|
||||||
|
entity.ServiceProvider.GetService<T5>() is { } t6 &&
|
||||||
|
entity.ServiceProvider.GetService<T6>() is { } t7 &&
|
||||||
|
entity.ServiceProvider.GetService<TRest>() is { } t8)
|
||||||
|
{
|
||||||
|
list.Add(new ValueTuple<T, T1, T2, T3, T4, T5, T6, TRest>(t1, t2, t3, t4, t5, t6, t7, t8));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_count--;
|
||||||
|
if (_count <= 0)
|
||||||
|
{
|
||||||
|
Entities.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogInformation($"已释放,还剩{_count}个实例");
|
||||||
|
|
||||||
|
_cancellationTokenSource?.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,6 @@ namespace BITKit.Entities
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IEntitiesService
|
public interface IEntitiesService
|
||||||
{
|
{
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 当添加Entity时
|
/// 当添加Entity时
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 2e822c111559c204ba6fc483b283d193
|
guid: ad41977c90d905e4fa0efdcfd3260ccc
|
||||||
folderAsset: yes
|
folderAsset: yes
|
||||||
DefaultImporter:
|
DefaultImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"name": "BITKit.Hotkey",
|
||||||
|
"rootNamespace": "",
|
||||||
|
"references": [],
|
||||||
|
"includePlatforms": [],
|
||||||
|
"excludePlatforms": [],
|
||||||
|
"allowUnsafeCode": false,
|
||||||
|
"overrideReferences": false,
|
||||||
|
"precompiledReferences": [],
|
||||||
|
"autoReferenced": true,
|
||||||
|
"defineConstraints": [],
|
||||||
|
"versionDefines": [],
|
||||||
|
"noEngineReferences": true
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 01cf845b40a364e4cbaee058936fa4a3
|
guid: 3abaaefa7af558d44ba20cea1c43d602
|
||||||
AssemblyDefinitionImporter:
|
AssemblyDefinitionImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
userData:
|
userData:
|
|
@ -0,0 +1,47 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace BITKit.UX.Hotkey
|
||||||
|
{
|
||||||
|
public interface IHotkeyProvider
|
||||||
|
{
|
||||||
|
string Name { get; }
|
||||||
|
string Description { get; }
|
||||||
|
object Data { get; }
|
||||||
|
bool Enabled { get; }
|
||||||
|
Action OnPerform { get; }
|
||||||
|
float HoldDuration => 0;
|
||||||
|
}
|
||||||
|
public struct HotkeyProvider : IHotkeyProvider
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string Description { get; set; }
|
||||||
|
public object Data { get; set; }
|
||||||
|
public bool Enabled { get; set; }
|
||||||
|
public Action OnPerform { get; set; }
|
||||||
|
|
||||||
|
public float HoldDuration { get; set; }
|
||||||
|
}
|
||||||
|
public interface IHotkeyCollection
|
||||||
|
{
|
||||||
|
IEnumerable<IHotkeyProvider> Hotkeys { get; }
|
||||||
|
void Register(IHotkeyProvider hotkey);
|
||||||
|
void UnRegister(IHotkeyProvider hotkey);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class HotkeyCollection:IHotkeyCollection
|
||||||
|
{
|
||||||
|
private readonly HashSet<IHotkeyProvider> _hotkeys = new();
|
||||||
|
public IEnumerable<IHotkeyProvider> Hotkeys => _hotkeys;
|
||||||
|
public void Register(IHotkeyProvider hotkey)
|
||||||
|
{
|
||||||
|
_hotkeys.Add(hotkey);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UnRegister(IHotkeyProvider hotkey)
|
||||||
|
{
|
||||||
|
_hotkeys.Remove(hotkey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 7ba6497a10fb8e14dab1acb39b2ec8aa
|
guid: 0ad36bc56dd5406418bf8ea67f4bc010
|
||||||
MonoImporter:
|
MonoImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
|
@ -53,7 +53,13 @@ namespace BITKit
|
||||||
public interface IScriptableItemProperty
|
public interface IScriptableItemProperty
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 控制器(分)类
|
||||||
|
/// </summary>
|
||||||
|
public interface IScriptableControllerClass
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 基础物品
|
/// 基础物品
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -88,6 +94,11 @@ namespace BITKit
|
||||||
/// 属性
|
/// 属性
|
||||||
/// </summary>
|
/// </summary>
|
||||||
IReadOnlyDictionary<Type, IScriptableItemProperty> Properties { get; }
|
IReadOnlyDictionary<Type, IScriptableItemProperty> Properties { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 控制器类
|
||||||
|
/// </summary>
|
||||||
|
IScriptableControllerClass ControllerClass { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 价值
|
/// 价值
|
||||||
|
|
|
@ -14,6 +14,7 @@ using BITKit.IO;
|
||||||
using BITKit.UX;
|
using BITKit.UX;
|
||||||
using Cysharp.Threading.Tasks;
|
using Cysharp.Threading.Tasks;
|
||||||
using Microsoft.CSharp;
|
using Microsoft.CSharp;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace BITKit.Mod
|
namespace BITKit.Mod
|
||||||
|
@ -133,17 +134,26 @@ namespace BITKit.Mod
|
||||||
|
|
||||||
var list=new List<ModPackage>();
|
var list=new List<ModPackage>();
|
||||||
var path = Path.Combine(Environment.CurrentDirectory, "Mods");
|
var path = Path.Combine(Environment.CurrentDirectory, "Mods");
|
||||||
var dir = new DirectoryInfo(path);
|
|
||||||
dir.Create();
|
try
|
||||||
foreach (var x in dir.GetDirectories())
|
|
||||||
{
|
{
|
||||||
var file = Path.Combine(x.FullName,ModPackage.DefaultFileName);
|
var dir = new DirectoryInfo(path);
|
||||||
if(File.Exists(file) is false)continue;
|
dir.Create();
|
||||||
var package = JsonConvert.DeserializeObject<ModPackage>(await File.ReadAllTextAsync(file))!;
|
foreach (var x in dir.GetDirectories())
|
||||||
package.PackagePath = file;
|
{
|
||||||
package.WorkDirectory = x.FullName;
|
var file = Path.Combine(x.FullName,ModPackage.DefaultFileName);
|
||||||
list.Add(package);
|
if(File.Exists(file) is false)continue;
|
||||||
|
var package = JsonConvert.DeserializeObject<ModPackage>(await File.ReadAllTextAsync(file))!;
|
||||||
|
package.PackagePath = file;
|
||||||
|
package.WorkDirectory = x.FullName;
|
||||||
|
list.Add(package);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
BIT4Log.LogException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return list.ToArray();
|
return list.ToArray();
|
||||||
}
|
}
|
||||||
|
@ -200,19 +210,16 @@ namespace BITKit.Mod
|
||||||
private static CancellationTokenSource _CancellationTokenSource;
|
private static CancellationTokenSource _CancellationTokenSource;
|
||||||
private static readonly ConcurrentDictionary<string,IMod> _InstalledMods=new();
|
private static readonly ConcurrentDictionary<string,IMod> _InstalledMods=new();
|
||||||
|
|
||||||
public static async UniTask Initialize()
|
public static async UniTask Initialize(ILogger logger=null)
|
||||||
{
|
{
|
||||||
BIT4Log.Log<ModService>("Mod服务已启动");
|
logger?.LogInformation("Mod服务已启动");
|
||||||
_CancellationTokenSource = new CancellationTokenSource();
|
_CancellationTokenSource = new CancellationTokenSource();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var modPath = Path.Combine(Environment.CurrentDirectory, "Mods\\");
|
var modPath = Path.Combine(Environment.CurrentDirectory, @"Mods\");
|
||||||
PathHelper.EnsureDirectoryCreated(modPath);
|
PathHelper.EnsureDirectoryCreated(modPath);
|
||||||
var directoryInfo = new DirectoryInfo(modPath);
|
var directoryInfo = new DirectoryInfo(modPath);
|
||||||
foreach (var fileInfo in directoryInfo.GetFiles())
|
foreach (var fileInfo in directoryInfo.GetFiles())
|
||||||
|
@ -238,18 +245,16 @@ namespace BITKit.Mod
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
BIT4Log.Warning<ModService>("自动加载Mod失败");
|
logger?.LogWarning("自动加载Mod失败");
|
||||||
BIT4Log.LogException(e);
|
BIT4Log.LogException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
logger?.LogWarning("Mod服务遇到了错误,已停止");
|
||||||
BIT4Log.LogException(e);
|
BIT4Log.LogException(e);
|
||||||
BIT4Log.Warning<ModService>("Mod服务遇到了错误,已停止");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Dispose()
|
public static void Dispose()
|
||||||
|
@ -336,7 +341,7 @@ namespace BITKit.Mod
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var fileInfo = new FileInfo(path);
|
var fileInfo = new FileInfo(path);
|
||||||
switch (fileInfo.Extension)
|
switch (fileInfo.Extension)
|
||||||
{
|
{
|
||||||
case ".dll":
|
case ".dll":
|
||||||
|
@ -360,6 +365,10 @@ namespace BITKit.Mod
|
||||||
}
|
}
|
||||||
public static async UniTask Load(IMod mod)
|
public static async UniTask Load(IMod mod)
|
||||||
{
|
{
|
||||||
|
await IsBusy;
|
||||||
|
|
||||||
|
using var _ = IsBusy.GetHandle();
|
||||||
|
|
||||||
mod.OnInitialize();
|
mod.OnInitialize();
|
||||||
OnModLoad?.Invoke(mod);
|
OnModLoad?.Invoke(mod);
|
||||||
BIT4Log.Log<ModService>($"加载Mod:{mod.GetType().FullName}");
|
BIT4Log.Log<ModService>($"加载Mod:{mod.GetType().FullName}");
|
||||||
|
@ -381,7 +390,7 @@ namespace BITKit.Mod
|
||||||
BIT4Log.Log<ModService>($"卸载Mod:{mod.GetType().FullName}");
|
BIT4Log.Log<ModService>($"卸载Mod:{mod.GetType().FullName}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async void Install(IMod mod)
|
public static async UniTask Install(IMod mod)
|
||||||
{
|
{
|
||||||
await IsBusy;
|
await IsBusy;
|
||||||
|
|
||||||
|
@ -404,11 +413,12 @@ namespace BITKit.Mod
|
||||||
mod.OnInitialized();
|
mod.OnInitialized();
|
||||||
OnModLoaded?.Invoke(mod);
|
OnModLoaded?.Invoke(mod);
|
||||||
}
|
}
|
||||||
public static void UnInstall(IMod mod)
|
public static async UniTask UnInstall(IMod mod)
|
||||||
{
|
{
|
||||||
|
await IsBusy;
|
||||||
|
|
||||||
using var _ = IsBusy.GetHandle();
|
using var _ = IsBusy.GetHandle();
|
||||||
|
|
||||||
|
|
||||||
if(_InstalledMods.ContainsKey(mod.PackageName) is false) return;
|
if(_InstalledMods.ContainsKey(mod.PackageName) is false) return;
|
||||||
_InstalledMods.TryRemove(mod.PackageName);
|
_InstalledMods.TryRemove(mod.PackageName);
|
||||||
Mods = _InstalledMods.Values.ToArray();
|
Mods = _InstalledMods.Values.ToArray();
|
||||||
|
|
|
@ -8,7 +8,20 @@ namespace BITKit.Mod
|
||||||
public partial class ModService
|
public partial class ModService
|
||||||
{
|
{
|
||||||
public static Func<string, UniTask<object>> LoadAssetAsyncFactory;
|
public static Func<string, UniTask<object>> LoadAssetAsyncFactory;
|
||||||
|
public static Func<string[], UniTask<IReadOnlyList<object>>> LoadAssetsAsyncFactory;
|
||||||
|
|
||||||
|
public static async UniTask<IReadOnlyList<T>> LoadAssets<T>(params string[] tags)
|
||||||
|
{
|
||||||
|
var list = new List<T>();
|
||||||
|
foreach (var func in LoadAssetsAsyncFactory.CastAsFunc())
|
||||||
|
{
|
||||||
|
foreach (var obj in await func.Invoke(tags))
|
||||||
|
{
|
||||||
|
list.Add((T)obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
public static async UniTask<T> LoadAsset<T>(string location) where T : class
|
public static async UniTask<T> LoadAsset<T>(string location) where T : class
|
||||||
{
|
{
|
||||||
if (LoadAssetAsyncFactory is null)
|
if (LoadAssetAsyncFactory is null)
|
||||||
|
|
|
@ -272,6 +272,14 @@ namespace BITKit
|
||||||
using var ms = new MemoryStream();
|
using var ms = new MemoryStream();
|
||||||
using var writer = new BinaryWriter(ms);
|
using var writer = new BinaryWriter(ms);
|
||||||
|
|
||||||
|
foreach (var parameterInfo in methodInfo.GetParameters())
|
||||||
|
{
|
||||||
|
if (parameterInfo.IsOut)
|
||||||
|
{
|
||||||
|
codeBuilder.AppendLine($"{parameterInfo.Name} = default;");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
codeBuilder.AppendLine(" using var ms = new MemoryStream();");
|
codeBuilder.AppendLine(" using var ms = new MemoryStream();");
|
||||||
codeBuilder.AppendLine(" using var writer = new BinaryWriter(ms);");
|
codeBuilder.AppendLine(" using var writer = new BinaryWriter(ms);");
|
||||||
codeBuilder.AppendLine(" writer.Write((byte)NetCommandType.Rpc);");
|
codeBuilder.AppendLine(" writer.Write((byte)NetCommandType.Rpc);");
|
||||||
|
@ -466,6 +474,7 @@ namespace BITKit
|
||||||
{
|
{
|
||||||
options= options.AddReferences(referencedAssembly);
|
options= options.AddReferences(referencedAssembly);
|
||||||
}
|
}
|
||||||
|
options = options.AddReferences(typeof(BITApp).Assembly);
|
||||||
|
|
||||||
var assembly = BITSharp.Compile(code, options);
|
var assembly = BITSharp.Compile(code, options);
|
||||||
|
|
||||||
|
|
|
@ -110,6 +110,11 @@ namespace BITKit
|
||||||
{
|
{
|
||||||
codeBuilder.AppendLine(GenerateMethod(method));
|
codeBuilder.AppendLine(GenerateMethod(method));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (var eventInfo in type.GetEvents())
|
||||||
|
{
|
||||||
|
codeBuilder.AppendLine(GenerateEvent(eventInfo));
|
||||||
|
}
|
||||||
|
|
||||||
codeBuilder.AppendLine(AfterGenerate(type));
|
codeBuilder.AppendLine(AfterGenerate(type));
|
||||||
|
|
||||||
|
@ -136,25 +141,32 @@ namespace BITKit
|
||||||
public virtual string GenerateMethod(MethodInfo methodInfo)
|
public virtual string GenerateMethod(MethodInfo methodInfo)
|
||||||
{
|
{
|
||||||
var codeBuilder = new StringBuilder();
|
var codeBuilder = new StringBuilder();
|
||||||
HashSet<MethodInfo> propertyMethods = new();
|
HashSet<MethodInfo> ignoreMethods = new();
|
||||||
|
|
||||||
|
foreach (var eventInfo in methodInfo.DeclaringType!.GetEvents())
|
||||||
|
{
|
||||||
|
ignoreMethods.Add(eventInfo.AddMethod);
|
||||||
|
ignoreMethods.Add(eventInfo.RemoveMethod);
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var propertyInfo in methodInfo.DeclaringType!.GetProperties())
|
foreach (var propertyInfo in methodInfo.DeclaringType!.GetProperties())
|
||||||
{
|
{
|
||||||
if (propertyInfo.GetMethod is not null)
|
if (propertyInfo.GetMethod is not null)
|
||||||
{
|
{
|
||||||
propertyMethods.Add(propertyInfo.GetMethod);
|
ignoreMethods.Add(propertyInfo.GetMethod);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (propertyInfo.SetMethod is not null)
|
if (propertyInfo.SetMethod is not null)
|
||||||
{
|
{
|
||||||
propertyMethods.Add(propertyInfo.SetMethod);
|
ignoreMethods.Add(propertyInfo.SetMethod);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(propertyMethods.Contains(methodInfo))return string.Empty;
|
|
||||||
|
if(ignoreMethods.Contains(methodInfo))return string.Empty;
|
||||||
string methodName = methodInfo.Name;
|
string methodName = methodInfo.Name;
|
||||||
string parameters = string.Join(", ", methodInfo.GetParameters()
|
string parameters = string.Join(", ", methodInfo.GetParameters()
|
||||||
.Select(p => $"{CSharpName(p.ParameterType)} {p.Name}"));
|
.Select(p => $"{(p.IsOut?"out":string.Empty)} {CSharpName(p.IsOut?p.ParameterType.GetElementType():p.ParameterType)} {p.Name}"));
|
||||||
|
|
||||||
var isAwaitable = methodInfo.ReturnType.GetMethod(nameof(Task.GetAwaiter)) != null;
|
var isAwaitable = methodInfo.ReturnType.GetMethod(nameof(Task.GetAwaiter)) != null;
|
||||||
|
|
||||||
|
@ -194,7 +206,17 @@ namespace BITKit
|
||||||
|
|
||||||
public virtual string GenerateMethodContext(MethodInfo methodInfo)
|
public virtual string GenerateMethodContext(MethodInfo methodInfo)
|
||||||
{
|
{
|
||||||
return methodInfo.ReturnType == typeof(void) ? string.Empty : $"return default;";
|
var codeBuilder = new StringBuilder();
|
||||||
|
foreach (var parameterInfo in methodInfo.GetParameters())
|
||||||
|
{
|
||||||
|
if (parameterInfo.IsOut)
|
||||||
|
{
|
||||||
|
codeBuilder.AppendLine($"{parameterInfo.Name} = default;");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
codeBuilder.AppendLine(methodInfo.ReturnType == typeof(void) ? string.Empty : $"return default;");
|
||||||
|
return codeBuilder.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual string GenerateField(FieldInfo fieldInfo)
|
public virtual string GenerateField(FieldInfo fieldInfo)
|
||||||
|
@ -209,7 +231,7 @@ namespace BITKit
|
||||||
|
|
||||||
public virtual string GenerateEvent(EventInfo eventInfo)
|
public virtual string GenerateEvent(EventInfo eventInfo)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
return $"public event {CSharpName(eventInfo.EventHandlerType)} {eventInfo.Name};";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if UNITY_5_3_OR_NEWER
|
#if UNITY_5_3_OR_NEWER
|
||||||
|
@ -257,7 +279,6 @@ namespace BITKit
|
||||||
{
|
{
|
||||||
result.Add(fieldInfo.FieldType.Assembly);
|
result.Add(fieldInfo.FieldType.Assembly);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var propertyInfo in type.GetProperties())
|
foreach (var propertyInfo in type.GetProperties())
|
||||||
{
|
{
|
||||||
result.Add(propertyInfo.PropertyType.Assembly);
|
result.Add(propertyInfo.PropertyType.Assembly);
|
||||||
|
@ -269,6 +290,10 @@ namespace BITKit
|
||||||
{
|
{
|
||||||
result.Add(argument.Assembly);
|
result.Add(argument.Assembly);
|
||||||
}
|
}
|
||||||
|
foreach (var parameterInfo in methodInfo.GetParameters())
|
||||||
|
{
|
||||||
|
result.Add(parameterInfo.ParameterType.Assembly);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -295,7 +320,24 @@ namespace BITKit
|
||||||
using var ms = new MemoryStream();
|
using var ms = new MemoryStream();
|
||||||
var result = script.GetCompilation().Emit(ms);
|
var result = script.GetCompilation().Emit(ms);
|
||||||
|
|
||||||
if (!result.Success) throw new Exception(string.Join("\n",result.Diagnostics));
|
if (!result.Success)
|
||||||
|
{
|
||||||
|
var report = new StringBuilder();
|
||||||
|
report.AppendLine(code);
|
||||||
|
|
||||||
|
foreach (var reference in script.GetCompilation().References)
|
||||||
|
{
|
||||||
|
report.AppendLine("Assembly referenced:" + reference.Display);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var diagnostic in result.Diagnostics)
|
||||||
|
{
|
||||||
|
report.AppendLine(diagnostic.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
throw new Exception(report.ToString());
|
||||||
|
}
|
||||||
ms.Seek(0, SeekOrigin.Begin);
|
ms.Seek(0, SeekOrigin.Begin);
|
||||||
var assembly = Assembly.Load(ms.ToArray()); // 加载程序集
|
var assembly = Assembly.Load(ms.ToArray()); // 加载程序集
|
||||||
|
|
||||||
|
|
|
@ -25,8 +25,8 @@ namespace BITKit.StateMachine
|
||||||
public bool Enabled { get; set; } = true;
|
public bool Enabled { get; set; } = true;
|
||||||
public T CurrentState { get;private set; }
|
public T CurrentState { get;private set; }
|
||||||
public T NextOrCurrentState => _nextTargetState.IfNotAllow(CurrentState);
|
public T NextOrCurrentState => _nextTargetState.IfNotAllow(CurrentState);
|
||||||
private T _nextState;
|
|
||||||
public event Action<T, T> OnStateChanging;
|
public event Action<T, T> OnStateChanging;
|
||||||
|
public event Func<T, T, UniTask> OnStateChangeAsync;
|
||||||
public event Action<T, T> OnStateChanged;
|
public event Action<T, T> OnStateChanged;
|
||||||
public event Action<T> OnStateRegistered;
|
public event Action<T> OnStateRegistered;
|
||||||
public IReadOnlyDictionary<int, T> Dictionary => _dictionary;
|
public IReadOnlyDictionary<int, T> Dictionary => _dictionary;
|
||||||
|
@ -53,21 +53,18 @@ namespace BITKit.StateMachine
|
||||||
{
|
{
|
||||||
if (CurrentState is null) return;
|
if (CurrentState is null) return;
|
||||||
using var _ = IsBusy.GetHandle();
|
using var _ = IsBusy.GetHandle();
|
||||||
await CurrentState.OnStateUpdateAsync(deltaTime);
|
|
||||||
CurrentState.OnStateUpdate(deltaTime);
|
CurrentState.OnStateUpdate(deltaTime);
|
||||||
|
await CurrentState.OnStateUpdateAsync(deltaTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public async void DisposeState()
|
public async void DisposeState()
|
||||||
{
|
{
|
||||||
await IsBusy;
|
await IsBusy;
|
||||||
if(_cancellationTokenSource.IsCancellationRequested)return;
|
if (_cancellationTokenSource.IsCancellationRequested) return;
|
||||||
if (CurrentState is null) return;
|
if (CurrentState is null) return;
|
||||||
using var _ = IsBusy.GetHandle();
|
using var _ = IsBusy.GetHandle();
|
||||||
if (CurrentState is not null)
|
CurrentState.Enabled = false;
|
||||||
{
|
|
||||||
CurrentState.Enabled = false;
|
|
||||||
}
|
|
||||||
await CurrentState.OnStateExitAsync(CurrentState, null);
|
await CurrentState.OnStateExitAsync(CurrentState, null);
|
||||||
CurrentState.OnStateExit(CurrentState, null);
|
CurrentState.OnStateExit(CurrentState, null);
|
||||||
CurrentState = null;
|
CurrentState = null;
|
||||||
|
@ -108,10 +105,15 @@ namespace BITKit.StateMachine
|
||||||
}
|
}
|
||||||
_nextTargetState.SetValueThenAllow(nextState);
|
_nextTargetState.SetValueThenAllow(nextState);
|
||||||
await IsBusy;
|
await IsBusy;
|
||||||
|
|
||||||
|
if(CurrentState==nextState)return;
|
||||||
if(_cancellationTokenSource.IsCancellationRequested)return;
|
if(_cancellationTokenSource.IsCancellationRequested)return;
|
||||||
using var _ = IsBusy.GetHandle();
|
using var _ = IsBusy.GetHandle();
|
||||||
|
|
||||||
OnStateChanging?.Invoke(CurrentState,nextState);
|
OnStateChanging?.Invoke(CurrentState,nextState);
|
||||||
if (_dictionary.TryAdd(nextState.Identifier, nextState))
|
await OnStateChangeAsync.UniTaskFunc(CurrentState,nextState);
|
||||||
|
|
||||||
|
if (nextState is not null && _dictionary.TryAdd(nextState.Identifier, nextState))
|
||||||
{
|
{
|
||||||
await nextState.InitializeAsync();
|
await nextState.InitializeAsync();
|
||||||
if(_cancellationTokenSource.IsCancellationRequested)return;
|
if(_cancellationTokenSource.IsCancellationRequested)return;
|
||||||
|
@ -125,6 +127,11 @@ namespace BITKit.StateMachine
|
||||||
CurrentState.OnStateExit(CurrentState,nextState);
|
CurrentState.OnStateExit(CurrentState,nextState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_nextTargetState.Allow && _nextTargetState.Value != nextState)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var tempState = CurrentState;
|
var tempState = CurrentState;
|
||||||
CurrentState = _nextTargetState.Value;
|
CurrentState = _nextTargetState.Value;
|
||||||
_nextTargetState.Clear();
|
_nextTargetState.Clear();
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Cysharp.Threading.Tasks;
|
using Cysharp.Threading.Tasks;
|
||||||
|
|
||||||
|
@ -44,11 +45,16 @@ namespace BITKit.StateMachine
|
||||||
UniTask OnStateExitAsync(IState old, IState newState);
|
UniTask OnStateExitAsync(IState old, IState newState);
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IStateMachine<T> where T:IState
|
public interface IMicroStateMachine<T>
|
||||||
|
{
|
||||||
|
T CurrentState { get; }
|
||||||
|
event Action<T, T> OnStateChanged;
|
||||||
|
T TransitionState<TState>() where TState : T;
|
||||||
|
T TransitionState(T state);
|
||||||
|
}
|
||||||
|
public interface IStateMachine<T>:IMicroStateMachine<T> where T:IState
|
||||||
{
|
{
|
||||||
bool Enabled { get; set; }
|
bool Enabled { get; set; }
|
||||||
T CurrentState { get; }
|
|
||||||
event Action<T,T> OnStateChanged;
|
|
||||||
event Action<T> OnStateRegistered;
|
event Action<T> OnStateRegistered;
|
||||||
event Action<T> OnStateUnRegistered;
|
event Action<T> OnStateUnRegistered;
|
||||||
|
|
||||||
|
@ -56,13 +62,72 @@ namespace BITKit.StateMachine
|
||||||
void Initialize();
|
void Initialize();
|
||||||
void UpdateState(float deltaTime);
|
void UpdateState(float deltaTime);
|
||||||
void DisposeState();
|
void DisposeState();
|
||||||
T TransitionState<TState>() where TState : T;
|
|
||||||
T TransitionState(T state);
|
|
||||||
void Register(T newState) => throw new NotImplementedException("未实现的接口");
|
void Register(T newState) => throw new NotImplementedException("未实现的接口");
|
||||||
void UnRegister(T newState) => throw new NotImplementedException("未实现的接口");
|
void UnRegister(T newState) => throw new NotImplementedException("未实现的接口");
|
||||||
void InvokeOnStateRegistered(T state){}
|
void InvokeOnStateRegistered(T state){}
|
||||||
void InvokeOnStateUnRegistered(T state){}
|
void InvokeOnStateUnRegistered(T state){}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class MicroStateMachine<T> : IMicroStateMachine<T>
|
||||||
|
{
|
||||||
|
public T CurrentState { get; private set; }
|
||||||
|
public event Action<T, T> OnStateChanged;
|
||||||
|
private readonly ConcurrentDictionary<Type,T> _stateDictionary=new();
|
||||||
|
public T TransitionState<TState>() where TState : T
|
||||||
|
{
|
||||||
|
var state = _stateDictionary.GetOrAdd(typeof(TState), Activator.CreateInstance<TState>());
|
||||||
|
return TransitionState(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T TransitionState(T state)
|
||||||
|
{
|
||||||
|
_stateDictionary.TryAdd(state.GetType(), state);
|
||||||
|
|
||||||
|
if (Equals(state, CurrentState)) return default;
|
||||||
|
|
||||||
|
var currentState = CurrentState;
|
||||||
|
CurrentState = state;
|
||||||
|
OnStateChanged?.Invoke(currentState, state);
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public abstract class StateAsync:IStateAsync
|
||||||
|
{
|
||||||
|
public virtual bool Enabled { get; set; }
|
||||||
|
public virtual void Initialize()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void OnStateEntry(IState old)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void OnStateUpdate(float deltaTime)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void OnStateExit(IState old, IState newState)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual int Identifier { get; set; }
|
||||||
|
public virtual UniTask InitializeAsync()
|
||||||
|
{
|
||||||
|
return UniTask.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual UniTask OnStateEntryAsync(IState old)
|
||||||
|
{ return UniTask.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual UniTask OnStateUpdateAsync(float deltaTime)
|
||||||
|
{ return UniTask.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual UniTask OnStateExitAsync(IState old, IState newState)
|
||||||
|
{ return UniTask.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
public static class StateMachineUtils
|
public static class StateMachineUtils
|
||||||
{
|
{
|
||||||
public static void Register<T>(this IStateMachine<T> stateMachine, T newState) where T : IState
|
public static void Register<T>(this IStateMachine<T> stateMachine, T newState) where T : IState
|
||||||
|
|
|
@ -30,6 +30,7 @@ namespace BITKit.UX
|
||||||
/// 该面板是否启用玩家输入
|
/// 该面板是否启用玩家输入
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool AllowInput { get; }
|
bool AllowInput { get; }
|
||||||
|
object Root { get; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 事件回调,当面板被打开时触发
|
/// 事件回调,当面板被打开时触发
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -43,6 +44,8 @@ namespace BITKit.UX
|
||||||
|
|
||||||
event Func<UniTask> OnExitAsync;
|
event Func<UniTask> OnExitAsync;
|
||||||
event Action OnExitCompleted;
|
event Action OnExitCompleted;
|
||||||
|
public event Action OnInitiated;
|
||||||
|
public event Func<UniTask> OnInitiatedAsync;
|
||||||
void OnTick(float deltaTime);
|
void OnTick(float deltaTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using Cysharp.Threading.Tasks;
|
using Cysharp.Threading.Tasks;
|
||||||
|
using Unity.Mathematics;
|
||||||
|
|
||||||
namespace BITKit.UX
|
namespace BITKit.UX
|
||||||
{
|
{
|
||||||
|
@ -52,6 +53,13 @@ namespace BITKit.UX
|
||||||
/// 面板改变回调
|
/// 面板改变回调
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event Action<IUXPanel, IUXPanel> OnPanelChanged;
|
public event Action<IUXPanel, IUXPanel> OnPanelChanged;
|
||||||
|
/// <summary>
|
||||||
|
/// 获取可交互的元素
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="position"></param>
|
||||||
|
/// <param name="obj"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public bool TryPick(float2 position, out object obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ namespace BITKit.WorldNode
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IWorldNodeService
|
public interface IWorldNodeService
|
||||||
{
|
{
|
||||||
public IReadOnlyDictionary<int, IWorldNode> WorldNodes { get; }
|
public IReadOnlyDictionary<int, HashSet<IWorldNode>> WorldNodes { get; }
|
||||||
public void RegisterNode(IWorldNode node);
|
public void RegisterNode(IWorldNode node);
|
||||||
public event Action<IWorldNode> OnNodeRegistered;
|
public event Action<IWorldNode> OnNodeRegistered;
|
||||||
}
|
}
|
||||||
|
@ -21,12 +21,12 @@ namespace BITKit.WorldNode
|
||||||
public class WorldNodeService : IWorldNodeService,IDisposable
|
public class WorldNodeService : IWorldNodeService,IDisposable
|
||||||
{
|
{
|
||||||
public static event Action<IWorldNode> OnNodeRegistered;
|
public static event Action<IWorldNode> OnNodeRegistered;
|
||||||
IReadOnlyDictionary<int, IWorldNode> IWorldNodeService.WorldNodes => WorldNodes;
|
IReadOnlyDictionary<int, HashSet<IWorldNode>> IWorldNodeService.WorldNodes => WorldNodes;
|
||||||
private static readonly ConcurrentDictionary<int, IWorldNode> WorldNodes = new();
|
private static readonly ConcurrentDictionary<int, HashSet<IWorldNode>> WorldNodes = new();
|
||||||
public void RegisterNode(IWorldNode node)
|
public void RegisterNode(IWorldNode node)
|
||||||
{
|
{
|
||||||
OnNodeRegistered?.Invoke(node);
|
OnNodeRegistered?.Invoke(node);
|
||||||
WorldNodes.TryAdd(node.Id, node);
|
WorldNodes.GetOrCreate(node.Id).Add(node);
|
||||||
}
|
}
|
||||||
event Action<IWorldNode> IWorldNodeService.OnNodeRegistered
|
event Action<IWorldNode> IWorldNodeService.OnNodeRegistered
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
#if UNITY_5_3_OR_NEWER
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
@ -12,6 +13,8 @@ namespace BITKit.WorldNode
|
||||||
[SerializeReference, SubclassSelector] private IWorldNode worldNode;
|
[SerializeReference, SubclassSelector] private IWorldNode worldNode;
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
public IWorldNode WorldNode => worldNode;
|
||||||
|
|
||||||
public object WorldObject
|
public object WorldObject
|
||||||
{
|
{
|
||||||
get => gameObject;
|
get => gameObject;
|
||||||
|
@ -27,10 +30,10 @@ namespace BITKit.WorldNode
|
||||||
Id = gameObject.GetInstanceID();
|
Id = gameObject.GetInstanceID();
|
||||||
worldNode.Id = Id;
|
worldNode.Id = Id;
|
||||||
worldNode.WorldObject = gameObject;
|
worldNode.WorldObject = gameObject;
|
||||||
worldNodeService.RegisterNode(worldNode);
|
|
||||||
worldNode.Initialize();
|
worldNode.Initialize();
|
||||||
|
worldNodeService.RegisterNode(worldNode);
|
||||||
Destroy(this);
|
Destroy(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
|
@ -20,17 +20,24 @@ namespace BITKit.WorldNode
|
||||||
[SerializeReference,SubclassSelector]
|
[SerializeReference,SubclassSelector]
|
||||||
#endif
|
#endif
|
||||||
private IReference description;
|
private IReference description;
|
||||||
|
#if UNITY_5_3_OR_NEWER
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
Name = name?.Value;
|
||||||
|
Description = description?.Value;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
public object WorldObject { get; set; }
|
public object WorldObject { get; set; }
|
||||||
public string Name => name?.Value;
|
public string Name { get; set; }
|
||||||
public string Description => description?.Value;
|
public string Description { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class WorldInfoNodeService : IDisposable
|
public sealed class WorldInfoNodeService : IDisposable
|
||||||
{
|
{
|
||||||
public IReadOnlyDictionary<int, WorldInfoNode> WorldInfoNodes => _infoNodes;
|
public IReadOnlyDictionary<int, WorldInfoNode> WorldInfoNodes => InfoNodes;
|
||||||
private readonly IWorldNodeService _worldNodeService;
|
private readonly IWorldNodeService _worldNodeService;
|
||||||
private readonly ConcurrentDictionary<int, WorldInfoNode> _infoNodes = new();
|
private static readonly ConcurrentDictionary<int, WorldInfoNode> InfoNodes = new();
|
||||||
|
|
||||||
public WorldInfoNodeService(IWorldNodeService worldNodeService)
|
public WorldInfoNodeService(IWorldNodeService worldNodeService)
|
||||||
{
|
{
|
||||||
|
@ -42,12 +49,12 @@ namespace BITKit.WorldNode
|
||||||
private void OnNodeRegistered(IWorldNode obj)
|
private void OnNodeRegistered(IWorldNode obj)
|
||||||
{
|
{
|
||||||
if (obj is not WorldInfoNode infoNode) return;
|
if (obj is not WorldInfoNode infoNode) return;
|
||||||
_infoNodes.TryAdd(obj.Id, infoNode);
|
InfoNodes.TryAdd(obj.Id, infoNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
_infoNodes.Clear();
|
InfoNodes.Clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace BITKit.WorldNode
|
||||||
|
{
|
||||||
|
[Serializable]
|
||||||
|
public struct WorldInfoNpcStartNode:IWorldNode
|
||||||
|
{
|
||||||
|
public string Address;
|
||||||
|
public int Id { get; set; }
|
||||||
|
public object WorldObject { get; set; }
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: c9d7136f598a780459b866ee63545a5f
|
guid: f2fba06a66e155a4580df30630f030fc
|
||||||
MonoImporter:
|
MonoImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
|
@ -14,6 +14,22 @@ namespace BITKit
|
||||||
}
|
}
|
||||||
public class ValueWrapper<T> : IWrapper<T>
|
public class ValueWrapper<T> : IWrapper<T>
|
||||||
{
|
{
|
||||||
|
public ValueWrapper()
|
||||||
|
{
|
||||||
|
var type = typeof(T);
|
||||||
|
if (type == typeof(string))
|
||||||
|
{
|
||||||
|
_value = string.Empty.As<T>();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(type.IsAbstract || type.IsInterface)return;
|
||||||
|
// 检查类型是否具有公共无参数构造函数
|
||||||
|
var constructor = type.GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, Type.EmptyTypes, null);
|
||||||
|
if (constructor is not null)
|
||||||
|
{
|
||||||
|
_value = Activator.CreateInstance<T>();
|
||||||
|
}
|
||||||
|
}
|
||||||
public Action<T, T> OnValueChanged { get; set; }
|
public Action<T, T> OnValueChanged { get; set; }
|
||||||
|
|
||||||
public T Value
|
public T Value
|
||||||
|
@ -27,7 +43,7 @@ namespace BITKit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private T _value = typeof(T) == typeof(string) ? string.Empty.As<T>() : Activator.CreateInstance<T>();
|
private T _value;
|
||||||
public object Obj
|
public object Obj
|
||||||
{
|
{
|
||||||
get => Value;
|
get => Value;
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
using System;
|
using System;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Unity.Mathematics;
|
using Unity.Mathematics;
|
||||||
|
using YamlDotNet.Core;
|
||||||
|
using YamlDotNet.Serialization;
|
||||||
|
|
||||||
#if NET5_0_OR_GREATER
|
#if NET5_0_OR_GREATER
|
||||||
namespace BITKit
|
namespace BITKit
|
||||||
|
@ -190,4 +192,4 @@ namespace BITKit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"reference": "GUID:14fe60d984bf9f84eac55c6ea033a8f4"
|
||||||
|
}
|
|
@ -1,7 +1,6 @@
|
||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 2da90b0890b24e644a1900960dc2fb9c
|
guid: 28ed10548f6aa6944ab6ac01ce4f9faf
|
||||||
folderAsset: yes
|
AssemblyDefinitionReferenceImporter:
|
||||||
DefaultImporter:
|
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
userData:
|
userData:
|
||||||
assetBundleName:
|
assetBundleName:
|
|
@ -0,0 +1,109 @@
|
||||||
|
using System;
|
||||||
|
using YamlDotNet.Core;
|
||||||
|
using YamlDotNet.Core.Events;
|
||||||
|
using YamlDotNet.Serialization;
|
||||||
|
using Unity.Mathematics;
|
||||||
|
|
||||||
|
namespace BITKit
|
||||||
|
{
|
||||||
|
public class UnityMathematicsYamlConverters : IYamlTypeConverter
|
||||||
|
{
|
||||||
|
public bool Accepts(Type type)
|
||||||
|
{
|
||||||
|
return type == typeof(int2) || type == typeof(int3) || type == typeof(int4) ||
|
||||||
|
type == typeof(float2) || type == typeof(float3) || type == typeof(float4) ||
|
||||||
|
type == typeof(quaternion);
|
||||||
|
}
|
||||||
|
|
||||||
|
public object ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer)
|
||||||
|
{
|
||||||
|
var scalar = parser.Consume<Scalar>();
|
||||||
|
var parts = scalar.Value.Split(',');
|
||||||
|
|
||||||
|
if (type == typeof(int2))
|
||||||
|
{
|
||||||
|
if (parts.Length != 2) throw new YamlException(scalar.Start, scalar.End, "Expected 2 int values for int2.");
|
||||||
|
return new int2(int.Parse(parts[0]), int.Parse(parts[1]));
|
||||||
|
}
|
||||||
|
else if (type == typeof(int3))
|
||||||
|
{
|
||||||
|
if (parts.Length != 3) throw new YamlException(scalar.Start, scalar.End, "Expected 3 int values for int3.");
|
||||||
|
return new int3(int.Parse(parts[0]), int.Parse(parts[1]), int.Parse(parts[2]));
|
||||||
|
}
|
||||||
|
else if (type == typeof(int4))
|
||||||
|
{
|
||||||
|
if (parts.Length != 4) throw new YamlException(scalar.Start, scalar.End, "Expected 4 int values for int4.");
|
||||||
|
return new int4(int.Parse(parts[0]), int.Parse(parts[1]), int.Parse(parts[2]), int.Parse(parts[3]));
|
||||||
|
}
|
||||||
|
else if (type == typeof(float2))
|
||||||
|
{
|
||||||
|
if (parts.Length != 2) throw new YamlException(scalar.Start, scalar.End, "Expected 2 float values for float2.");
|
||||||
|
return new float2(float.Parse(parts[0]), float.Parse(parts[1]));
|
||||||
|
}
|
||||||
|
else if (type == typeof(float3))
|
||||||
|
{
|
||||||
|
if (parts.Length != 3) throw new YamlException(scalar.Start, scalar.End, "Expected 3 float values for float3.");
|
||||||
|
return new float3(float.Parse(parts[0]), float.Parse(parts[1]), float.Parse(parts[2]));
|
||||||
|
}
|
||||||
|
else if (type == typeof(float4))
|
||||||
|
{
|
||||||
|
if (parts.Length != 4) throw new YamlException(scalar.Start, scalar.End, "Expected 4 float values for float4.");
|
||||||
|
return new float4(float.Parse(parts[0]), float.Parse(parts[1]), float.Parse(parts[2]), float.Parse(parts[3]));
|
||||||
|
}
|
||||||
|
else if (type == typeof(quaternion))
|
||||||
|
{
|
||||||
|
if (parts.Length != 4) throw new YamlException(scalar.Start, scalar.End, "Expected 4 float values for quaternion.");
|
||||||
|
return new quaternion(float.Parse(parts[0]), float.Parse(parts[1]), float.Parse(parts[2]), float.Parse(parts[3]));
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new YamlException(scalar.Start, scalar.End, $"Unsupported type: {type}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteYaml(IEmitter emitter, object value, Type type, ObjectSerializer serializer)
|
||||||
|
{
|
||||||
|
string scalarValue = "";
|
||||||
|
|
||||||
|
if (type == typeof(int2))
|
||||||
|
{
|
||||||
|
var int2Value = (int2)value;
|
||||||
|
scalarValue = $"{int2Value.x},{int2Value.y}";
|
||||||
|
}
|
||||||
|
else if (type == typeof(int3))
|
||||||
|
{
|
||||||
|
var int3Value = (int3)value;
|
||||||
|
scalarValue = $"{int3Value.x},{int3Value.y},{int3Value.z}";
|
||||||
|
}
|
||||||
|
else if (type == typeof(int4))
|
||||||
|
{
|
||||||
|
var int4Value = (int4)value;
|
||||||
|
scalarValue = $"{int4Value.x},{int4Value.y},{int4Value.z},{int4Value.w}";
|
||||||
|
}
|
||||||
|
else if (type == typeof(float2))
|
||||||
|
{
|
||||||
|
var float2Value = (float2)value;
|
||||||
|
scalarValue = $"{float2Value.x},{float2Value.y}";
|
||||||
|
}
|
||||||
|
else if (type == typeof(float3))
|
||||||
|
{
|
||||||
|
var float3Value = (float3)value;
|
||||||
|
scalarValue = $"{float3Value.x},{float3Value.y},{float3Value.z}";
|
||||||
|
}
|
||||||
|
else if (type == typeof(float4))
|
||||||
|
{
|
||||||
|
var float4Value = (float4)value;
|
||||||
|
scalarValue = $"{float4Value.x},{float4Value.y},{float4Value.z},{float4Value.w}";
|
||||||
|
}
|
||||||
|
else if (type == typeof(quaternion))
|
||||||
|
{
|
||||||
|
var quaternionValue = (quaternion)value;
|
||||||
|
scalarValue = $"{quaternionValue.value.x},{quaternionValue.value.y},{quaternionValue.value.z},{quaternionValue.value.w}";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new YamlException($"Unsupported type: {type}");
|
||||||
|
}
|
||||||
|
|
||||||
|
emitter.Emit(new Scalar(scalarValue));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 16ca25bd5fef10847aec8081266207e1
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"reference": "GUID:14fe60d984bf9f84eac55c6ea033a8f4"
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: d31ceb431a775db4a8757a1208d82106
|
||||||
|
AssemblyDefinitionReferenceImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
|
@ -36,7 +36,7 @@
|
||||||
"name": "Crouch",
|
"name": "Crouch",
|
||||||
"type": "Button",
|
"type": "Button",
|
||||||
"id": "eab8ff36-98a9-4a2d-8393-167d9347227b",
|
"id": "eab8ff36-98a9-4a2d-8393-167d9347227b",
|
||||||
"expectedControlType": "Button",
|
"expectedControlType": "",
|
||||||
"processors": "",
|
"processors": "",
|
||||||
"interactions": "Press,Tap",
|
"interactions": "Press,Tap",
|
||||||
"initialStateCheck": false
|
"initialStateCheck": false
|
||||||
|
@ -45,7 +45,7 @@
|
||||||
"name": "Crawl",
|
"name": "Crawl",
|
||||||
"type": "Button",
|
"type": "Button",
|
||||||
"id": "350ae177-bf96-40b1-aff0-e10865947df9",
|
"id": "350ae177-bf96-40b1-aff0-e10865947df9",
|
||||||
"expectedControlType": "Button",
|
"expectedControlType": "",
|
||||||
"processors": "",
|
"processors": "",
|
||||||
"interactions": "",
|
"interactions": "",
|
||||||
"initialStateCheck": false
|
"initialStateCheck": false
|
||||||
|
@ -54,7 +54,7 @@
|
||||||
"name": "HoldCrouch",
|
"name": "HoldCrouch",
|
||||||
"type": "Button",
|
"type": "Button",
|
||||||
"id": "07dfe885-d709-4482-9686-57f671b1aed6",
|
"id": "07dfe885-d709-4482-9686-57f671b1aed6",
|
||||||
"expectedControlType": "Button",
|
"expectedControlType": "",
|
||||||
"processors": "",
|
"processors": "",
|
||||||
"interactions": "Press",
|
"interactions": "Press",
|
||||||
"initialStateCheck": false
|
"initialStateCheck": false
|
||||||
|
@ -63,7 +63,7 @@
|
||||||
"name": "Fire",
|
"name": "Fire",
|
||||||
"type": "Button",
|
"type": "Button",
|
||||||
"id": "9db494c5-bec3-4b09-bd5f-66ba07a3a729",
|
"id": "9db494c5-bec3-4b09-bd5f-66ba07a3a729",
|
||||||
"expectedControlType": "Button",
|
"expectedControlType": "",
|
||||||
"processors": "",
|
"processors": "",
|
||||||
"interactions": "Press,Tap,Hold",
|
"interactions": "Press,Tap,Hold",
|
||||||
"initialStateCheck": false
|
"initialStateCheck": false
|
||||||
|
@ -81,7 +81,7 @@
|
||||||
"name": "Interactive",
|
"name": "Interactive",
|
||||||
"type": "Button",
|
"type": "Button",
|
||||||
"id": "9b32c7f1-0553-4735-b0f9-7726d59808ca",
|
"id": "9b32c7f1-0553-4735-b0f9-7726d59808ca",
|
||||||
"expectedControlType": "Button",
|
"expectedControlType": "",
|
||||||
"processors": "",
|
"processors": "",
|
||||||
"interactions": "Press,Hold",
|
"interactions": "Press,Hold",
|
||||||
"initialStateCheck": false
|
"initialStateCheck": false
|
||||||
|
@ -90,7 +90,7 @@
|
||||||
"name": "Melee",
|
"name": "Melee",
|
||||||
"type": "Button",
|
"type": "Button",
|
||||||
"id": "0afd994b-f97e-4198-8700-5f570d3b7b56",
|
"id": "0afd994b-f97e-4198-8700-5f570d3b7b56",
|
||||||
"expectedControlType": "Button",
|
"expectedControlType": "",
|
||||||
"processors": "",
|
"processors": "",
|
||||||
"interactions": "",
|
"interactions": "",
|
||||||
"initialStateCheck": false
|
"initialStateCheck": false
|
||||||
|
@ -99,7 +99,7 @@
|
||||||
"name": "Run",
|
"name": "Run",
|
||||||
"type": "Button",
|
"type": "Button",
|
||||||
"id": "95bba0fe-8e29-470a-a7ef-126b21ea4b5c",
|
"id": "95bba0fe-8e29-470a-a7ef-126b21ea4b5c",
|
||||||
"expectedControlType": "Button",
|
"expectedControlType": "",
|
||||||
"processors": "",
|
"processors": "",
|
||||||
"interactions": "Press,MultiTap",
|
"interactions": "Press,MultiTap",
|
||||||
"initialStateCheck": false
|
"initialStateCheck": false
|
||||||
|
@ -108,7 +108,7 @@
|
||||||
"name": "Reload",
|
"name": "Reload",
|
||||||
"type": "Button",
|
"type": "Button",
|
||||||
"id": "53f6beb0-aeec-43f0-aa36-f4d54f068d75",
|
"id": "53f6beb0-aeec-43f0-aa36-f4d54f068d75",
|
||||||
"expectedControlType": "Button",
|
"expectedControlType": "",
|
||||||
"processors": "",
|
"processors": "",
|
||||||
"interactions": "",
|
"interactions": "",
|
||||||
"initialStateCheck": false
|
"initialStateCheck": false
|
||||||
|
@ -234,7 +234,7 @@
|
||||||
"name": "ToggleCamera",
|
"name": "ToggleCamera",
|
||||||
"type": "Button",
|
"type": "Button",
|
||||||
"id": "a207eefa-8338-4ae0-95a1-8f650a3db235",
|
"id": "a207eefa-8338-4ae0-95a1-8f650a3db235",
|
||||||
"expectedControlType": "Button",
|
"expectedControlType": "",
|
||||||
"processors": "",
|
"processors": "",
|
||||||
"interactions": "Press",
|
"interactions": "Press",
|
||||||
"initialStateCheck": false
|
"initialStateCheck": false
|
||||||
|
@ -272,6 +272,17 @@
|
||||||
"isComposite": false,
|
"isComposite": false,
|
||||||
"isPartOfComposite": false
|
"isPartOfComposite": false
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"id": "bcc014bd-8bca-4b71-96b9-62fa63db2d17",
|
||||||
|
"path": "<Pointer>/delta",
|
||||||
|
"interactions": "",
|
||||||
|
"processors": "",
|
||||||
|
"groups": "",
|
||||||
|
"action": "View",
|
||||||
|
"isComposite": false,
|
||||||
|
"isPartOfComposite": false
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "",
|
"name": "",
|
||||||
"id": "3204e30b-6062-47f0-9af6-e72db104c7ec",
|
"id": "3204e30b-6062-47f0-9af6-e72db104c7ec",
|
||||||
|
@ -283,6 +294,17 @@
|
||||||
"isComposite": false,
|
"isComposite": false,
|
||||||
"isPartOfComposite": false
|
"isPartOfComposite": false
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"id": "88f9f36f-9b75-44a7-9176-b07a7daee4ab",
|
||||||
|
"path": "<XInputController>/buttonSouth",
|
||||||
|
"interactions": "",
|
||||||
|
"processors": "",
|
||||||
|
"groups": "",
|
||||||
|
"action": "Jump",
|
||||||
|
"isComposite": false,
|
||||||
|
"isPartOfComposite": false
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "",
|
"name": "",
|
||||||
"id": "c6f71c75-cb44-418b-9dc0-4202757d20ad",
|
"id": "c6f71c75-cb44-418b-9dc0-4202757d20ad",
|
||||||
|
@ -294,6 +316,17 @@
|
||||||
"isComposite": false,
|
"isComposite": false,
|
||||||
"isPartOfComposite": false
|
"isPartOfComposite": false
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"id": "2560f543-52ea-48c4-a2f6-df8b9deef518",
|
||||||
|
"path": "<XInputController>/buttonEast",
|
||||||
|
"interactions": "",
|
||||||
|
"processors": "",
|
||||||
|
"groups": "",
|
||||||
|
"action": "Crouch",
|
||||||
|
"isComposite": false,
|
||||||
|
"isPartOfComposite": false
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "",
|
"name": "",
|
||||||
"id": "ad8529d0-2894-4cb2-aea4-f07f96251032",
|
"id": "ad8529d0-2894-4cb2-aea4-f07f96251032",
|
||||||
|
@ -316,6 +349,17 @@
|
||||||
"isComposite": false,
|
"isComposite": false,
|
||||||
"isPartOfComposite": false
|
"isPartOfComposite": false
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"id": "d158c65a-e04f-4a62-a576-d13796c3d903",
|
||||||
|
"path": "<Gamepad>/rightTrigger",
|
||||||
|
"interactions": "",
|
||||||
|
"processors": "",
|
||||||
|
"groups": "",
|
||||||
|
"action": "Fire",
|
||||||
|
"isComposite": false,
|
||||||
|
"isPartOfComposite": false
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "",
|
"name": "",
|
||||||
"id": "05431a8a-4464-49e0-8a15-eec2a4351985",
|
"id": "05431a8a-4464-49e0-8a15-eec2a4351985",
|
||||||
|
@ -327,6 +371,17 @@
|
||||||
"isComposite": false,
|
"isComposite": false,
|
||||||
"isPartOfComposite": false
|
"isPartOfComposite": false
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"id": "fce3a9d9-2f96-4a18-bc01-4f6a61f66e59",
|
||||||
|
"path": "<Gamepad>/leftTrigger",
|
||||||
|
"interactions": "",
|
||||||
|
"processors": "",
|
||||||
|
"groups": "",
|
||||||
|
"action": "Aim",
|
||||||
|
"isComposite": false,
|
||||||
|
"isPartOfComposite": false
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "",
|
"name": "",
|
||||||
"id": "9a305ecb-00ee-46fb-be5b-f58125ac34eb",
|
"id": "9a305ecb-00ee-46fb-be5b-f58125ac34eb",
|
||||||
|
@ -338,6 +393,17 @@
|
||||||
"isComposite": false,
|
"isComposite": false,
|
||||||
"isPartOfComposite": false
|
"isPartOfComposite": false
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"id": "9a2d7939-d112-4796-a50f-7e723cb0ebb4",
|
||||||
|
"path": "<XInputController>/rightStickPress",
|
||||||
|
"interactions": "",
|
||||||
|
"processors": "",
|
||||||
|
"groups": "",
|
||||||
|
"action": "Melee",
|
||||||
|
"isComposite": false,
|
||||||
|
"isPartOfComposite": false
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "2D Vector",
|
"name": "2D Vector",
|
||||||
"id": "f2793bde-975d-41cf-b721-4ea21c2cfe7d",
|
"id": "f2793bde-975d-41cf-b721-4ea21c2cfe7d",
|
||||||
|
@ -415,6 +481,17 @@
|
||||||
"isComposite": false,
|
"isComposite": false,
|
||||||
"isPartOfComposite": false
|
"isPartOfComposite": false
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"id": "7475328b-a74c-4c33-90ad-0a59351a3595",
|
||||||
|
"path": "<XInputController>/leftStickPress",
|
||||||
|
"interactions": "",
|
||||||
|
"processors": "",
|
||||||
|
"groups": "",
|
||||||
|
"action": "Run",
|
||||||
|
"isComposite": false,
|
||||||
|
"isPartOfComposite": false
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "",
|
"name": "",
|
||||||
"id": "b8ca7195-54e8-472e-9849-378ea8b1b2d4",
|
"id": "b8ca7195-54e8-472e-9849-378ea8b1b2d4",
|
||||||
|
@ -536,6 +613,17 @@
|
||||||
"isComposite": false,
|
"isComposite": false,
|
||||||
"isPartOfComposite": false
|
"isPartOfComposite": false
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"id": "fa054fa0-fc44-4096-a9df-ea3e6cae27f3",
|
||||||
|
"path": "<XInputController>/buttonWest",
|
||||||
|
"interactions": "",
|
||||||
|
"processors": "",
|
||||||
|
"groups": "",
|
||||||
|
"action": "Interactive",
|
||||||
|
"isComposite": false,
|
||||||
|
"isPartOfComposite": false
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "",
|
"name": "",
|
||||||
"id": "abfe62ef-1678-40c6-85e4-7644a3ffffc3",
|
"id": "abfe62ef-1678-40c6-85e4-7644a3ffffc3",
|
||||||
|
@ -547,6 +635,17 @@
|
||||||
"isComposite": false,
|
"isComposite": false,
|
||||||
"isPartOfComposite": false
|
"isPartOfComposite": false
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"id": "ccb765ab-4913-467a-9b10-c66f7b1b836c",
|
||||||
|
"path": "<XInputController>/buttonWest",
|
||||||
|
"interactions": "Hold",
|
||||||
|
"processors": "",
|
||||||
|
"groups": "",
|
||||||
|
"action": "Reload",
|
||||||
|
"isComposite": false,
|
||||||
|
"isPartOfComposite": false
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "",
|
"name": "",
|
||||||
"id": "c354e7ce-0648-4b49-b042-1f7dfc7657d9",
|
"id": "c354e7ce-0648-4b49-b042-1f7dfc7657d9",
|
||||||
|
@ -591,6 +690,17 @@
|
||||||
"isComposite": false,
|
"isComposite": false,
|
||||||
"isPartOfComposite": false
|
"isPartOfComposite": false
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"id": "438f83aa-f2a6-4d51-84a2-c6b334924fb0",
|
||||||
|
"path": "<XInputController>/select",
|
||||||
|
"interactions": "",
|
||||||
|
"processors": "",
|
||||||
|
"groups": "",
|
||||||
|
"action": "ToggleCamera",
|
||||||
|
"isComposite": false,
|
||||||
|
"isPartOfComposite": false
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "",
|
"name": "",
|
||||||
"id": "c7bf69ae-febf-4280-b153-d529229f82b5",
|
"id": "c7bf69ae-febf-4280-b153-d529229f82b5",
|
||||||
|
@ -686,7 +796,7 @@
|
||||||
"name": "Cancel",
|
"name": "Cancel",
|
||||||
"type": "Button",
|
"type": "Button",
|
||||||
"id": "60dfbf31-4ec8-4df1-be35-9f1eca07d7be",
|
"id": "60dfbf31-4ec8-4df1-be35-9f1eca07d7be",
|
||||||
"expectedControlType": "Button",
|
"expectedControlType": "",
|
||||||
"processors": "",
|
"processors": "",
|
||||||
"interactions": "Press,Hold,Tap",
|
"interactions": "Press,Hold,Tap",
|
||||||
"initialStateCheck": false
|
"initialStateCheck": false
|
||||||
|
@ -713,7 +823,7 @@
|
||||||
"name": "Inventory",
|
"name": "Inventory",
|
||||||
"type": "Button",
|
"type": "Button",
|
||||||
"id": "80289a66-dc26-4d9e-967d-a561bb8794e3",
|
"id": "80289a66-dc26-4d9e-967d-a561bb8794e3",
|
||||||
"expectedControlType": "Button",
|
"expectedControlType": "",
|
||||||
"processors": "",
|
"processors": "",
|
||||||
"interactions": "Press,Hold",
|
"interactions": "Press,Hold",
|
||||||
"initialStateCheck": false
|
"initialStateCheck": false
|
||||||
|
@ -740,6 +850,17 @@
|
||||||
"isComposite": false,
|
"isComposite": false,
|
||||||
"isPartOfComposite": false
|
"isPartOfComposite": false
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"id": "16cf3841-290b-4e38-9b3f-71d4a5428c70",
|
||||||
|
"path": "<Gamepad>/leftStick",
|
||||||
|
"interactions": "",
|
||||||
|
"processors": "",
|
||||||
|
"groups": "",
|
||||||
|
"action": "Point",
|
||||||
|
"isComposite": false,
|
||||||
|
"isPartOfComposite": false
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "",
|
"name": "",
|
||||||
"id": "39028ab4-2f9f-43b2-99f6-6689cbc29e17",
|
"id": "39028ab4-2f9f-43b2-99f6-6689cbc29e17",
|
||||||
|
@ -817,6 +938,50 @@
|
||||||
"isComposite": false,
|
"isComposite": false,
|
||||||
"isPartOfComposite": false
|
"isPartOfComposite": false
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"id": "c65bdae3-6e08-4931-b364-738eb5248f5c",
|
||||||
|
"path": "<Gamepad>/start",
|
||||||
|
"interactions": "",
|
||||||
|
"processors": "",
|
||||||
|
"groups": "",
|
||||||
|
"action": "Cancel",
|
||||||
|
"isComposite": false,
|
||||||
|
"isPartOfComposite": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"id": "e610040c-2163-48b0-892a-d17c525b4763",
|
||||||
|
"path": "<VirtualMouse>/{Cancel}",
|
||||||
|
"interactions": "",
|
||||||
|
"processors": "",
|
||||||
|
"groups": "",
|
||||||
|
"action": "Cancel",
|
||||||
|
"isComposite": false,
|
||||||
|
"isPartOfComposite": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"id": "835f92ac-0a3f-495c-a09b-694b13942d96",
|
||||||
|
"path": "<Touchscreen>/{Cancel}",
|
||||||
|
"interactions": "",
|
||||||
|
"processors": "",
|
||||||
|
"groups": "",
|
||||||
|
"action": "Cancel",
|
||||||
|
"isComposite": false,
|
||||||
|
"isPartOfComposite": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"id": "a490bb73-90bd-4cd2-b702-cd89bc1987d4",
|
||||||
|
"path": "<Pointer>/{Cancel}",
|
||||||
|
"interactions": "",
|
||||||
|
"processors": "",
|
||||||
|
"groups": "",
|
||||||
|
"action": "Cancel",
|
||||||
|
"isComposite": false,
|
||||||
|
"isPartOfComposite": false
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "",
|
"name": "",
|
||||||
"id": "5f7a54af-6a1b-4e69-8a46-57a6772019cc",
|
"id": "5f7a54af-6a1b-4e69-8a46-57a6772019cc",
|
||||||
|
@ -850,6 +1015,17 @@
|
||||||
"isComposite": false,
|
"isComposite": false,
|
||||||
"isPartOfComposite": false
|
"isPartOfComposite": false
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"id": "6f51a8c8-9f11-40d5-a0b9-3a78dde74a22",
|
||||||
|
"path": "<Gamepad>/dpad/up",
|
||||||
|
"interactions": "",
|
||||||
|
"processors": "",
|
||||||
|
"groups": "",
|
||||||
|
"action": "Inventory",
|
||||||
|
"isComposite": false,
|
||||||
|
"isPartOfComposite": false
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "WASD",
|
"name": "WASD",
|
||||||
"id": "a40b1b7f-8cb3-4138-80a0-ec2771a2481a",
|
"id": "a40b1b7f-8cb3-4138-80a0-ec2771a2481a",
|
||||||
|
@ -981,7 +1157,7 @@
|
||||||
"name": "Vertical",
|
"name": "Vertical",
|
||||||
"type": "Button",
|
"type": "Button",
|
||||||
"id": "5703bb8a-1107-4f73-91fa-9bbc362d9528",
|
"id": "5703bb8a-1107-4f73-91fa-9bbc362d9528",
|
||||||
"expectedControlType": "Button",
|
"expectedControlType": "",
|
||||||
"processors": "",
|
"processors": "",
|
||||||
"interactions": "",
|
"interactions": "",
|
||||||
"initialStateCheck": false
|
"initialStateCheck": false
|
||||||
|
@ -1093,7 +1269,7 @@
|
||||||
"name": "AscendAndDescend",
|
"name": "AscendAndDescend",
|
||||||
"type": "Button",
|
"type": "Button",
|
||||||
"id": "a78acdb6-b9dd-4d90-a89e-58fb62647380",
|
"id": "a78acdb6-b9dd-4d90-a89e-58fb62647380",
|
||||||
"expectedControlType": "Button",
|
"expectedControlType": "",
|
||||||
"processors": "",
|
"processors": "",
|
||||||
"interactions": "",
|
"interactions": "",
|
||||||
"initialStateCheck": false
|
"initialStateCheck": false
|
||||||
|
@ -1309,7 +1485,7 @@
|
||||||
"name": "Vertical",
|
"name": "Vertical",
|
||||||
"type": "Button",
|
"type": "Button",
|
||||||
"id": "cc774816-362e-40d3-98c5-19411a7ae97a",
|
"id": "cc774816-362e-40d3-98c5-19411a7ae97a",
|
||||||
"expectedControlType": "Button",
|
"expectedControlType": "",
|
||||||
"processors": "",
|
"processors": "",
|
||||||
"interactions": "",
|
"interactions": "",
|
||||||
"initialStateCheck": false
|
"initialStateCheck": false
|
||||||
|
|
|
@ -6,7 +6,6 @@ using System.IO;
|
||||||
using BITKit.IO;
|
using BITKit.IO;
|
||||||
using BITKit.UX;
|
using BITKit.UX;
|
||||||
using Cysharp.Threading.Tasks;
|
using Cysharp.Threading.Tasks;
|
||||||
using UnityEditorInternal;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.Events;
|
using UnityEngine.Events;
|
||||||
using UnityEngine.Rendering;
|
using UnityEngine.Rendering;
|
||||||
|
@ -26,9 +25,11 @@ namespace BITKit
|
||||||
private static void Reload()
|
private static void Reload()
|
||||||
{
|
{
|
||||||
Stopwatch = new Stopwatch();
|
Stopwatch = new Stopwatch();
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
|
|
||||||
#else
|
#else
|
||||||
SplashScreen.Stop(SplashScreen.StopBehavior.StopImmediate);
|
SplashScreen.Stop(SplashScreen.StopBehavior.StopImmediate);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using BITKit.Entities;
|
||||||
|
using BITKit.Mod;
|
||||||
|
using Cysharp.Threading.Tasks;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using UnityEngine;
|
||||||
|
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
||||||
|
|
||||||
|
namespace BITKit.IO
|
||||||
|
{
|
||||||
|
public class ScriptableEntitiesService : IDisposable
|
||||||
|
{
|
||||||
|
private readonly IEntitiesService _entitiesService;
|
||||||
|
|
||||||
|
public string Tags = "scriptable_object";
|
||||||
|
|
||||||
|
private readonly List<IEntity> _registeredEntities = new();
|
||||||
|
|
||||||
|
public ScriptableEntitiesService(IEntitiesService entitiesService)
|
||||||
|
{
|
||||||
|
_entitiesService = entitiesService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async UniTask InitializeAsync(ILogger logger = null)
|
||||||
|
{
|
||||||
|
logger?.LogInformation("正在查找所有ScriptableObject...");
|
||||||
|
var objs = await ModService.LoadAssets<ScriptableObject>(Tags);
|
||||||
|
logger?.LogInformation($"找到{objs.Count}个资源,正在加载中...");
|
||||||
|
for (var index = 0; index < objs.Count; index++)
|
||||||
|
{
|
||||||
|
var scriptableObject = objs[index];
|
||||||
|
var entity = new Entity();
|
||||||
|
|
||||||
|
var idComponent = new IdComponent();
|
||||||
|
|
||||||
|
entity.ServiceCollection.AddSingleton(idComponent);
|
||||||
|
|
||||||
|
var type = scriptableObject.GetType();
|
||||||
|
|
||||||
|
entity.ServiceCollection.AddSingleton(type, scriptableObject);
|
||||||
|
|
||||||
|
_entitiesService.Register(entity);
|
||||||
|
|
||||||
|
logger?.LogInformation($"已加载:{scriptableObject.name}:{type.Name},剩余:{index + 1}/{objs.Count}");
|
||||||
|
_registeredEntities.Add(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
logger?.LogInformation("加载完成");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
foreach (var x in _registeredEntities)
|
||||||
|
{
|
||||||
|
_entitiesService.UnRegister(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
_registeredEntities.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e1ff18f234ca249459fb3df556f90b11
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
|
@ -1,30 +1,165 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing.Printing;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using BITKit.Mod;
|
using BITKit.Mod;
|
||||||
using Cysharp.Threading.Tasks;
|
using Cysharp.Threading.Tasks;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using UnityEditor;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using YooAsset;
|
using YooAsset;
|
||||||
|
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
||||||
using Object = UnityEngine.Object;
|
using Object = UnityEngine.Object;
|
||||||
|
|
||||||
namespace BITKit.IO
|
namespace BITKit.IO
|
||||||
{
|
{
|
||||||
public class YooAssetModHelper : MonoBehaviour
|
public class YooAssetModHelper
|
||||||
{
|
{
|
||||||
private void OnEnable()
|
public static string Url = "http://server.bitfall.icu:21982/com.project.b/Mods";
|
||||||
|
public static readonly ConcurrentDictionary<string, HashSet<string>> PackagesManifestDictionary = new();
|
||||||
|
public static async UniTask LoadMods(ILogger logger=null)
|
||||||
{
|
{
|
||||||
ModService.LoadAssetAsyncFactory += LoadAsset;
|
try
|
||||||
|
{
|
||||||
|
var modPath = Path.Combine(Environment.CurrentDirectory, "Mods");
|
||||||
|
|
||||||
|
if (Application.platform is RuntimePlatform.Android)
|
||||||
|
{
|
||||||
|
modPath = Path.Combine($"/storage/emulated/0/{Application.identifier}/Mods/");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
foreach (var directoryInfo in new DirectoryInfo(modPath).GetDirectories())
|
||||||
|
{
|
||||||
|
var packageName = directoryInfo.Name;
|
||||||
|
|
||||||
|
logger?.LogInformation($"开始加载:{packageName}");
|
||||||
|
|
||||||
|
var package = YooAssets.CreatePackage(packageName);
|
||||||
|
|
||||||
|
|
||||||
|
var initPars = new HostPlayModeParameters()
|
||||||
|
{
|
||||||
|
BuildinQueryServices = new GameQueryServices(),
|
||||||
|
RemoteServices = new RemoteServices($"{Url}/{directoryInfo.Name}",$"file://{directoryInfo.FullName}")
|
||||||
|
};
|
||||||
|
|
||||||
|
await package.InitializeAsync(initPars);
|
||||||
|
|
||||||
|
var update = package.UpdatePackageVersionAsync();
|
||||||
|
await update.ToUniTask();
|
||||||
|
|
||||||
|
var manifest = package.UpdatePackageManifestAsync(update.PackageVersion);
|
||||||
|
await manifest.ToUniTask();
|
||||||
|
|
||||||
|
var downloader = package.CreateResourceDownloader(10, 3);
|
||||||
|
|
||||||
|
if (logger is not null)
|
||||||
|
{
|
||||||
|
downloader.OnDownloadProgressCallback = (totalDownloadCount, currentDownloadCount,
|
||||||
|
totalDownloadBytes, currentDownloadBytes) =>
|
||||||
|
{
|
||||||
|
//下载进度
|
||||||
|
var progress = (float)currentDownloadBytes / totalDownloadBytes;
|
||||||
|
logger.LogInformation($"已下载{(int)(progress*100)}%,资源数量{currentDownloadBytes}/{totalDownloadBytes}");
|
||||||
|
};
|
||||||
|
downloader.OnDownloadErrorCallback = (fileName, error) =>
|
||||||
|
{
|
||||||
|
logger.LogError($"资源[{fileName}]下载错误::{error}");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
downloader.BeginDownload();
|
||||||
|
|
||||||
|
await downloader.ToUniTask();
|
||||||
|
|
||||||
|
var mod = new MyMod()
|
||||||
|
{
|
||||||
|
FolderPath = directoryInfo.FullName,
|
||||||
|
PackageName = packageName,
|
||||||
|
Name = packageName
|
||||||
|
};
|
||||||
|
|
||||||
|
await ModService.Install(mod);
|
||||||
|
await ModService.Load(mod);
|
||||||
|
|
||||||
|
YooAssetUtils.RegisterResourcePackage(package);
|
||||||
|
|
||||||
|
logger?.LogInformation($"已加载:{packageName},路径:{directoryInfo.FullName}");
|
||||||
|
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
if (logger is not null)
|
||||||
|
{
|
||||||
|
logger.LogCritical(e.Message,e);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BIT4Log.LogException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger?.LogInformation($"未找到Mod");
|
||||||
}
|
}
|
||||||
private void OnDisable()
|
|
||||||
|
private static HashSet<string> BuildPackageCache(string obj)
|
||||||
{
|
{
|
||||||
ModService.LoadAssetAsyncFactory -= LoadAsset;
|
var package = YooAssets.GetPackage(obj);
|
||||||
|
var playMode = package.GetType().GetField("_playModeImpl", ReflectionHelper.Flags)!.GetValue(package);
|
||||||
|
var manifest = playMode.GetType().GetProperty("ActiveManifest", ReflectionHelper.Flags)!.GetValue(playMode);
|
||||||
|
var dictionary = manifest.GetType().GetField("AssetDic", ReflectionHelper.Flags)!.GetValue(manifest) as IDictionary;
|
||||||
|
|
||||||
|
var hashset = new HashSet<string>();
|
||||||
|
|
||||||
|
foreach (var key in dictionary.Keys)
|
||||||
|
{
|
||||||
|
hashset.Add(key?.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
var assetPathMapping1=manifest.GetType().GetField("AssetPathMapping1", ReflectionHelper.Flags)!.GetValue(manifest) as IDictionary<string,string>;
|
||||||
|
|
||||||
|
foreach (var key in assetPathMapping1.Keys)
|
||||||
|
{
|
||||||
|
hashset.Add(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
return hashset;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async UniTask<object> LoadAsset(string arg)
|
public static async UniTask<IReadOnlyList<object>> LoadAssets( string[] arg)
|
||||||
{
|
{
|
||||||
var handle = YooAssets.LoadAssetAsync(arg);
|
var list = new List<object>();
|
||||||
await handle;
|
foreach (var resourcePackage in YooAssetUtils.RegisteredResourcePackages)
|
||||||
return handle.AssetObject;
|
{
|
||||||
|
foreach (var assetInfo in resourcePackage.GetAssetInfos(arg))
|
||||||
|
{
|
||||||
|
var asyncHandle = resourcePackage.LoadAssetAsync(assetInfo);
|
||||||
|
await asyncHandle;
|
||||||
|
list.Add(asyncHandle.AssetObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async UniTask<object> LoadAsset(string arg)
|
||||||
|
{
|
||||||
|
foreach (var resourcePackage in YooAssetUtils.RegisteredResourcePackages.Reverse())
|
||||||
|
{
|
||||||
|
if(PackagesManifestDictionary.GetOrAdd(resourcePackage.PackageName,BuildPackageCache).Contains(arg) is false)continue;
|
||||||
|
|
||||||
|
var assetInfo = resourcePackage.GetAssetInfo(arg);
|
||||||
|
if(string.IsNullOrEmpty(assetInfo.Error) is false)continue;
|
||||||
|
var handle = resourcePackage.LoadAssetAsync(arg);
|
||||||
|
await handle;
|
||||||
|
return handle.AssetObject;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -203,6 +203,14 @@ namespace BITKit
|
||||||
BITApp.Time.DeltaTime = Time.deltaTime;
|
BITApp.Time.DeltaTime = Time.deltaTime;
|
||||||
BITApp.Time.TimeAsDouble = Time.timeAsDouble;
|
BITApp.Time.TimeAsDouble = Time.timeAsDouble;
|
||||||
allowCursor = AllowCursor.Allow;
|
allowCursor = AllowCursor.Allow;
|
||||||
|
|
||||||
|
if (Touchscreen.current is not null && Touchscreen.current.IsPressed())
|
||||||
|
{
|
||||||
|
AllowCursor.AddElement(int.MaxValue);
|
||||||
|
}else if (Mouse.current is not null && Mouse.current.IsPressed())
|
||||||
|
{
|
||||||
|
AllowCursor.RemoveElement(int.MaxValue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetName()
|
public string GetName()
|
||||||
|
|
|
@ -36,6 +36,19 @@ namespace BITKit
|
||||||
action.RegisterCallback(callback);
|
action.RegisterCallback(callback);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public InputActionGroup RegisterCallback(InputAction inputAction,Action<InputAction.CallbackContext> callback)
|
||||||
|
{
|
||||||
|
EnsureConfiguration();
|
||||||
|
|
||||||
|
var action = actions.GetOrAdd(inputAction.name, _=>inputAction.Clone());
|
||||||
|
|
||||||
|
allowInput.Invoke();
|
||||||
|
|
||||||
|
action.RegisterCallback(callback);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public InputAction EnsureCreated(InputActionReference reference)
|
public InputAction EnsureCreated(InputActionReference reference)
|
||||||
{
|
{
|
||||||
|
@ -57,6 +70,20 @@ namespace BITKit
|
||||||
|
|
||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
public InputAction EnsureCreated(InputAction inputAction)
|
||||||
|
{
|
||||||
|
EnsureConfiguration();
|
||||||
|
var action = actions.GetOrAdd(inputAction.name, _ =>
|
||||||
|
{
|
||||||
|
var newAction = inputAction.Clone();
|
||||||
|
newAction.Rename(inputAction.name);
|
||||||
|
return newAction;
|
||||||
|
});
|
||||||
|
|
||||||
|
allowInput.Invoke();
|
||||||
|
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
public void Inherit(InputActionGroup other)
|
public void Inherit(InputActionGroup other)
|
||||||
{
|
{
|
||||||
|
@ -80,6 +107,12 @@ namespace BITKit
|
||||||
action.UnRegisterCallback(callback);
|
action.UnRegisterCallback(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void UnRegisterCallback(InputAction inputAction, Action<InputAction.CallbackContext> callback)
|
||||||
|
{
|
||||||
|
if(actions.TryGetValue(inputAction.name,out var action))
|
||||||
|
action.UnRegisterCallback(callback);
|
||||||
|
}
|
||||||
|
|
||||||
private void EnsureConfiguration()
|
private void EnsureConfiguration()
|
||||||
{
|
{
|
||||||
if (state is not InitializationState.Initialized)
|
if (state is not InitializationState.Initialized)
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using BITKit;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace UnityEngine.InputSystem
|
||||||
|
{
|
||||||
|
public class UnityPlayerInput : MonoBehaviour
|
||||||
|
{
|
||||||
|
private readonly InputActionGroup _inputActionGroup=new();
|
||||||
|
|
||||||
|
[SerializeField] private InputActionAsset inputActionAsset;
|
||||||
|
|
||||||
|
private bool _isInitialized;
|
||||||
|
|
||||||
|
private void Start()
|
||||||
|
{
|
||||||
|
foreach (var inputActionMap in inputActionAsset.actionMaps)
|
||||||
|
{
|
||||||
|
foreach (var inputAction in inputActionMap.actions)
|
||||||
|
{
|
||||||
|
_inputActionGroup.RegisterCallback(inputAction, x =>
|
||||||
|
{
|
||||||
|
SendMessage($"On{inputAction.name}",x,SendMessageOptions.DontRequireReceiver);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_isInitialized is false)
|
||||||
|
{
|
||||||
|
_inputActionGroup.allowInput.AddElement(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
_isInitialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnEnable()
|
||||||
|
{
|
||||||
|
if (_isInitialized)
|
||||||
|
_inputActionGroup.allowInput.AddElement(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDisable()
|
||||||
|
{
|
||||||
|
_inputActionGroup.allowInput.RemoveElement(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 6b2748010e8669a44b12cd163ea95fa2
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
|
@ -1,121 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using BITKit.UX;
|
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
|
||||||
using UnityEditor;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace BITKit.Mod
|
|
||||||
{
|
|
||||||
public class UnityModService : MonoBehaviour
|
|
||||||
{
|
|
||||||
[SerializeReference,SubclassSelector] private IReference[] referencedAssemblies;
|
|
||||||
private async void Start()
|
|
||||||
{
|
|
||||||
//DI.TryGet<IUXWaiting>(out var waiting);
|
|
||||||
IUXWaiting waiting = null;
|
|
||||||
var handle = waiting?.Get();
|
|
||||||
handle?.SetMessage("正在初始化Mod服务");
|
|
||||||
|
|
||||||
if (Application.isEditor is false)
|
|
||||||
{
|
|
||||||
BIT4Log.Log<UnityModService>($"UnityPlayer所在位置:{Application.dataPath}");
|
|
||||||
|
|
||||||
BIT4Log.Log<UnityModService>($"{nameof(System.Linq)}位于{typeof(Enumerable).Assembly.Location}");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
foreach (var x in referencedAssemblies)
|
|
||||||
{
|
|
||||||
var dllName = x.Value.Contains(".dll") ? x.Value : $"{x.Value}.dll";
|
|
||||||
|
|
||||||
if (SearchDll(dllName,out var dll) is false)
|
|
||||||
{
|
|
||||||
BIT4Log.Warning<UnityModService>($"未找到:{dll}");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
BITSharp.ReferencedAssemblies.Add(@$"""{dll}""");
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
ModService.Initialize();
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
BIT4Log.Warning<UnityModService>("初始化失败");
|
|
||||||
BIT4Log.LogException(e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
destroyCancellationToken.Register(ModService.Dispose);
|
|
||||||
|
|
||||||
ModService.OnPackageLoad+=OnPackageLoad;
|
|
||||||
|
|
||||||
|
|
||||||
var packages = await ModService.SearchPackages();
|
|
||||||
if (destroyCancellationToken.IsCancellationRequested) return;
|
|
||||||
foreach (var package in packages)
|
|
||||||
{
|
|
||||||
await ModService.LoadFromPackage(package.PackagePath);
|
|
||||||
if (destroyCancellationToken.IsCancellationRequested) return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
destroyCancellationToken.Register(() =>
|
|
||||||
{
|
|
||||||
ModService.OnPackageLoad-=OnPackageLoad;
|
|
||||||
});
|
|
||||||
|
|
||||||
waiting?.Release(handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnPackageLoad(ModPackage obj)
|
|
||||||
{
|
|
||||||
var loadedDlls = referencedAssemblies.Cast();
|
|
||||||
var reportBuilder = new System.Text.StringBuilder();
|
|
||||||
|
|
||||||
//对比已加载的dll和当前引用的dll
|
|
||||||
foreach (var x in obj.Dlls.Except(loadedDlls))
|
|
||||||
{
|
|
||||||
if (SearchDll(x, out var dll) is false)
|
|
||||||
{
|
|
||||||
BIT4Log.Warning<UnityModService>($"未找到:{dll}");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
BITSharp.ReferencedAssemblies.Add(@$"""{dll}""");
|
|
||||||
reportBuilder.AppendLine($"加载:{dll}");
|
|
||||||
}
|
|
||||||
BIT4Log.Log<UnityModService>(reportBuilder.ToString());
|
|
||||||
}
|
|
||||||
private bool SearchDll(string dllName,out string dll,params string[] moreFolder)
|
|
||||||
{
|
|
||||||
#if UNITY_EDITOR
|
|
||||||
dll = System.IO.Path.Combine(Environment.CurrentDirectory, "Library", "ScriptAssemblies", dllName);
|
|
||||||
var folder = EditorApplication.applicationPath;
|
|
||||||
folder = Path.GetDirectoryName(folder);
|
|
||||||
if(File.Exists(dll) is false)
|
|
||||||
{
|
|
||||||
dll = Path.Combine(folder,"Data", "MonoBleedingEdge", "lib","mono","unityjit-win32",dllName);
|
|
||||||
}
|
|
||||||
if (File.Exists(dll) is false)
|
|
||||||
{
|
|
||||||
dll = Path.Combine(folder,"Data", "MonoBleedingEdge", "lib","mono","unityjit-win32","Facades",dllName);
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
dll = System.IO.Path.Combine(Environment.CurrentDirectory,$"{Application.productName}_Data", "Managed", dllName);
|
|
||||||
#endif
|
|
||||||
return File.Exists(dll);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,48 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using Cysharp.Threading.Tasks;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace BITKit.Mod
|
|
||||||
{
|
|
||||||
public class UnityModServiceTester : MonoBehaviour
|
|
||||||
{
|
|
||||||
[Serializable]
|
|
||||||
public class TestLogGameTickMod:MyMod
|
|
||||||
{
|
|
||||||
public override void OnInitialized()
|
|
||||||
{
|
|
||||||
base.OnInitialized();
|
|
||||||
GameTickService.Add(OnTick);
|
|
||||||
}
|
|
||||||
private static void OnTick(float obj)
|
|
||||||
{
|
|
||||||
BIT4Log.Log<TestLogGameTickMod>($"On Test Mod Tick,delta:{obj}");
|
|
||||||
}
|
|
||||||
public override void OnDispose()
|
|
||||||
{
|
|
||||||
GameTickService.Remove(OnTick);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[SerializeReference, SubclassSelector] private IMod[] initialMods;
|
|
||||||
private void OnEnable()
|
|
||||||
{
|
|
||||||
foreach (var testMod in initialMods)
|
|
||||||
{
|
|
||||||
ModService.Install(testMod);
|
|
||||||
ModService.Load(testMod);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private void OnDisable()
|
|
||||||
{
|
|
||||||
foreach (var testMod in initialMods)
|
|
||||||
{
|
|
||||||
ModService.UnLoad(testMod);
|
|
||||||
ModService.UnInstall(testMod);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -2,7 +2,8 @@
|
||||||
"name": "BITKit.Physics",
|
"name": "BITKit.Physics",
|
||||||
"rootNamespace": "",
|
"rootNamespace": "",
|
||||||
"references": [
|
"references": [
|
||||||
"GUID:14fe60d984bf9f84eac55c6ea033a8f4"
|
"GUID:14fe60d984bf9f84eac55c6ea033a8f4",
|
||||||
|
"GUID:6babdba9f8b742f40904649736008000"
|
||||||
],
|
],
|
||||||
"includePlatforms": [],
|
"includePlatforms": [],
|
||||||
"excludePlatforms": [],
|
"excludePlatforms": [],
|
||||||
|
|
|
@ -0,0 +1,99 @@
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace BITKit.Physics
|
||||||
|
{
|
||||||
|
public static class GeometryUtils
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 获取一个点到一条线段的最近点
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="point"></param>
|
||||||
|
/// <param name="lineStart"></param>
|
||||||
|
/// <param name="lineEnd"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static Vector3 PointToLineSegmentDistance(Vector3 point, Vector3 lineStart, Vector3 lineEnd)
|
||||||
|
{
|
||||||
|
Vector3 lineDirection = lineEnd - lineStart;
|
||||||
|
Vector3 pointDirection = point - lineStart;
|
||||||
|
|
||||||
|
float lineLength = lineDirection.magnitude;
|
||||||
|
lineDirection.Normalize();
|
||||||
|
|
||||||
|
float dotProduct = Vector3.Dot(pointDirection, lineDirection);
|
||||||
|
dotProduct = Mathf.Clamp(dotProduct, 0f, lineLength);
|
||||||
|
|
||||||
|
Vector3 closestPoint = lineStart + lineDirection * dotProduct;
|
||||||
|
return closestPoint;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 获取一个点到一个三角形内最短距离的点
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="a">三角形顶点a</param>
|
||||||
|
/// <param name="b">三角形顶点b</param>
|
||||||
|
/// <param name="c">三角形顶点c</param>
|
||||||
|
/// <param name="pos"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static Vector3 GetPosInTriangle(Vector3 a, Vector3 b, Vector3 c, Vector3 pos)
|
||||||
|
{
|
||||||
|
Vector3 normal = Vector3.Cross(b - a, c - a).normalized;
|
||||||
|
Vector3 toPoint = pos - a;
|
||||||
|
float distance = Vector3.Dot(toPoint, normal);
|
||||||
|
|
||||||
|
Vector3 targetPos = pos - distance * normal;
|
||||||
|
|
||||||
|
if(PointInTriangle(targetPos, a, b, c))
|
||||||
|
return targetPos;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Vector3 p1 = PointToLineSegmentDistance(pos, a, b);
|
||||||
|
Vector3 p2 = PointToLineSegmentDistance(pos, a, c);
|
||||||
|
Vector3 p3 = PointToLineSegmentDistance(pos, b, c);
|
||||||
|
|
||||||
|
float d1 = Vector3.Distance(p1, pos);
|
||||||
|
float d2 = Vector3.Distance(p2, pos);
|
||||||
|
float d3 = Vector3.Distance(p3, pos);
|
||||||
|
|
||||||
|
if (d1 <= d2 && d1 <= d3)
|
||||||
|
return p1;
|
||||||
|
else if (d2 <= d3 && d2 <= d1)
|
||||||
|
return p2;
|
||||||
|
else /*if(d3 <= d1 && d3 <= d2)*/
|
||||||
|
return p3;
|
||||||
|
|
||||||
|
//return default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 判断一个点是否在三角形内
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pos"></param>
|
||||||
|
/// <param name="a"></param>
|
||||||
|
/// <param name="b"></param>
|
||||||
|
/// <param name="c"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static bool PointInTriangle(Vector3 pos, Vector3 a, Vector3 b, Vector3 c)
|
||||||
|
{
|
||||||
|
var v0 = c - a;
|
||||||
|
var v1 = b - a;
|
||||||
|
var v2 = pos - a;
|
||||||
|
|
||||||
|
var dot00 = Vector3.Dot(v0, v0);
|
||||||
|
var dot01 = Vector3.Dot(v0, v1);
|
||||||
|
var dot02 = Vector3.Dot(v0, v2);
|
||||||
|
var dot11 = Vector3.Dot(v1, v1);
|
||||||
|
var dot12 = Vector3.Dot(v1, v2);
|
||||||
|
|
||||||
|
var invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
|
||||||
|
var u = (dot11 * dot02 - dot01 * dot12) * invDenom;
|
||||||
|
var v = (dot00 * dot12 - dot01 * dot02) * invDenom;
|
||||||
|
|
||||||
|
// 如果u和v都在[0,1]的范围内,那么点P在三角形ABC内
|
||||||
|
return (u >= 0) && (v >= 0) && (u + v < 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: ae14ae5985cea8e40946355bfdf7113b
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
|
@ -1,7 +1,9 @@
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using DrawXXL;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace BITKit.Physics
|
namespace BITKit.Physics
|
||||||
|
@ -9,7 +11,7 @@ namespace BITKit.Physics
|
||||||
public class GetClosePointFromCollider : IClosePointProvider
|
public class GetClosePointFromCollider : IClosePointProvider
|
||||||
{
|
{
|
||||||
public string Name="Default";
|
public string Name="Default";
|
||||||
public Transform Transform;
|
public readonly Transform Transform;
|
||||||
public Vector3 Offset = default;
|
public Vector3 Offset = default;
|
||||||
public LayerMask LayerMask=LayerMask.NameToLayer("Default");
|
public LayerMask LayerMask=LayerMask.NameToLayer("Default");
|
||||||
public float Distance=1.6f;
|
public float Distance=1.6f;
|
||||||
|
@ -26,68 +28,97 @@ namespace BITKit.Physics
|
||||||
|
|
||||||
public bool TryGetValue(out Vector3 position, out Collider collider)
|
public bool TryGetValue(out Vector3 position, out Collider collider)
|
||||||
{
|
{
|
||||||
Vector3 vector3 = default;
|
|
||||||
StringBuilder reportBuilder = new();
|
StringBuilder reportBuilder = new();
|
||||||
reportBuilder.AppendLine($"检测任务:{Name}");
|
reportBuilder.AppendLine($"检测任务:{Name}");
|
||||||
position = Transform.position + Transform.rotation * Offset;
|
position = Transform.position + Transform.rotation * Offset;
|
||||||
var detectedLength = UnityEngine.Physics.OverlapSphereNonAlloc(position, Distance, _mainCollider, LayerMask);
|
var detectedLength = UnityEngine.Physics.OverlapSphereNonAlloc(position, Distance, _mainCollider, LayerMask);
|
||||||
reportBuilder.AppendLine($"检测到了{detectedLength}个碰撞体");
|
reportBuilder.AppendLine($"检测到了{detectedLength}个碰撞体");
|
||||||
|
|
||||||
|
var validMeshColliders = new Queue<(Collider collider,Vector3 targetPosition)>();
|
||||||
|
|
||||||
|
var samplePoint = position;
|
||||||
|
samplePoint.y += Distance / 2;
|
||||||
|
|
||||||
foreach (var collider1 in _mainCollider.Take(detectedLength).OrderBy(ByTop).Reverse())
|
foreach (var collider1 in _mainCollider.Take(detectedLength).OrderBy(ByTop).Reverse())
|
||||||
//for (var i = 0; i <detectedLength ; i++)
|
|
||||||
{
|
{
|
||||||
//reportBuilder.AppendLine($"----------------------------检测到了碰撞体{_mainCollider[i].name}");
|
|
||||||
//var collider = _mainCollider[i];
|
|
||||||
if (collider1.isTrigger)
|
if (collider1.isTrigger)
|
||||||
{
|
{
|
||||||
reportBuilder?.AppendLine("碰撞体是触发器");
|
reportBuilder?.AppendLine("碰撞体是触发器");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector3 closePoint;
|
||||||
|
|
||||||
switch (collider1)
|
switch (collider1)
|
||||||
{
|
{
|
||||||
case MeshCollider meshCollider:
|
case TerrainCollider terrainCollider:
|
||||||
if (meshCollider.convex is false)
|
{
|
||||||
{
|
closePoint = terrainCollider.ClosestPointOnBounds(samplePoint);
|
||||||
reportBuilder?.AppendLine("MeshCollider未勾选Convex");
|
}
|
||||||
continue;
|
break;
|
||||||
}
|
case MeshCollider { convex: false } meshCollider:
|
||||||
|
{
|
||||||
|
var getClosestPointFromMesh =
|
||||||
|
new GetClosestPointFromMesh(meshCollider.sharedMesh,meshCollider.transform.InverseTransformPoint(samplePoint));
|
||||||
|
|
||||||
break;
|
if (getClosestPointFromMesh.TryGetValue(out var localPosition, out collider))
|
||||||
|
{
|
||||||
|
localPosition = meshCollider.transform.TransformPoint(localPosition);
|
||||||
|
|
||||||
|
Debug.DrawLine(Transform.position,localPosition,Color.magenta);
|
||||||
|
|
||||||
|
if (Vector3.Distance(localPosition, position) < Distance)
|
||||||
|
{
|
||||||
|
closePoint = localPosition;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
closePoint = collider1.ClosestPoint(samplePoint);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if(collider1.Raycast(new Ray(Transform.position,Transform.forward),out var raycastHit,64) is false)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (MathV.IsForward(position, Transform.forward, closePoint) is false)
|
||||||
|
{
|
||||||
|
//DrawBasics.PointTag(closePoint,"not forward");
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var bounds = collider1.bounds;
|
if (Transform.position.y + MinHeight > closePoint.y)
|
||||||
vector3 = collider1.ClosestPoint(Transform.position + Vector3.up * 64);
|
|
||||||
var top = bounds.center.y + bounds.extents.y;
|
|
||||||
Debug.DrawLine(Transform.position, Transform.position + Vector3.up * top, Color.blue, 8f);
|
|
||||||
if (Transform.position.y + MinHeight > top)
|
|
||||||
{
|
{
|
||||||
reportBuilder?.AppendLine("高度不足");
|
DrawBasics.PointTag(closePoint,"not enough height");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var nextPos = position;
|
|
||||||
nextPos.y = collider1.bounds.center.y;
|
|
||||||
|
|
||||||
{
|
|
||||||
var ray = new Ray(nextPos, Transform.forward);
|
|
||||||
if (collider1.Raycast(new Ray(nextPos, Transform.forward), out _, Distance) is false)
|
|
||||||
{
|
|
||||||
reportBuilder?.AppendLine("未检测到前方");
|
|
||||||
Debug.DrawRay(ray.origin,ray.direction,Color.red,Distance);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var height = Mathf.Abs(top - Transform.position.y);
|
var height = Mathf.Abs(closePoint.y - Transform.position.y);
|
||||||
if (height > MaxHeight)
|
if (height > MaxHeight)
|
||||||
{
|
{
|
||||||
reportBuilder?.AppendLine($"高度差距过大:{height}");
|
reportBuilder?.AppendLine($"高度差距过大:{height}");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (UnityEngine.Physics.Linecast(Transform.position, vector3, out var raycastHit2, LayerMask))
|
if (UnityEngine.Physics.Linecast(Transform.position, closePoint, out var raycastHit2, LayerMask))
|
||||||
{
|
{
|
||||||
if (raycastHit2.collider != collider1)
|
if (raycastHit2.collider != collider1)
|
||||||
{
|
{
|
||||||
|
@ -95,40 +126,61 @@ namespace BITKit.Physics
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var length = UnityEngine.Physics.OverlapSphereNonAlloc(vector3, 0.01f, _colliders, LayerMask);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var length = UnityEngine.Physics.OverlapSphereNonAlloc(closePoint+Vector3.up*0.2f, 0.1f, _colliders, LayerMask);
|
||||||
switch (length)
|
switch (length)
|
||||||
{
|
{
|
||||||
case 1:
|
case > 0:
|
||||||
if (_colliders[0] != collider1)
|
|
||||||
{
|
|
||||||
reportBuilder.AppendLine($"检测到了其他碰撞体{_colliders[0].name}");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
case > 1:
|
|
||||||
reportBuilder.AppendLine("检测到了更多碰撞体");
|
reportBuilder.AppendLine("检测到了更多碰撞体");
|
||||||
for (var ii = 0; ii < length; ii++)
|
for (var ii = 0; ii < length; ii++)
|
||||||
{
|
{
|
||||||
//Debug.DrawLine(vector3, _colliders[ii].ClosestPoint(vector3), Color.red, 8);
|
//Debug.DrawLine(vector3, _colliders[ii].ClosestPoint(vector3), Color.red, 8);
|
||||||
reportBuilder.AppendLine($"\t{_colliders[ii].name}");
|
reportBuilder.AppendLine($"\t{_colliders[ii].name}");
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
vector3.y = top;
|
|
||||||
position = vector3;
|
|
||||||
|
|
||||||
collider = collider1;
|
|
||||||
|
|
||||||
reportBuilder.AppendLine("<color=green>成功</color>");
|
reportBuilder.AppendLine("<color=green>成功</color>");
|
||||||
|
|
||||||
//BIT4Log.Log<GetClosePointFromCollider>(reportBuilder.ToString());
|
//BIT4Log.Log<GetClosePointFromCollider>(reportBuilder.ToString());
|
||||||
return true;
|
|
||||||
|
Debug.DrawLine(Transform.position,closePoint,Color.green);
|
||||||
|
|
||||||
|
validMeshColliders.Enqueue(new(collider1,closePoint));
|
||||||
|
}
|
||||||
|
|
||||||
|
var minDot = 64f;
|
||||||
|
|
||||||
|
Collider resultCollider = default;
|
||||||
|
Vector3 resultPosition=default;
|
||||||
|
|
||||||
|
while (validMeshColliders.TryDequeue(out var result))
|
||||||
|
{
|
||||||
|
var dot =Mathf.Abs(Vector3.Cross(Transform.forward, result.targetPosition-Transform.position).y);
|
||||||
|
|
||||||
|
DrawBasics.LineFrom(Transform.position,result.targetPosition-Transform.position,Color.red,text:dot.ToString(CultureInfo.InvariantCulture));
|
||||||
|
|
||||||
|
if(dot>minDot)continue;
|
||||||
|
|
||||||
|
resultCollider = result.collider;
|
||||||
|
resultPosition = result.targetPosition;
|
||||||
|
|
||||||
|
minDot = dot;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (minDot < 64)
|
||||||
|
{
|
||||||
|
collider = resultCollider;
|
||||||
|
position = resultPosition;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
collider = null;
|
collider = null;
|
||||||
//BIT4Log.Log<GetClosePointFromCollider>(reportBuilder.ToString());
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
private float ByTop(Collider arg)
|
private float ByTop(Collider arg)
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace BITKit.Physics
|
||||||
|
{
|
||||||
|
[ExecuteAlways]
|
||||||
|
public class GetClosePointFromColliderDebugger : MonoBehaviour
|
||||||
|
{
|
||||||
|
private GetClosePointFromCollider _getClosePointFromCollider;
|
||||||
|
[SerializeField] private LayerMask layerMask;
|
||||||
|
private void OnEnable()
|
||||||
|
{
|
||||||
|
_getClosePointFromCollider = new GetClosePointFromCollider(transform);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Update()
|
||||||
|
{
|
||||||
|
_getClosePointFromCollider.LayerMask = layerMask;
|
||||||
|
if (_getClosePointFromCollider.TryGetValue(out Vector3 vector3, out var collider1))
|
||||||
|
{
|
||||||
|
var offset = Vector3.up * -0.01f;
|
||||||
|
Debug.DrawLine(transform.position+offset,vector3+offset,Color.cyan);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDrawGizmosSelected()
|
||||||
|
{
|
||||||
|
Gizmos.DrawWireSphere(transform.position,_getClosePointFromCollider.Distance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e856e0f7ca7746740a416303f76dc89d
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
|
@ -0,0 +1,53 @@
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace BITKit.Physics
|
||||||
|
{
|
||||||
|
public readonly struct GetClosestPointFromMesh:IClosePointProvider
|
||||||
|
{
|
||||||
|
private readonly Vector3 _position;
|
||||||
|
private readonly Mesh _mesh;
|
||||||
|
|
||||||
|
public GetClosestPointFromMesh(Mesh mesh, Vector3 position)
|
||||||
|
{
|
||||||
|
_mesh = mesh;
|
||||||
|
_position = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetValue(out Vector3 position, out Collider collider)
|
||||||
|
{
|
||||||
|
position = default;
|
||||||
|
collider = default;
|
||||||
|
|
||||||
|
if (_mesh.isReadable is false) return false;
|
||||||
|
|
||||||
|
|
||||||
|
var vertices = _mesh.vertices;
|
||||||
|
|
||||||
|
if (vertices.Length > 2048) return false;
|
||||||
|
|
||||||
|
var minPos = new Vector3(64, 64, 64);
|
||||||
|
|
||||||
|
for (var index = 0; index < _mesh.triangles.Length; index+=3)
|
||||||
|
{
|
||||||
|
var x = vertices[_mesh.triangles[index]];
|
||||||
|
var y = vertices[_mesh.triangles[index + 1]];
|
||||||
|
var z = vertices[_mesh.triangles[index + 2]];
|
||||||
|
|
||||||
|
var pos = GeometryUtils.GetPosInTriangle(x, y, z, _position);
|
||||||
|
|
||||||
|
if (Vector3.Distance(pos, _position) < Vector3.Distance(minPos, _position))
|
||||||
|
{
|
||||||
|
minPos = pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
position = minPos;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 979c184b4aaba6a439cbe74f0196267f
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
|
@ -27,7 +27,7 @@ namespace BITKit
|
||||||
AssetDatabase.LoadAssetAtPath<DictionaryReferenceScriptableObject>(
|
AssetDatabase.LoadAssetAtPath<DictionaryReferenceScriptableObject>(
|
||||||
"Assets/Artists/Configs/reference_dictionary.asset");
|
"Assets/Artists/Configs/reference_dictionary.asset");
|
||||||
#else
|
#else
|
||||||
var task = YooAssets.LoadAssetAsync("reference_directory");
|
var task = YooAssets.LoadAssetAsync("reference_dictionary");
|
||||||
task.WaitForAsyncComplete();
|
task.WaitForAsyncComplete();
|
||||||
_singleton=task.AssetObject as DictionaryReferenceScriptableObject;
|
_singleton=task.AssetObject as DictionaryReferenceScriptableObject;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -11,7 +11,7 @@ using UnityEngine;
|
||||||
using UnityEngine.Jobs;
|
using UnityEngine.Jobs;
|
||||||
using UnityEngine.Pool;
|
using UnityEngine.Pool;
|
||||||
|
|
||||||
namespace BITFALL.Rig{
|
namespace BITKit.UX.Rig{
|
||||||
public class TickOverrideTranformService : MonoBehaviour
|
public class TickOverrideTranformService : MonoBehaviour
|
||||||
{
|
{
|
||||||
//[BurstCompile]
|
//[BurstCompile]
|
||||||
|
|
|
@ -3,7 +3,7 @@ using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace BITFALL.Rig
|
namespace BITKit.UX.Rig
|
||||||
{
|
{
|
||||||
public class TickOverrideTransform : MonoBehaviour
|
public class TickOverrideTransform : MonoBehaviour
|
||||||
{
|
{
|
||||||
|
|
|
@ -14,7 +14,7 @@ namespace BITKit
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class IntervalTick:ITicker
|
public class IntervalTick:ITicker
|
||||||
{
|
{
|
||||||
[SerializeField] private float interval;
|
private float interval;
|
||||||
public ulong TickCount=>IntervalTickService.GetTickCount(interval);
|
public ulong TickCount=>IntervalTickService.GetTickCount(interval);
|
||||||
|
|
||||||
public void Add(Action action)
|
public void Add(Action action)
|
||||||
|
|
|
@ -18,7 +18,9 @@
|
||||||
"GUID:517785bb4600a5140b47eac5fa49b8fc",
|
"GUID:517785bb4600a5140b47eac5fa49b8fc",
|
||||||
"GUID:838d3286f0973344ab6e99d3951012f7",
|
"GUID:838d3286f0973344ab6e99d3951012f7",
|
||||||
"GUID:a11ff146d38b27a44af87b4b4d9c4ecb",
|
"GUID:a11ff146d38b27a44af87b4b4d9c4ecb",
|
||||||
"GUID:e4d11af1289097a4d9d8987f332a2ae8"
|
"GUID:e4d11af1289097a4d9d8987f332a2ae8",
|
||||||
|
"GUID:3abaaefa7af558d44ba20cea1c43d602",
|
||||||
|
"GUID:d8b63aba1907145bea998dd612889d6b"
|
||||||
],
|
],
|
||||||
"includePlatforms": [],
|
"includePlatforms": [],
|
||||||
"excludePlatforms": [],
|
"excludePlatforms": [],
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 9d540311d69835747a74085c9e0aba6c
|
guid: ea593ccd503f23741b162c0f5a00fb52
|
||||||
folderAsset: yes
|
folderAsset: yes
|
||||||
DefaultImporter:
|
DefaultImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
|
@ -59,9 +59,10 @@ namespace BITKit.UX
|
||||||
GUILayout.BeginVertical();
|
GUILayout.BeginVertical();
|
||||||
//颜色更改为黑色
|
//颜色更改为黑色
|
||||||
GUI.color = textColor;
|
GUI.color = textColor;
|
||||||
GUILayout.Label(_logBuilder.ToString(),style);
|
GUILayout.Label(string.Join("\n",_logBuilder.ToString().Split("\n").Reverse()),style);
|
||||||
GUILayout.EndVertical();
|
GUILayout.EndVertical();
|
||||||
GUILayout.EndArea();
|
GUILayout.EndArea();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -8,7 +8,8 @@
|
||||||
"GUID:14fe60d984bf9f84eac55c6ea033a8f4",
|
"GUID:14fe60d984bf9f84eac55c6ea033a8f4",
|
||||||
"GUID:d525ad6bd40672747bde77962f1c401e",
|
"GUID:d525ad6bd40672747bde77962f1c401e",
|
||||||
"GUID:49b49c76ee64f6b41bf28ef951cb0e50",
|
"GUID:49b49c76ee64f6b41bf28ef951cb0e50",
|
||||||
"GUID:517785bb4600a5140b47eac5fa49b8fc"
|
"GUID:517785bb4600a5140b47eac5fa49b8fc",
|
||||||
|
"GUID:d8b63aba1907145bea998dd612889d6b"
|
||||||
],
|
],
|
||||||
"includePlatforms": [],
|
"includePlatforms": [],
|
||||||
"excludePlatforms": [],
|
"excludePlatforms": [],
|
||||||
|
|
|
@ -0,0 +1,115 @@
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.UIElements;
|
||||||
|
|
||||||
|
namespace BITKit.UX
|
||||||
|
{
|
||||||
|
public class OnScreenButton : OnScreenControl
|
||||||
|
{
|
||||||
|
public new class UxmlTraits : VisualElement.UxmlTraits
|
||||||
|
{
|
||||||
|
private readonly UxmlFloatAttributeDescription m_PressedValueAttribute = new ()
|
||||||
|
{
|
||||||
|
name = "PressedValue",
|
||||||
|
defaultValue = 1f,
|
||||||
|
};
|
||||||
|
|
||||||
|
private readonly UxmlBoolAttributeDescription m_ReleasePressAttribute = new()
|
||||||
|
{
|
||||||
|
name = "ReleasePress"
|
||||||
|
};
|
||||||
|
|
||||||
|
public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc)
|
||||||
|
{
|
||||||
|
base.Init(ve, bag, cc);
|
||||||
|
var table = (OnScreenButton)ve;
|
||||||
|
table.PressedValue = m_PressedValueAttribute.GetValueFromBag(bag, cc);
|
||||||
|
table.ReleasePress = m_ReleasePressAttribute.GetValueFromBag(bag, cc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public new class UxmlFactory : UxmlFactory<OnScreenButton, UxmlTraits> { }
|
||||||
|
public float PressedValue { get; set; }= 1f;
|
||||||
|
public bool ReleasePress { get; set; }
|
||||||
|
|
||||||
|
private bool _isPressed;
|
||||||
|
private int _pointerId=-1;
|
||||||
|
private Label _label;
|
||||||
|
|
||||||
|
private readonly ValidHandle _isTriggered = new();
|
||||||
|
public OnScreenButton()
|
||||||
|
{
|
||||||
|
RegisterCallback<PointerUpEvent>(OnPointerUp);
|
||||||
|
RegisterCallback<PointerDownEvent>(OnPointerDown);
|
||||||
|
RegisterCallback<PointerMoveEvent>(OnPointerMove);
|
||||||
|
this.AddManipulator(new Clickable(OnClick));
|
||||||
|
_label = this.Create<Label>();
|
||||||
|
|
||||||
|
_isTriggered.AddListener(x =>
|
||||||
|
{
|
||||||
|
if (x)
|
||||||
|
{
|
||||||
|
AddToClassList("selected");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RemoveFromClassList("selected");
|
||||||
|
}
|
||||||
|
var value = x?PressedValue : 0f;
|
||||||
|
SendValueToControl( value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
private void OnClick()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
private void OnPointerMove(PointerMoveEvent evt)
|
||||||
|
{
|
||||||
|
if(_pointerId!=evt.pointerId)return;
|
||||||
|
|
||||||
|
if (ReleasePress)
|
||||||
|
{
|
||||||
|
_isPressed = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_isPressed is false)
|
||||||
|
{
|
||||||
|
_isTriggered.AddElement(0);
|
||||||
|
_isPressed = true;
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPointerDown(PointerDownEvent evt)
|
||||||
|
{
|
||||||
|
if(_pointerId is not -1)return;
|
||||||
|
|
||||||
|
_pointerId = evt.pointerId;
|
||||||
|
|
||||||
|
_isPressed = true;
|
||||||
|
|
||||||
|
_isTriggered.AddElement(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPointerUp(PointerUpEvent evt)
|
||||||
|
{
|
||||||
|
if(_pointerId!=evt.pointerId)return;
|
||||||
|
|
||||||
|
if (ReleasePress && _isPressed)
|
||||||
|
{
|
||||||
|
_isTriggered.AddElement(0);
|
||||||
|
_pointerId = -1;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_pointerId = -1;
|
||||||
|
|
||||||
|
|
||||||
|
_isTriggered.RemoveElement(0);
|
||||||
|
|
||||||
|
}
|
||||||
|
protected override string ControlPathInternal { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 8afc05714f63ce542a2e2ead78933966
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
|
@ -0,0 +1,330 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Unity.Collections;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.InputSystem;
|
||||||
|
using UnityEngine.InputSystem.Layouts;
|
||||||
|
using UnityEngine.InputSystem.LowLevel;
|
||||||
|
using UnityEngine.InputSystem.Utilities;
|
||||||
|
using UnityEngine.UIElements;
|
||||||
|
|
||||||
|
namespace BITKit.UX
|
||||||
|
{
|
||||||
|
public abstract class OnScreenControl:VisualElement
|
||||||
|
{
|
||||||
|
|
||||||
|
public new class UxmlTraits : VisualElement.UxmlTraits
|
||||||
|
{
|
||||||
|
private readonly UxmlStringAttributeDescription m_ControlPathAttribute = new ()
|
||||||
|
{
|
||||||
|
name = "ControlPath"
|
||||||
|
};
|
||||||
|
|
||||||
|
public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc)
|
||||||
|
{
|
||||||
|
base.Init(ve, bag, cc);
|
||||||
|
var table = (OnScreenControl)ve;
|
||||||
|
table.ControlPath = m_ControlPathAttribute.GetValueFromBag(bag, cc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected OnScreenControl()
|
||||||
|
{
|
||||||
|
RegisterCallback<GeometryChangedEvent>(OnGeometryChanged);
|
||||||
|
RegisterCallback<AttachToPanelEvent>(OnAttachToPanel);
|
||||||
|
RegisterCallback<DetachFromPanelEvent>(OnDetachFromPanel);
|
||||||
|
IsEnabled.AddDisableElements(this);
|
||||||
|
|
||||||
|
IsEnabled.AddListener(x =>
|
||||||
|
{
|
||||||
|
if (x)
|
||||||
|
OnEnable();
|
||||||
|
else OnDisable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDetachFromPanel(DetachFromPanelEvent evt)
|
||||||
|
{
|
||||||
|
IsEnabled.AddDisableElements(32);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnAttachToPanel(AttachToPanelEvent evt)
|
||||||
|
{
|
||||||
|
IsEnabled.RemoveDisableElements(32);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnGeometryChanged(GeometryChangedEvent evt)
|
||||||
|
{
|
||||||
|
IsEnabled.SetDisableElements(this, !visible);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected readonly ValidHandle IsEnabled = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The control path (see <see cref="InputControlPath"/>) for the control that the on-screen
|
||||||
|
/// control will feed input into.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// A device will be created from the device layout referenced by the control path (see
|
||||||
|
/// <see cref="InputControlPath.TryGetDeviceLayout"/>). The path is then used to look up
|
||||||
|
/// <see cref="Control"/> on the device. The resulting control will be fed values from
|
||||||
|
/// the on-screen control.
|
||||||
|
///
|
||||||
|
/// Multiple on-screen controls sharing the same device layout will together create a single
|
||||||
|
/// virtual device. If, for example, one component uses <c>"<Gamepad>/buttonSouth"</c>
|
||||||
|
/// and another uses <c>"<Gamepad>/leftStick"</c> as the control path, a single
|
||||||
|
/// <see cref="Gamepad"/> will be created and the first component will feed data to
|
||||||
|
/// <see cref="Gamepad.buttonSouth"/> and the second component will feed data to
|
||||||
|
/// <see cref="Gamepad.leftStick"/>.
|
||||||
|
/// </remarks>
|
||||||
|
/// <seealso cref="InputControlPath"/>
|
||||||
|
public string ControlPath
|
||||||
|
{
|
||||||
|
get => ControlPathInternal;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
IsEnabled.SetElements(1, string.IsNullOrEmpty(value) is false);
|
||||||
|
ControlPathInternal = value;
|
||||||
|
IsEnabled.AddDisableElements("Force");
|
||||||
|
IsEnabled.RemoveDisableElements("Force");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The actual control that is fed input from the on-screen control.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This is only valid while the on-screen control is enabled. Otherwise, it is <c>null</c>. Also,
|
||||||
|
/// if no <see cref="ControlPath"/> has been set, this will remain <c>null</c> even if the component is enabled.
|
||||||
|
/// </remarks>
|
||||||
|
public InputControl Control => _mControl;
|
||||||
|
|
||||||
|
private InputControl _mControl;
|
||||||
|
private OnScreenControl _mNextControlOnDevice;
|
||||||
|
private InputEventPtr _mInputEventPtr;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Accessor for the <see cref="ControlPath"/> of the component. Must be implemented by subclasses.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Moving the definition of how the control path is stored into subclasses allows them to
|
||||||
|
/// apply their own <see cref="InputControlAttribute"/> attributes to them and thus set their
|
||||||
|
/// own layout filters.
|
||||||
|
/// </remarks>
|
||||||
|
protected abstract string ControlPathInternal { get; set; }
|
||||||
|
|
||||||
|
private void SetupInputControl()
|
||||||
|
{
|
||||||
|
Debug.Assert(_mControl == null, "InputControl already initialized");
|
||||||
|
Debug.Assert(_mNextControlOnDevice == null, "Previous InputControl has not been properly uninitialized (m_NextControlOnDevice still set)");
|
||||||
|
Debug.Assert(!_mInputEventPtr.valid, "Previous InputControl has not been properly uninitialized (m_InputEventPtr still set)");
|
||||||
|
|
||||||
|
// Nothing to do if we don't have a control path.
|
||||||
|
var path = ControlPathInternal;
|
||||||
|
if (string.IsNullOrEmpty(path))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Determine what type of device to work with.
|
||||||
|
var layoutName = InputControlPath.TryGetDeviceLayout(path);
|
||||||
|
if (layoutName == null)
|
||||||
|
{
|
||||||
|
Debug.LogError(
|
||||||
|
$"Cannot determine device layout to use based on control path '{path}' used in {GetType().Name} component with {name}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to find existing on-screen device that matches.
|
||||||
|
var internedLayoutName = new InternedString(layoutName);
|
||||||
|
var deviceInfoIndex = -1;
|
||||||
|
for (var i = 0; i < OnScreenDevices.Count; ++i)
|
||||||
|
{
|
||||||
|
////FIXME: this does not take things such as different device usages into account
|
||||||
|
if (OnScreenDevices[i].Device.layout != internedLayoutName) continue;
|
||||||
|
deviceInfoIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we don't have a matching one, create a new one.
|
||||||
|
InputDevice device;
|
||||||
|
if (deviceInfoIndex == -1)
|
||||||
|
{
|
||||||
|
// Try to create device.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
device = InputSystem.AddDevice(layoutName);
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
Debug.LogError(
|
||||||
|
$"Could not create device with layout '{layoutName}' used in '{GetType().Name}' component");
|
||||||
|
Debug.LogException(exception);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
InputSystem.AddDeviceUsage(device, "OnScreen");
|
||||||
|
|
||||||
|
// Create event buffer.
|
||||||
|
var buffer = StateEvent.From(device, out var eventPtr, Allocator.Persistent);
|
||||||
|
|
||||||
|
// Add to list.
|
||||||
|
deviceInfoIndex = OnScreenDevices.Count;
|
||||||
|
OnScreenDevices.Add(new OnScreenDeviceInfo
|
||||||
|
{
|
||||||
|
EventPtr = eventPtr,
|
||||||
|
Buffer = buffer,
|
||||||
|
Device = device,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
device = OnScreenDevices[deviceInfoIndex].Device;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to find control on device.
|
||||||
|
_mControl = InputControlPath.TryFindControl(device, path);
|
||||||
|
if (_mControl == null)
|
||||||
|
{
|
||||||
|
Debug.LogError(
|
||||||
|
$"Cannot find control with path '{path}' on device of type '{layoutName}' referenced by component '{GetType().Name}' with {name}");
|
||||||
|
|
||||||
|
// Remove the device, if we just created one.
|
||||||
|
if (OnScreenDevices[deviceInfoIndex].FirstControl == null)
|
||||||
|
{
|
||||||
|
OnScreenDevices[deviceInfoIndex].Destroy();
|
||||||
|
OnScreenDevices.RemoveAt(deviceInfoIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_mInputEventPtr = OnScreenDevices[deviceInfoIndex].EventPtr;
|
||||||
|
|
||||||
|
// We have all we need. Permanently add us.
|
||||||
|
OnScreenDevices[deviceInfoIndex] =
|
||||||
|
OnScreenDevices[deviceInfoIndex].AddControl(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void SendValueToControl<TValue>(TValue value)
|
||||||
|
where TValue : struct
|
||||||
|
{
|
||||||
|
if (_mControl == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!(_mControl is InputControl<TValue> control))
|
||||||
|
throw new ArgumentException(
|
||||||
|
$"The control path {ControlPath} yields a control of type {_mControl.GetType().Name} which is not an InputControl with value type {typeof(TValue).Name}", nameof(value));
|
||||||
|
|
||||||
|
////FIXME: this gives us a one-frame lag (use InputState.Change instead?)
|
||||||
|
_mInputEventPtr.time = InputState.currentTime;
|
||||||
|
control.WriteValueIntoEvent(value, _mInputEventPtr);
|
||||||
|
InputSystem.QueueEvent(_mInputEventPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void SentDefaultValueToControl()
|
||||||
|
{
|
||||||
|
if (_mControl == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
////FIXME: this gives us a one-frame lag (use InputState.Change instead?)
|
||||||
|
_mInputEventPtr.time = InputState.currentTime;
|
||||||
|
_mControl.ResetToDefaultStateInEvent(_mInputEventPtr);
|
||||||
|
InputSystem.QueueEvent(_mInputEventPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void OnEnable()
|
||||||
|
{
|
||||||
|
SetupInputControl();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void OnDisable()
|
||||||
|
{
|
||||||
|
if (_mControl == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var device = _mControl.device;
|
||||||
|
for (var i = 0; i < OnScreenDevices.Count; ++i)
|
||||||
|
{
|
||||||
|
if (OnScreenDevices[i].Device != device)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var deviceInfo = OnScreenDevices[i].RemoveControl(this);
|
||||||
|
if (deviceInfo.FirstControl == null)
|
||||||
|
{
|
||||||
|
// We're the last on-screen control on this device. Remove the device.
|
||||||
|
OnScreenDevices[i].Destroy();
|
||||||
|
OnScreenDevices.RemoveAt(i);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
OnScreenDevices[i] = deviceInfo;
|
||||||
|
|
||||||
|
// We're keeping the device , but we're disabling the on-screen representation
|
||||||
|
// for one of its controls. If the control isn't in default state, reset it
|
||||||
|
// to that now. This is what ensures that if, for example, OnScreenButton is
|
||||||
|
// disabled after OnPointerDown, we reset its button control to zero even
|
||||||
|
// though we will not see an OnPointerUp.
|
||||||
|
if (!_mControl.CheckStateIsAtDefault())
|
||||||
|
SentDefaultValueToControl();
|
||||||
|
}
|
||||||
|
|
||||||
|
_mControl = null;
|
||||||
|
_mInputEventPtr = new InputEventPtr();
|
||||||
|
Debug.Assert(_mNextControlOnDevice == null);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct OnScreenDeviceInfo
|
||||||
|
{
|
||||||
|
public InputEventPtr EventPtr;
|
||||||
|
public NativeArray<byte> Buffer;
|
||||||
|
public InputDevice Device;
|
||||||
|
public OnScreenControl FirstControl;
|
||||||
|
|
||||||
|
public OnScreenDeviceInfo AddControl(OnScreenControl control)
|
||||||
|
{
|
||||||
|
control._mNextControlOnDevice = FirstControl;
|
||||||
|
FirstControl = control;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OnScreenDeviceInfo RemoveControl(OnScreenControl control)
|
||||||
|
{
|
||||||
|
if (FirstControl == control)
|
||||||
|
FirstControl = control._mNextControlOnDevice;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (OnScreenControl current = FirstControl._mNextControlOnDevice, previous = FirstControl;
|
||||||
|
current != null; previous = current, current = current._mNextControlOnDevice)
|
||||||
|
{
|
||||||
|
if (current != control)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
previous._mNextControlOnDevice = current._mNextControlOnDevice;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
control._mNextControlOnDevice = null;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Destroy()
|
||||||
|
{
|
||||||
|
if (Buffer.IsCreated)
|
||||||
|
Buffer.Dispose();
|
||||||
|
if (Device != null)
|
||||||
|
InputSystem.RemoveDevice(Device);
|
||||||
|
Device = null;
|
||||||
|
Buffer = new NativeArray<byte>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly List<OnScreenDeviceInfo> OnScreenDevices=new ();
|
||||||
|
|
||||||
|
internal string GetWarningMessage()
|
||||||
|
{
|
||||||
|
return $"{GetType()} needs to be attached as a child to a UI Canvas and have a RectTransform component to function properly.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 8d6822f32ddff3b4f9fd962009912a81
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
|
@ -0,0 +1,92 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Unity.Mathematics;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.UIElements;
|
||||||
|
|
||||||
|
namespace BITKit.UX
|
||||||
|
{
|
||||||
|
public class OnScreenGamepad : OnScreenControl
|
||||||
|
{
|
||||||
|
public new class UxmlFactory : UxmlFactory<OnScreenGamepad, UxmlTraits> { }
|
||||||
|
protected override string ControlPathInternal { get; set; }
|
||||||
|
private readonly Dictionary<Vector2Int, VisualElement> _buttonMap = new();
|
||||||
|
public OnScreenGamepad()
|
||||||
|
{
|
||||||
|
IsEnabled.AddListener(OnActive);
|
||||||
|
for (var y = 1; y >=-1; y--)
|
||||||
|
{
|
||||||
|
var row = this.Create<VisualElement>();
|
||||||
|
row.style.flexGrow = 1;
|
||||||
|
row.style.flexDirection = FlexDirection.Row;
|
||||||
|
for (var x = -1; x <= 1; x++)
|
||||||
|
{
|
||||||
|
var dir = (x, y) switch
|
||||||
|
{
|
||||||
|
(-1, 1) => "NW", // 西北
|
||||||
|
(0, 1) => "N", // 北
|
||||||
|
(1, 1) => "NE", // 东北
|
||||||
|
(-1, 0) => "W", // 西
|
||||||
|
(0, 0) => "C", // 中心
|
||||||
|
(1, 0) => "E", // 东
|
||||||
|
(-1, -1) => "SW", // 西南
|
||||||
|
(0, -1) => "S", // 南
|
||||||
|
(1, -1) => "SE", // 东南
|
||||||
|
_ => "NULL" // 其他无效位置
|
||||||
|
};
|
||||||
|
var value = (x, y) switch
|
||||||
|
{
|
||||||
|
(-1, -1) => new float2(-0.707f, -0.707f), // NW 西北
|
||||||
|
(0, -1) =>new float2 (0f, -1f), // N 北
|
||||||
|
(1, -1) =>new float2 (0.707f, -0.707f), // NE 东北
|
||||||
|
(-1, 0) => new float2(-1f, 0f), // W 西
|
||||||
|
(0, 0) =>new float2 (0f, 0f), // C 中心
|
||||||
|
(1, 0) =>new float2 (1f, 0f), // E 东
|
||||||
|
(-1, 1) => new float2(-0.707f, 0.707f), // SW 西南
|
||||||
|
(0, 1) =>new float2 (0f, 1f), // S 南
|
||||||
|
(1, 1) => new float2(0.707f, 0.707f), // SE 东南
|
||||||
|
_ => new float2(0f, 0f) // 默认返回 (0, 0) 无效位置
|
||||||
|
};
|
||||||
|
|
||||||
|
var button = row.Create<VisualElement>();
|
||||||
|
|
||||||
|
|
||||||
|
_buttonMap.TryAdd(new Vector2Int(x, y), button);
|
||||||
|
|
||||||
|
button.style.flexGrow = 1;
|
||||||
|
|
||||||
|
button.AddToClassList("gamepad-button");
|
||||||
|
button.AddToClassList($"gamepad-button--{dir.ToLower()}");
|
||||||
|
|
||||||
|
button.AddManipulator(new Clickable(()=>{}));
|
||||||
|
|
||||||
|
button.RegisterCallback<PointerOverEvent>(_ =>
|
||||||
|
{
|
||||||
|
SendValueToControl((Vector2)value);
|
||||||
|
});
|
||||||
|
button.RegisterCallback<PointerUpEvent>(_ =>
|
||||||
|
{
|
||||||
|
SendValueToControl((Vector2)default);
|
||||||
|
});
|
||||||
|
|
||||||
|
// var label = button.Create<Label>();
|
||||||
|
// label.style.flexGrow = 1;
|
||||||
|
//
|
||||||
|
// label.text = $"{value.x},{value.y}";
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnActive(bool obj)
|
||||||
|
{
|
||||||
|
if (obj is false)
|
||||||
|
{
|
||||||
|
SendValueToControl((Vector2)default);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 4bf58213910164e4d8cab38b29830a7b
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
|
@ -0,0 +1,80 @@
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.UIElements;
|
||||||
|
|
||||||
|
namespace BITKit.UX
|
||||||
|
{
|
||||||
|
public class OnScreenStick:OnScreenControl
|
||||||
|
{
|
||||||
|
public new class UxmlTraits : OnScreenControl.UxmlTraits
|
||||||
|
{
|
||||||
|
private readonly UxmlBoolAttributeDescription m_IsDelteaAttribute = new ()
|
||||||
|
{
|
||||||
|
name = "IsDelta"
|
||||||
|
};
|
||||||
|
|
||||||
|
private readonly UxmlFloatAttributeDescription m_MoveRangeAttribute = new()
|
||||||
|
{
|
||||||
|
name = "MoveRange",defaultValue = 32,
|
||||||
|
};
|
||||||
|
|
||||||
|
public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc)
|
||||||
|
{
|
||||||
|
base.Init(ve, bag, cc);
|
||||||
|
var table = (OnScreenStick)ve;
|
||||||
|
table.IsDelta = m_IsDelteaAttribute.GetValueFromBag(bag, cc);
|
||||||
|
table.MoveRange=m_MoveRangeAttribute.GetValueFromBag(bag, cc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public new class UxmlFactory : UxmlFactory<OnScreenStick, UxmlTraits> { }
|
||||||
|
public bool IsDelta { get; set; }
|
||||||
|
public float MoveRange { get; set; } = 32;
|
||||||
|
protected override string ControlPathInternal { get; set; }
|
||||||
|
private int _ignoreFrame=1;
|
||||||
|
private Vector2 _startPosition;
|
||||||
|
public OnScreenStick()
|
||||||
|
{
|
||||||
|
RegisterCallback<PointerDownEvent>(OnPointerDown);
|
||||||
|
RegisterCallback<PointerMoveEvent>(OnPointerMove);
|
||||||
|
RegisterCallback<PointerUpEvent>(OnPointerUp);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPointerUp(PointerUpEvent evt)
|
||||||
|
{
|
||||||
|
SendValueToControl(Vector2.zero);
|
||||||
|
_startPosition = evt.position;
|
||||||
|
_ignoreFrame = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPointerDown(PointerDownEvent evt)
|
||||||
|
{
|
||||||
|
_ignoreFrame = 1;
|
||||||
|
_startPosition = evt.position;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPointerMove(PointerMoveEvent evt)
|
||||||
|
{
|
||||||
|
if (_ignoreFrame-- > 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Vector2.Distance(evt.deltaPosition, default) > Vector2.Distance(_startPosition, evt.position))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var pos = evt.deltaPosition;
|
||||||
|
if (IsDelta)
|
||||||
|
{
|
||||||
|
var newPos = evt.position;
|
||||||
|
pos = new Vector2(newPos.x, newPos.y) - _startPosition;
|
||||||
|
|
||||||
|
pos /= MoveRange;
|
||||||
|
}
|
||||||
|
SendValueToControl(new Vector2(pos.x, -pos.y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e068da31183a7244198cbd23b00ebdbf
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
|
@ -11,9 +11,9 @@ namespace BITKit.UX
|
||||||
{
|
{
|
||||||
public UXInputAction(VisualElement visualElement,string controlPathInternal)
|
public UXInputAction(VisualElement visualElement,string controlPathInternal)
|
||||||
{
|
{
|
||||||
this.controlPathInternal = controlPathInternal;
|
this.ControlPathInternal = controlPathInternal;
|
||||||
}
|
}
|
||||||
protected sealed override string controlPathInternal { get; set; }
|
protected sealed override string ControlPathInternal { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.UIElements;
|
||||||
|
|
||||||
|
namespace BITKit.UX
|
||||||
|
{
|
||||||
|
public class CellContainer : VisualElement
|
||||||
|
{
|
||||||
|
public new class UxmlFactory : UxmlFactory<CellContainer, UxmlTraits> { }
|
||||||
|
|
||||||
|
public int CellSize { get; set; } = 64;
|
||||||
|
public CellContainer()
|
||||||
|
{
|
||||||
|
|
||||||
|
RegisterCallback<CustomStyleResolvedEvent>(x =>
|
||||||
|
{
|
||||||
|
MarkDirtyRepaint();
|
||||||
|
});
|
||||||
|
generateVisualContent += GenerateVisualContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GenerateVisualContent(MeshGenerationContext obj)
|
||||||
|
{
|
||||||
|
if(contentRect.height<=0 || contentRect.width<=0)return;
|
||||||
|
|
||||||
|
var painter = obj.painter2D;
|
||||||
|
|
||||||
|
painter.lineWidth = resolvedStyle.borderTopWidth;
|
||||||
|
painter.strokeColor = resolvedStyle.borderTopColor;
|
||||||
|
|
||||||
|
var yCount = contentRect.height / CellSize;
|
||||||
|
var xCount = contentRect.width / CellSize;
|
||||||
|
|
||||||
|
for (var x = 1; x < xCount; x++)
|
||||||
|
{
|
||||||
|
painter.BeginPath();
|
||||||
|
painter.MoveTo(new Vector2(x * CellSize, 0));
|
||||||
|
painter.LineTo(new Vector2(x * CellSize, contentRect.height));
|
||||||
|
painter.Stroke();
|
||||||
|
}
|
||||||
|
for (var y = 1; y < yCount; y++)
|
||||||
|
{
|
||||||
|
painter.BeginPath();
|
||||||
|
painter.MoveTo(new Vector2(0, y * CellSize));
|
||||||
|
painter.LineTo(new Vector2(contentRect.width, y * CellSize));
|
||||||
|
painter.Stroke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 7b5ba7b7494ea5d42b820dee5a7619c6
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
|
@ -3,6 +3,7 @@ using System.Collections;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
#if UNITY_5_3_OR_NEWER && UNITY_WINDOW
|
#if UNITY_5_3_OR_NEWER && UNITY_WINDOW
|
||||||
|
@ -11,11 +12,13 @@ using AnotherFileBrowser.Windows;
|
||||||
using BITKit.Mod;
|
using BITKit.Mod;
|
||||||
using Cysharp.Threading.Tasks;
|
using Cysharp.Threading.Tasks;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
using UnityEngine.InputSystem;
|
||||||
using UnityEngine.UIElements;
|
using UnityEngine.UIElements;
|
||||||
|
using Pointer = UnityEngine.InputSystem.Pointer;
|
||||||
|
|
||||||
namespace BITKit.UX
|
namespace BITKit.UX
|
||||||
{
|
{
|
||||||
public class UXModService:UIToolKitPanel,IDisposable
|
public class UXModService:UIToolKitPanel
|
||||||
{
|
{
|
||||||
protected override string DocumentPath => "ux_mod_Service";
|
protected override string DocumentPath => "ux_mod_Service";
|
||||||
private const string TemplatePath = "ux_mod_service_template";
|
private const string TemplatePath = "ux_mod_service_template";
|
||||||
|
@ -37,8 +40,7 @@ namespace BITKit.UX
|
||||||
private Label _modDescriptionLabel;
|
private Label _modDescriptionLabel;
|
||||||
[UXBindPath("reload-mod-button",true)]
|
[UXBindPath("reload-mod-button",true)]
|
||||||
private Button _reloadModButton;
|
private Button _reloadModButton;
|
||||||
[UXBindPath("install-roslyn-fill")]
|
|
||||||
private VisualElement _installRoslynFill;
|
|
||||||
|
|
||||||
private readonly ConcurrentDictionary<string,VisualElement> _modContainers=new();
|
private readonly ConcurrentDictionary<string,VisualElement> _modContainers=new();
|
||||||
public UXModService(IUXService uxService) : base(uxService)
|
public UXModService(IUXService uxService) : base(uxService)
|
||||||
|
@ -54,8 +56,6 @@ namespace BITKit.UX
|
||||||
|
|
||||||
private async UniTask InitializeAsync()
|
private async UniTask InitializeAsync()
|
||||||
{
|
{
|
||||||
_installRoslynFill.style.width = 0;
|
|
||||||
|
|
||||||
_modTemplate =await ModService.LoadAsset<VisualTreeAsset>(TemplatePath);
|
_modTemplate =await ModService.LoadAsset<VisualTreeAsset>(TemplatePath);
|
||||||
UXUtils.Inject(this);
|
UXUtils.Inject(this);
|
||||||
|
|
||||||
|
@ -134,6 +134,7 @@ namespace BITKit.UX
|
||||||
private VisualElement Create(IMod mod)
|
private VisualElement Create(IMod mod)
|
||||||
{
|
{
|
||||||
var container =_modsContainer.Create(_modTemplate);
|
var container =_modsContainer.Create(_modTemplate);
|
||||||
|
container.Get<Toggle>().SetValueWithoutNotify(ModService.Mods.Contains(mod));
|
||||||
container.Get<Toggle>().RegisterValueChangedCallback(evt =>
|
container.Get<Toggle>().RegisterValueChangedCallback(evt =>
|
||||||
{
|
{
|
||||||
if (evt.newValue)
|
if (evt.newValue)
|
||||||
|
@ -145,6 +146,7 @@ namespace BITKit.UX
|
||||||
ModService.UnLoad(mod);
|
ModService.UnLoad(mod);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
container.Get<Label>().text = mod.Name +"@"+mod.PackageName;
|
||||||
container.tooltip = mod.Name+"\n"+mod.Description;
|
container.tooltip = mod.Name+"\n"+mod.Description;
|
||||||
|
|
||||||
container.Get<Button>().clicked += () =>
|
container.Get<Button>().clicked += () =>
|
||||||
|
@ -155,8 +157,9 @@ namespace BITKit.UX
|
||||||
return container;
|
return container;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public override void Dispose()
|
||||||
{
|
{
|
||||||
|
base.Dispose();
|
||||||
ModService.OnModInstalled-=OnModInstalled;
|
ModService.OnModInstalled-=OnModInstalled;
|
||||||
ModService.OnModUnInstalled-=OnModUnInstalled;
|
ModService.OnModUnInstalled-=OnModUnInstalled;
|
||||||
ModService.OnModLoaded-=OnModLoaded;
|
ModService.OnModLoaded-=OnModLoaded;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: f51cb0688f8e0454e8dce6e90da31939
|
guid: 64e4049b9c8014d43bb7431cb56b6a09
|
||||||
folderAsset: yes
|
folderAsset: yes
|
||||||
DefaultImporter:
|
DefaultImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
|
@ -0,0 +1,111 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using BITKit.Mod;
|
||||||
|
using BITKit.UX.Hotkey;
|
||||||
|
using Cysharp.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.UIElements;
|
||||||
|
|
||||||
|
namespace BITKit.UX
|
||||||
|
{
|
||||||
|
public class UXRadialMenu : UIToolKitPanel
|
||||||
|
{
|
||||||
|
protected override string DocumentPath => "ui_radial_menu";
|
||||||
|
public override bool CloseWhenClickOutside => true;
|
||||||
|
public override bool AllowCursor => true;
|
||||||
|
private VisualTreeAsset _template;
|
||||||
|
|
||||||
|
[UXBindPath("radialMenu-container")]
|
||||||
|
private VisualElement _container;
|
||||||
|
[UXBindPath("info-label")]
|
||||||
|
private Label _infoLabel;
|
||||||
|
|
||||||
|
public IHotkeyCollection HotkeyCollection { get; set; }
|
||||||
|
|
||||||
|
public UXRadialMenu(IUXService uxService) : base(uxService)
|
||||||
|
{
|
||||||
|
OnInitiatedAsync += InitiatedAsync;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async UniTask InitiatedAsync()
|
||||||
|
{
|
||||||
|
_container.Clear();
|
||||||
|
|
||||||
|
_template =await ModService.LoadAsset<VisualTreeAsset>("ui_radial_menu-template");
|
||||||
|
|
||||||
|
RootVisualElement.RegisterCallback<PointerDownEvent>(x =>
|
||||||
|
{
|
||||||
|
UXService.Return();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
protected override void OnPanelEntry()
|
||||||
|
{
|
||||||
|
base.OnPanelEntry();
|
||||||
|
|
||||||
|
_infoLabel.text = "选择快速动作";
|
||||||
|
|
||||||
|
if (HotkeyCollection is null)
|
||||||
|
{
|
||||||
|
_infoLabel.text = "<color=yellow>没有快速动作</color>";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var count = HotkeyCollection.Hotkeys.Count();
|
||||||
|
|
||||||
|
if (count is 0)
|
||||||
|
{
|
||||||
|
_infoLabel.text = "<color=yellow>目前没有快速动作</color>";
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
var hotkey = HotkeyCollection.Hotkeys.ElementAt(i);
|
||||||
|
|
||||||
|
var angle = 360 / count * i;
|
||||||
|
var pos = Quaternion.Euler(0, 0, angle) * Vector3.up * 384;
|
||||||
|
pos.y *= 0.64f;
|
||||||
|
var container = _container.Create<VisualElement>(_template.CloneTree);
|
||||||
|
|
||||||
|
var button = container.Get<Button>();
|
||||||
|
button.text = hotkey.Name;
|
||||||
|
button.focusable = false;
|
||||||
|
button.clickable = hotkey.HoldDuration is 0 ? new Clickable(OnClick) : null;
|
||||||
|
|
||||||
|
container.style.position = Position.Absolute;
|
||||||
|
container.transform.position = pos;
|
||||||
|
|
||||||
|
container.SetEnabled(hotkey.Enabled);
|
||||||
|
container.RegisterCallback<PointerOverEvent>(OnMouseOver);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
void OnClick()
|
||||||
|
{
|
||||||
|
if (!hotkey.Enabled) return;
|
||||||
|
if (hotkey.OnPerform is not null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
hotkey.OnPerform();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Debug.LogException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UXService.Return();
|
||||||
|
}
|
||||||
|
void OnMouseOver(PointerOverEvent evt)
|
||||||
|
{
|
||||||
|
_infoLabel.text = hotkey.Description;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
protected override void OnPanelExit()
|
||||||
|
{
|
||||||
|
base.OnPanelExit();
|
||||||
|
|
||||||
|
_container.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 961781fb0b2f7004dbb5f7956301c4fc
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
|
@ -40,7 +40,6 @@ namespace BITKit.UX
|
||||||
uxService.Register(this);
|
uxService.Register(this);
|
||||||
InitializeAsync().Forget();
|
InitializeAsync().Forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async UniTask InitializeAsync()
|
private async UniTask InitializeAsync()
|
||||||
{
|
{
|
||||||
await _isBusy;
|
await _isBusy;
|
||||||
|
@ -89,20 +88,20 @@ namespace BITKit.UX
|
||||||
|
|
||||||
UXUtils.Inject(this,RootVisualElement);
|
UXUtils.Inject(this,RootVisualElement);
|
||||||
|
|
||||||
OnInitiated?.Invoke();
|
|
||||||
|
|
||||||
RootVisualElement.SetActive(false);
|
RootVisualElement.SetActive(false);
|
||||||
|
|
||||||
await OnInitiatedAsync.UniTaskFunc();
|
await OnInitiatedAsync.UniTaskFunc();
|
||||||
|
|
||||||
WaitUtilInitialized.TrySetResult();
|
|
||||||
|
|
||||||
RootVisualElement.RegisterCallback<TransitionRunEvent>(OnTransitionRun);
|
RootVisualElement.RegisterCallback<TransitionRunEvent>(OnTransitionRun);
|
||||||
RootVisualElement.RegisterCallback<TransitionStartEvent>(OnTransitionStart);
|
RootVisualElement.RegisterCallback<TransitionStartEvent>(OnTransitionStart);
|
||||||
RootVisualElement.RegisterCallback<TransitionEndEvent>(OnTransitionEnd);
|
RootVisualElement.RegisterCallback<TransitionEndEvent>(OnTransitionEnd);
|
||||||
RootVisualElement.RegisterCallback<TransitionCancelEvent>(OnTransitionEnd);
|
RootVisualElement.RegisterCallback<TransitionCancelEvent>(OnTransitionEnd);
|
||||||
|
|
||||||
WaitUtilTransitionCompleted.TrySetResult();
|
WaitUtilTransitionCompleted.TrySetResult();
|
||||||
|
|
||||||
|
WaitUtilInitialized.TrySetResult();
|
||||||
|
|
||||||
|
OnInitiated?.Invoke();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,6 +126,7 @@ namespace BITKit.UX
|
||||||
public virtual bool AllowReload { get; }
|
public virtual bool AllowReload { get; }
|
||||||
public virtual bool AllowCursor { get; }
|
public virtual bool AllowCursor { get; }
|
||||||
public virtual bool AllowInput { get; }
|
public virtual bool AllowInput { get; }
|
||||||
|
public object Root => RootVisualElement;
|
||||||
public virtual string[] InitialUssClasses { get; } = Array.Empty<string>();
|
public virtual string[] InitialUssClasses { get; } = Array.Empty<string>();
|
||||||
public bool IsDisposed { get; private set; }
|
public bool IsDisposed { get; private set; }
|
||||||
|
|
||||||
|
@ -152,6 +152,11 @@ namespace BITKit.UX
|
||||||
RootVisualElement.SetActive(true);
|
RootVisualElement.SetActive(true);
|
||||||
|
|
||||||
//await UniTask.NextFrame();
|
//await UniTask.NextFrame();
|
||||||
|
|
||||||
|
if (IsWindow)
|
||||||
|
{
|
||||||
|
RootVisualElement.BringToFront();
|
||||||
|
}
|
||||||
|
|
||||||
RootVisualElement.AddToClassList(USSEntry);
|
RootVisualElement.AddToClassList(USSEntry);
|
||||||
|
|
||||||
|
@ -174,9 +179,19 @@ namespace BITKit.UX
|
||||||
{
|
{
|
||||||
BIT4Log.LogException(e);
|
BIT4Log.LogException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
await WaitUtilTransitionCompleted.Task;
|
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var cts = new CancellationTokenSource();
|
||||||
|
cts.CancelAfter(1000);
|
||||||
|
await WaitUtilTransitionCompleted.Task.AttachExternalCancellation(cts.Token);
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
await UniTask.SwitchToMainThread();
|
||||||
|
|
||||||
RootVisualElement.AddToClassList(USSEntered);
|
RootVisualElement.AddToClassList(USSEntered);
|
||||||
}
|
}
|
||||||
private void OnTransitionEnd<TChangeEvent>(TChangeEvent evt)
|
private void OnTransitionEnd<TChangeEvent>(TChangeEvent evt)
|
||||||
|
@ -218,8 +233,17 @@ namespace BITKit.UX
|
||||||
await UniTask.NextFrame();
|
await UniTask.NextFrame();
|
||||||
|
|
||||||
await OnExitAsync.UniTaskFunc();
|
await OnExitAsync.UniTaskFunc();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var cts = new CancellationTokenSource();
|
||||||
|
cts.CancelAfter(1000);
|
||||||
|
await WaitUtilTransitionCompleted.Task.AttachExternalCancellation(cts.Token);
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
await WaitUtilTransitionCompleted.Task;
|
|
||||||
}
|
}
|
||||||
void IEntryElement.Exited()
|
void IEntryElement.Exited()
|
||||||
{
|
{
|
||||||
|
@ -249,7 +273,7 @@ namespace BITKit.UX
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public virtual void Dispose()
|
||||||
{
|
{
|
||||||
RootVisualElement?.RemoveFromHierarchy();
|
RootVisualElement?.RemoveFromHierarchy();
|
||||||
IsDisposed = true;
|
IsDisposed = true;
|
||||||
|
|
|
@ -0,0 +1,141 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Cysharp.Threading.Tasks;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.UIElements;
|
||||||
|
|
||||||
|
namespace BITKit.UX
|
||||||
|
{
|
||||||
|
public class UIToolkitSubPanel<T> :IUXPanel where T : IUXPanel
|
||||||
|
{
|
||||||
|
private readonly IServiceProvider _serviceProvider;
|
||||||
|
protected readonly T Panel;
|
||||||
|
|
||||||
|
protected readonly ValidHandle IsVisible=new();
|
||||||
|
private readonly ValidHandle _busy = new();
|
||||||
|
|
||||||
|
public UIToolkitSubPanel(IServiceProvider serviceProvider)
|
||||||
|
{
|
||||||
|
_serviceProvider = serviceProvider;
|
||||||
|
|
||||||
|
Panel = serviceProvider.GetRequiredService<T>();
|
||||||
|
|
||||||
|
Panel.OnInitiated += OnInitiated;
|
||||||
|
Panel.OnInitiatedAsync += OnInitiatedAsync;
|
||||||
|
|
||||||
|
if (Panel is UIToolKitPanel uiToolKitPanel)
|
||||||
|
{
|
||||||
|
if (uiToolKitPanel.WaitUtilInitialized.Task.Status is UniTaskStatus.Succeeded)
|
||||||
|
{
|
||||||
|
OnInitiatedAsync().Forget();
|
||||||
|
OnInitiated();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Panel.OnEntry +=()=> IsVisible.RemoveDisableElements(this);
|
||||||
|
Panel.OnExit +=()=> IsVisible.AddDisableElements(this);
|
||||||
|
|
||||||
|
IsVisible.AddListener(IsVisibleCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void IsVisibleCallback(bool x)
|
||||||
|
{
|
||||||
|
await _busy;
|
||||||
|
using var busy = _busy.GetHandle();
|
||||||
|
if (x)
|
||||||
|
{
|
||||||
|
OnEntry?.Invoke();
|
||||||
|
OnEntryAsync?.Invoke();
|
||||||
|
OnEntryCompleted?.Invoke();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
OnExit?.Invoke();
|
||||||
|
OnExitAsync?.Invoke();
|
||||||
|
OnExitCompleted?.Invoke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual UniTask OnInitiatedAsync()
|
||||||
|
{
|
||||||
|
UXUtils.Inject(this,Panel.Root as VisualElement);
|
||||||
|
return UniTask.CompletedTask;
|
||||||
|
}
|
||||||
|
protected virtual void OnInitiated()
|
||||||
|
{ UXUtils.Inject(this,Panel.Root as VisualElement);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IEntryElement.IsEntered
|
||||||
|
{
|
||||||
|
get => Panel.IsEntered;
|
||||||
|
set => Panel.IsEntered = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IEntryElement.Entry()
|
||||||
|
{
|
||||||
|
Panel.Entry();
|
||||||
|
}
|
||||||
|
|
||||||
|
UniTask IEntryElement.EntryAsync()
|
||||||
|
{
|
||||||
|
return Panel.EntryAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
void IEntryElement.Entered()
|
||||||
|
{
|
||||||
|
Panel.Entered();
|
||||||
|
}
|
||||||
|
|
||||||
|
void IEntryElement.Exit()
|
||||||
|
{
|
||||||
|
Panel.Exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
UniTask IEntryElement.ExitAsync()
|
||||||
|
{
|
||||||
|
return Panel.ExitAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
void IEntryElement.Exited()
|
||||||
|
{
|
||||||
|
Panel.Exited();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IUXPanel.IsWindow => Panel.IsWindow;
|
||||||
|
|
||||||
|
string IUXPanel.Index => Panel.Index;
|
||||||
|
|
||||||
|
bool IUXPanel.AllowCursor => Panel.AllowCursor;
|
||||||
|
|
||||||
|
bool IUXPanel.AllowInput => Panel.AllowInput;
|
||||||
|
|
||||||
|
object IUXPanel.Root => Panel.Root;
|
||||||
|
public event Action OnEntry;
|
||||||
|
public event Func<UniTask> OnEntryAsync;
|
||||||
|
public event Action OnEntryCompleted;
|
||||||
|
public event Action OnExit;
|
||||||
|
public event Func<UniTask> OnExitAsync;
|
||||||
|
public event Action OnExitCompleted;
|
||||||
|
|
||||||
|
event Action IUXPanel.OnInitiated
|
||||||
|
{
|
||||||
|
add => Panel.OnInitiated += value;
|
||||||
|
remove => Panel.OnInitiated -= value;
|
||||||
|
}
|
||||||
|
|
||||||
|
event Func<UniTask> IUXPanel.OnInitiatedAsync
|
||||||
|
{
|
||||||
|
add => Panel.OnInitiatedAsync += value;
|
||||||
|
remove => Panel.OnInitiatedAsync -= value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IUXPanel.OnTick(float deltaTime)
|
||||||
|
{
|
||||||
|
Panel.OnTick(deltaTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 3b6d7b7e48316f04f9130c5301091ee7
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
|
@ -5,7 +5,10 @@ using System.Threading;
|
||||||
using BITKit.Mod;
|
using BITKit.Mod;
|
||||||
using Cysharp.Threading.Tasks;
|
using Cysharp.Threading.Tasks;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Unity.Mathematics;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
using UnityEngine.EventSystems;
|
||||||
|
using UnityEngine.InputSystem;
|
||||||
using UnityEngine.UIElements;
|
using UnityEngine.UIElements;
|
||||||
using Object = UnityEngine.Object;
|
using Object = UnityEngine.Object;
|
||||||
|
|
||||||
|
@ -25,9 +28,26 @@ namespace BITKit.UX
|
||||||
_serviceProvider = serviceProvider;
|
_serviceProvider = serviceProvider;
|
||||||
_cancellationTokenSource = cancellationTokenSource;
|
_cancellationTokenSource = cancellationTokenSource;
|
||||||
_entryGroup.OnEntry += OnEntry;
|
_entryGroup.OnEntry += OnEntry;
|
||||||
|
|
||||||
|
_windowEntryGroup.OnEntry += OnWindowEntry;
|
||||||
|
_windowEntryGroup.OnExit += OnWindowExit;
|
||||||
_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 obj)
|
||||||
|
{
|
||||||
|
BITAppForUnity.AllowCursor.SetElements(_windowEntryGroup, obj.AllowCursor);
|
||||||
|
if (obj.AllowInput is false)
|
||||||
|
BITInputSystem.AllowInput.AddDisableElements(_windowEntryGroup);
|
||||||
|
}
|
||||||
|
|
||||||
private readonly EntryGroup<IUXPanel> _entryGroup = new();
|
private readonly EntryGroup<IUXPanel> _entryGroup = new();
|
||||||
private readonly EntryGroup<IUXPanel> _windowEntryGroup = new();
|
private readonly EntryGroup<IUXPanel> _windowEntryGroup = new();
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -73,9 +93,9 @@ namespace BITKit.UX
|
||||||
|
|
||||||
public string SettingsPath { get; set; } = "ux_panel_settings";
|
public string SettingsPath { get; set; } = "ux_panel_settings";
|
||||||
public object Root { get; private set; }
|
public object Root { get; private set; }
|
||||||
|
public static VisualElement RootVisualElement { get; private set; }
|
||||||
public async UniTask InitializeAsync()
|
public async UniTask InitializeAsync()
|
||||||
{
|
{
|
||||||
|
|
||||||
var gameObject = new GameObject("UXService");
|
var gameObject = new GameObject("UXService");
|
||||||
Object.DontDestroyOnLoad(gameObject);
|
Object.DontDestroyOnLoad(gameObject);
|
||||||
|
|
||||||
|
@ -87,6 +107,11 @@ Object.Destroy(gameObject);
|
||||||
var document = gameObject.AddComponent<UIDocument>();
|
var document = gameObject.AddComponent<UIDocument>();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
if (Touchscreen.current is not null && SettingsPath == "ux_panel_settings")
|
||||||
|
{
|
||||||
|
SettingsPath = "ux_panel_settings_mobile";
|
||||||
|
}
|
||||||
|
|
||||||
var panelSettings =await ModService.LoadAsset<PanelSettings>(SettingsPath);
|
var panelSettings =await ModService.LoadAsset<PanelSettings>(SettingsPath);
|
||||||
document.panelSettings = panelSettings;
|
document.panelSettings = panelSettings;
|
||||||
}
|
}
|
||||||
|
@ -96,8 +121,12 @@ Object.Destroy(gameObject);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Root = RootVisualElement= document.rootVisualElement;
|
||||||
Root = document.rootVisualElement;
|
|
||||||
|
if (Touchscreen.current is not null)
|
||||||
|
{
|
||||||
|
RootVisualElement.AddToClassList("mobile");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Register(IUXPanel panel) => _registryQueue.Enqueue(panel);
|
public void Register(IUXPanel panel) => _registryQueue.Enqueue(panel);
|
||||||
|
@ -115,6 +144,22 @@ Object.Destroy(gameObject);
|
||||||
public void Entry(string panelName) => _entryQueueByName.TryAdd(panelName);
|
public void Entry(string panelName) => _entryQueueByName.TryAdd(panelName);
|
||||||
public IUXPanel CurrentPanel => _currentPanel;
|
public IUXPanel CurrentPanel => _currentPanel;
|
||||||
public event Action<IUXPanel, IUXPanel> OnPanelChanged;
|
public event Action<IUXPanel, IUXPanel> OnPanelChanged;
|
||||||
|
public bool TryPick(float2 position, out object obj)
|
||||||
|
{
|
||||||
|
obj = null;
|
||||||
|
if (!EventSystem.current.IsPointerOverGameObject())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
position.y = Screen.height - position.y;
|
||||||
|
|
||||||
|
var ve = RootVisualElement.panel.Pick(RuntimePanelUtils.ScreenToPanel(RootVisualElement.panel, position));
|
||||||
|
|
||||||
|
obj = ve;
|
||||||
|
|
||||||
|
return obj is not null;
|
||||||
|
}
|
||||||
|
|
||||||
public void Return()
|
public void Return()
|
||||||
{
|
{
|
||||||
|
@ -143,6 +188,7 @@ Object.Destroy(gameObject);
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
||||||
while (_registryQueue.TryDequeue(out var result))
|
while (_registryQueue.TryDequeue(out var result))
|
||||||
{
|
{
|
||||||
if (result is null) continue;
|
if (result is null) continue;
|
||||||
|
@ -201,6 +247,13 @@ Object.Destroy(gameObject);
|
||||||
|
|
||||||
public async void Dispose()
|
public async void Dispose()
|
||||||
{
|
{
|
||||||
|
foreach (var panelsValue in _panels.Values)
|
||||||
|
{
|
||||||
|
if (panelsValue is IDisposable disposable)
|
||||||
|
{
|
||||||
|
disposable.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
_ticker.Remove(OnTick);
|
_ticker.Remove(OnTick);
|
||||||
await UniTask.SwitchToMainThread();
|
await UniTask.SwitchToMainThread();
|
||||||
if (_currentPanel is not null)
|
if (_currentPanel is not null)
|
||||||
|
|
|
@ -3,6 +3,8 @@ using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Cysharp.Threading.Tasks;
|
using Cysharp.Threading.Tasks;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Unity.Mathematics;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UIElements;
|
using UnityEngine.UIElements;
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
|
@ -10,103 +12,106 @@ using Types = FullscreenEditor.Types;
|
||||||
#endif
|
#endif
|
||||||
namespace BITKit.UX.Settings
|
namespace BITKit.UX.Settings
|
||||||
{
|
{
|
||||||
public class UXSettings : MonoBehaviour
|
public interface IUXSettings:IUXPanel{}
|
||||||
|
public class UXSettings<T,TValue> : UIToolkitSubPanel<T>,IUXSettings where T: IUXPanel
|
||||||
{
|
{
|
||||||
|
private readonly TValue _value;
|
||||||
[SerializeField] private UIDocument document;
|
private readonly IWrapper<TValue> _valueWrapper;
|
||||||
|
public UXSettings(IServiceProvider serviceProvider, IWrapper<TValue> valueWrapper) : base(serviceProvider)
|
||||||
[UXBindPath("resolution-dropdown")]
|
|
||||||
private DropdownField _resolutionDropdown;
|
|
||||||
[UXBindPath("sensitivity-slider")]
|
|
||||||
private Slider _sensitivitySlider;
|
|
||||||
[UXBindPath("fullscreen-toggle")]
|
|
||||||
private Toggle _fullscreenToggle;
|
|
||||||
|
|
||||||
private void Start()
|
|
||||||
{
|
{
|
||||||
UXUtils.Inject(this);
|
_valueWrapper = valueWrapper;
|
||||||
|
_value = _valueWrapper.Value;
|
||||||
|
|
||||||
|
|
||||||
_resolutionDropdown.choices = Screen.resolutions.Select(x => x.ToString()).ToList();
|
|
||||||
_resolutionDropdown.SetValueWithoutNotify(Screen.currentResolution.ToString());
|
|
||||||
_resolutionDropdown.RegisterValueChangedCallback(x =>
|
|
||||||
{
|
|
||||||
Data.Set(Constant.Environment.mat_setvideomode, x.newValue);
|
|
||||||
});
|
|
||||||
|
|
||||||
_fullscreenToggle.SetValueWithoutNotify(Screen.fullScreen);
|
|
||||||
_fullscreenToggle.RegisterValueChangedCallback(x =>
|
|
||||||
{
|
|
||||||
Data.Set(Constant.Environment.fullscreen, x.newValue);
|
|
||||||
});
|
|
||||||
|
|
||||||
//_sensitivitySlider.SetValueWithoutNotify(PlayerConfig.Singleton.Sensitivity);
|
|
||||||
_sensitivitySlider.RegisterValueChangedCallback(x =>
|
|
||||||
{
|
|
||||||
Data.Set(Constant.Environment.sensitivity, x.newValue);
|
|
||||||
});
|
|
||||||
|
|
||||||
Data.AddListener<string>(Constant.Environment.mat_setvideomode, OnResolutionChanged);
|
|
||||||
Data.AddListener<bool>(Constant.Environment.fullscreen,OnFullScreenChanged);
|
|
||||||
Data.AddListener<float>(Constant.Environment.sensitivity,OnSensitivityChanged);
|
|
||||||
|
|
||||||
destroyCancellationToken.Register(() =>
|
|
||||||
{
|
|
||||||
Data.RemoveListender<string>(Constant.Environment.mat_setvideomode, OnResolutionChanged);
|
|
||||||
Data.RemoveListender<bool>(Constant.Environment.fullscreen,OnFullScreenChanged);
|
|
||||||
Data.RemoveListender<float>(Constant.Environment.sensitivity,OnSensitivityChanged);
|
|
||||||
|
|
||||||
PlayerPrefs.Save();
|
|
||||||
});
|
|
||||||
|
|
||||||
if(PlayerPrefs.HasKey(Constant.Environment.fullscreen))
|
|
||||||
Data.Set(Constant.Environment.fullscreen, PlayerPrefs.GetInt(Constant.Environment.fullscreen) == 1);
|
|
||||||
if(PlayerPrefs.HasKey(Constant.Environment.sensitivity))
|
|
||||||
Data.Set(Constant.Environment.sensitivity, PlayerPrefs.GetFloat(Constant.Environment.sensitivity));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void OnSensitivityChanged(float obj)
|
|
||||||
{
|
|
||||||
await UniTask.SwitchToMainThread(destroyCancellationToken);
|
|
||||||
|
|
||||||
_sensitivitySlider.SetValueWithoutNotify(obj);
|
|
||||||
|
|
||||||
PlayerPrefs.SetFloat(Constant.Environment.sensitivity,obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void OnFullScreenChanged(bool obj)
|
|
||||||
{
|
|
||||||
await UniTask.SwitchToMainThread(destroyCancellationToken);
|
|
||||||
_fullscreenToggle.SetValueWithoutNotify(obj);
|
|
||||||
|
|
||||||
|
[UXBindPath("settings-container")]
|
||||||
|
private VisualElement _settingsContainer;
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
private void Save()
|
||||||
if (obj)
|
{
|
||||||
|
_valueWrapper.Value = _value;
|
||||||
|
}
|
||||||
|
protected override void OnInitiated()
|
||||||
|
{
|
||||||
|
base.OnInitiated();
|
||||||
|
_settingsContainer.Clear();
|
||||||
|
foreach (var propertyInfo in typeof(TValue).GetProperties())
|
||||||
{
|
{
|
||||||
FullscreenEditor.Fullscreen.MakeFullscreen(Types.GameView);
|
var name = propertyInfo.GetDisplayName();
|
||||||
}
|
var value = propertyInfo.GetValue(_valueWrapper.Value);
|
||||||
else
|
switch (propertyInfo.PropertyType)
|
||||||
{
|
|
||||||
foreach (var x in FullscreenEditor.Fullscreen.GetAllFullscreen())
|
|
||||||
{
|
{
|
||||||
x.Close();
|
case var type when type == typeof(bool):
|
||||||
|
{
|
||||||
|
var checkBox = _settingsContainer.Create<Toggle>();
|
||||||
|
checkBox.label = name;
|
||||||
|
checkBox.SetValueWithoutNotify(value.As<bool>());
|
||||||
|
checkBox.RegisterValueChangedCallback(x =>
|
||||||
|
{
|
||||||
|
propertyInfo.SetValue(_value,x.newValue);
|
||||||
|
Save();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case var type when type == typeof(float):
|
||||||
|
{
|
||||||
|
var slider = _settingsContainer.Create<Slider>();
|
||||||
|
slider.label = name;
|
||||||
|
slider.showInputField = true;
|
||||||
|
slider.showMixedValue = true;
|
||||||
|
slider.lowValue = 1;
|
||||||
|
slider.highValue = 100;
|
||||||
|
slider.SetValueWithoutNotify(value.As<float>());
|
||||||
|
slider.RegisterValueChangedCallback(x =>
|
||||||
|
{
|
||||||
|
propertyInfo.SetValue(_value,x.newValue);
|
||||||
|
Save();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case var type when type == typeof(int):
|
||||||
|
{
|
||||||
|
var slider = _settingsContainer.Create<SliderInt>();
|
||||||
|
slider.label = name;
|
||||||
|
slider.showInputField = true;
|
||||||
|
slider.showMixedValue = true;
|
||||||
|
slider.lowValue = 1;
|
||||||
|
slider.highValue = 100;
|
||||||
|
slider.SetValueWithoutNotify(value.As<int>());
|
||||||
|
slider.RegisterValueChangedCallback(x =>
|
||||||
|
{
|
||||||
|
propertyInfo.SetValue(_value,x.newValue);
|
||||||
|
Save();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case var type when type == typeof(string):
|
||||||
|
{
|
||||||
|
var textField = _settingsContainer.Create<TextField>();
|
||||||
|
textField.label = name;
|
||||||
|
textField.SetValueWithoutNotify(value.As<string>());
|
||||||
|
textField.RegisterValueChangedCallback(x =>
|
||||||
|
{
|
||||||
|
propertyInfo.SetValue(_value,x.newValue);
|
||||||
|
Save();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case var type when type.IsEnum:
|
||||||
|
{
|
||||||
|
var enumField = _settingsContainer.Create<EnumField>();
|
||||||
|
enumField.label = name;
|
||||||
|
|
||||||
|
enumField.Init(value as Enum);
|
||||||
|
enumField.SetValueWithoutNotify(value as Enum);
|
||||||
|
enumField.RegisterValueChangedCallback(x =>
|
||||||
|
{
|
||||||
|
propertyInfo.SetValue(_value,x.newValue);
|
||||||
|
Save();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
Screen.fullScreen = obj;
|
|
||||||
#endif
|
|
||||||
PlayerPrefs.SetInt(Constant.Environment.fullscreen, obj ? 1 : 0);
|
|
||||||
}
|
|
||||||
private async void OnResolutionChanged(string newResolution)
|
|
||||||
{
|
|
||||||
await UniTask.SwitchToMainThread(destroyCancellationToken);
|
|
||||||
|
|
||||||
_resolutionDropdown.SetValueWithoutNotify(newResolution);
|
|
||||||
var resolution = Screen.resolutions.Single(x => x.ToString() == newResolution);
|
|
||||||
|
|
||||||
Screen.SetResolution(resolution.width,resolution.height,Data.Get<bool>(Constant.Environment.fullscreen));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -84,7 +84,18 @@ namespace BITKit.UX
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
var screenPosition = Mouse.current.position.ReadValue();
|
var screenPosition = Vector2.zero;
|
||||||
|
|
||||||
|
if (Mouse.current is not null)
|
||||||
|
{
|
||||||
|
screenPosition= Mouse.current.position.ReadValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Touchscreen.current is not null)
|
||||||
|
{
|
||||||
|
screenPosition = Touchscreen.current.position.ReadValue();
|
||||||
|
}
|
||||||
|
|
||||||
screenPosition.y = Screen.height - screenPosition.y;
|
screenPosition.y = Screen.height - screenPosition.y;
|
||||||
|
|
||||||
VisualElement ve = panel.Pick(RuntimePanelUtils.ScreenToPanel(panel, screenPosition));
|
VisualElement ve = panel.Pick(RuntimePanelUtils.ScreenToPanel(panel, screenPosition));
|
||||||
|
|
|
@ -204,8 +204,8 @@ namespace BITKit
|
||||||
} while (property.NextVisible(false));
|
} while (property.NextVisible(false));
|
||||||
|
|
||||||
foreach (var method in serializedObject.targetObject.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
|
foreach (var method in serializedObject.targetObject.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
|
||||||
{
|
{
|
||||||
if (method.GetCustomAttribute<BITAttribute>() is null) continue;
|
if (method.GetCustomAttribute<BITAttribute>() is null&& method.GetCustomAttribute<ContextMenu>() is null) continue;
|
||||||
if (method.GetParameters().Length is not 0) continue;
|
if (method.GetParameters().Length is not 0) continue;
|
||||||
var button = new Button(() =>
|
var button = new Button(() =>
|
||||||
{
|
{
|
||||||
|
|
|
@ -11,6 +11,8 @@ using Newtonsoft.Json.Serialization;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using UnityEngine.UIElements;
|
using UnityEngine.UIElements;
|
||||||
|
using Object = UnityEngine.Object;
|
||||||
|
|
||||||
namespace BITKit
|
namespace BITKit
|
||||||
{
|
{
|
||||||
public static partial class MathQ
|
public static partial class MathQ
|
||||||
|
@ -34,6 +36,22 @@ namespace BITKit
|
||||||
}
|
}
|
||||||
public static partial class MathV
|
public static partial class MathV
|
||||||
{
|
{
|
||||||
|
public static Matrix4x4 Rotate(Transform self, Vector3 center, Vector3 euler)
|
||||||
|
{
|
||||||
|
// 计算物体与中心点的相对位置
|
||||||
|
Vector3 relativePosition = self.position - center;
|
||||||
|
|
||||||
|
// 使用欧拉角来计算旋转矩阵
|
||||||
|
Quaternion rotation = Quaternion.Euler(euler);
|
||||||
|
|
||||||
|
// 计算旋转后的相对位置
|
||||||
|
Vector3 rotatedPosition = rotation * relativePosition;
|
||||||
|
|
||||||
|
var newPosition = center + rotatedPosition;
|
||||||
|
var newRotation = rotation * self.rotation;
|
||||||
|
|
||||||
|
return Matrix4x4.TRS(newPosition, newRotation, Vector3.one);
|
||||||
|
}
|
||||||
public static Vector3 CalculateTorque(Transform transform,Quaternion targetRotation)
|
public static Vector3 CalculateTorque(Transform transform,Quaternion targetRotation)
|
||||||
{
|
{
|
||||||
var deltaRot = targetRotation * Quaternion.Inverse(transform.rotation);
|
var deltaRot = targetRotation * Quaternion.Inverse(transform.rotation);
|
||||||
|
@ -157,6 +175,12 @@ namespace BITKit
|
||||||
return direction.sqrMagnitude < factor; */
|
return direction.sqrMagnitude < factor; */
|
||||||
return Vector3.Angle(vectorX, vectorY) < 8;
|
return Vector3.Angle(vectorX, vectorY) < 8;
|
||||||
}
|
}
|
||||||
|
public static Vector2 TransientRotationAxis(Vector2 transientAxis)
|
||||||
|
{
|
||||||
|
transientAxis.x = TransientRotationAxis(transientAxis.x);
|
||||||
|
transientAxis.y = TransientRotationAxis(transientAxis.y);
|
||||||
|
return transientAxis;
|
||||||
|
}
|
||||||
public static Vector3 TransientRotationAxis(Vector3 transientAxis)
|
public static Vector3 TransientRotationAxis(Vector3 transientAxis)
|
||||||
{
|
{
|
||||||
transientAxis.x = TransientRotationAxis(transientAxis.x);
|
transientAxis.x = TransientRotationAxis(transientAxis.x);
|
||||||
|
@ -218,18 +242,18 @@ namespace BITKit
|
||||||
}
|
}
|
||||||
public static float TransientRotationAxis(this float transientAxis)
|
public static float TransientRotationAxis(this float transientAxis)
|
||||||
{
|
{
|
||||||
return (transientAxis %= 360) switch
|
return (transientAxis %= 360f) switch
|
||||||
{
|
{
|
||||||
> 180 => transientAxis - 360,
|
> 180f => transientAxis - 360f,
|
||||||
< -180 => transientAxis + 360,
|
< -180f => transientAxis + 360f,
|
||||||
_ => transientAxis,
|
_ => transientAxis,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
public static float WrapAngle(float angle)
|
public static float WrapAngle(float angle)
|
||||||
{
|
{
|
||||||
angle %= 360;
|
angle %= 360f;
|
||||||
if (angle > 180)
|
if (angle > 180f)
|
||||||
return angle - 360;
|
return angle - 360f;
|
||||||
|
|
||||||
return angle;
|
return angle;
|
||||||
}
|
}
|
||||||
|
@ -455,16 +479,23 @@ namespace BITKit
|
||||||
self.TryGetValue(key, out value);
|
self.TryGetValue(key, out value);
|
||||||
return value; ;
|
return value; ;
|
||||||
}
|
}
|
||||||
public static void DestoryChilds(this GameObject self)
|
public static void DestoryChilds(this GameObject self,bool immediately=false)
|
||||||
{
|
{
|
||||||
if (self)
|
if (!self) return;
|
||||||
|
|
||||||
|
var list = self.GetComponentsInChildren<Transform>().ToList();
|
||||||
|
list.TryRemove(self.transform);
|
||||||
|
foreach (var x in list)
|
||||||
{
|
{
|
||||||
var list = self.GetComponentsInChildren<Transform>().ToList();
|
if (immediately)
|
||||||
list.TryRemove(self.transform);
|
|
||||||
list.ForEach(x =>
|
|
||||||
{
|
{
|
||||||
GameObject.Destroy(x.gameObject);
|
Object.DestroyImmediate(x.gameObject);
|
||||||
});
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Object.Destroy(x.gameObject);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static bool Contains(this string self, IEnumerable<string> strs, out string key)
|
public static bool Contains(this string self, IEnumerable<string> strs, out string key)
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
{
|
|
||||||
"name": "BITKit.WorldNode.Runtime",
|
|
||||||
"rootNamespace": "",
|
|
||||||
"references": [
|
|
||||||
"GUID:14fe60d984bf9f84eac55c6ea033a8f4",
|
|
||||||
"GUID:508392158bd966c4d9c21e19661a441d",
|
|
||||||
"GUID:d525ad6bd40672747bde77962f1c401e",
|
|
||||||
"GUID:49b49c76ee64f6b41bf28ef951cb0e50",
|
|
||||||
"GUID:d8b63aba1907145bea998dd612889d6b",
|
|
||||||
"GUID:1193c2664d97cc049a6e4c486c6bce71",
|
|
||||||
"GUID:d750d221812bb1d48baff92e6ef73e28"
|
|
||||||
],
|
|
||||||
"includePlatforms": [],
|
|
||||||
"excludePlatforms": [],
|
|
||||||
"allowUnsafeCode": false,
|
|
||||||
"overrideReferences": false,
|
|
||||||
"precompiledReferences": [],
|
|
||||||
"autoReferenced": true,
|
|
||||||
"defineConstraints": [],
|
|
||||||
"versionDefines": [],
|
|
||||||
"noEngineReferences": false
|
|
||||||
}
|
|
|
@ -136,4 +136,3 @@ Material:
|
||||||
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
|
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
|
||||||
- _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1}
|
- _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1}
|
||||||
m_BuildTextureStacks: []
|
m_BuildTextureStacks: []
|
||||||
m_AllowLocking: 1
|
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
fileFormatVersion: 2
|
|
||||||
guid: 300c66b95bcadb345ba713cc787c90de
|
|
||||||
folderAsset: yes
|
|
||||||
DefaultImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
|
@ -1,16 +0,0 @@
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace BITKit.GameSocket
|
|
||||||
{
|
|
||||||
public interface ISocketComponent
|
|
||||||
{
|
|
||||||
public string Name { get; }
|
|
||||||
public object Object { get; }
|
|
||||||
}
|
|
||||||
public interface ISocketService:IReadOnlyDictionary<string,ISocketComponent>
|
|
||||||
{
|
|
||||||
void Initialize();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace BITKit.GameSocket
|
|
||||||
{
|
|
||||||
public class UnitySocketComponent : MonoBehaviour,ISocketComponent
|
|
||||||
{
|
|
||||||
[SerializeReference,SubclassSelector] private IReference nameReference;
|
|
||||||
public string Name => nameReference.Value;
|
|
||||||
public object Object => transform;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,50 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using AYellowpaper.SerializedCollections;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace BITKit.GameSocket
|
|
||||||
{
|
|
||||||
public class UnitySocketService : MonoBehaviour,ISocketService
|
|
||||||
{
|
|
||||||
private readonly Dictionary<string, ISocketComponent> _sockets=new();
|
|
||||||
public void Initialize()
|
|
||||||
{
|
|
||||||
_sockets.Clear();
|
|
||||||
foreach (var x in GetComponentsInChildren<ISocketComponent>())
|
|
||||||
{
|
|
||||||
_sockets.Add(x.Name, x);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerator<KeyValuePair<string, ISocketComponent>> GetEnumerator()
|
|
||||||
{
|
|
||||||
return _sockets.GetEnumerator();
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator()
|
|
||||||
{
|
|
||||||
return _sockets.GetEnumerator();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Count => _sockets.Count;
|
|
||||||
|
|
||||||
public bool ContainsKey(string key)
|
|
||||||
{
|
|
||||||
return _sockets.ContainsKey(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TryGetValue(string key, out ISocketComponent value)
|
|
||||||
{
|
|
||||||
return _sockets.TryGetValue(key, out value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ISocketComponent this[string key] => _sockets[key];
|
|
||||||
|
|
||||||
public IEnumerable<string> Keys => _sockets.Keys;
|
|
||||||
|
|
||||||
public IEnumerable<ISocketComponent> Values => _sockets.Values;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
fileFormatVersion: 2
|
|
||||||
guid: 8284a08494909e147b79d71c7142ed12
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
|
@ -526,3 +526,122 @@ TabContainer > * {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transition-duration: 0.1s;
|
transition-duration: 0.1s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OnScreenButton {
|
||||||
|
width: 80px;
|
||||||
|
height: 80px;
|
||||||
|
border-top-left-radius: 64px;
|
||||||
|
border-top-right-radius: 64px;
|
||||||
|
border-bottom-right-radius: 64px;
|
||||||
|
border-bottom-left-radius: 64px;
|
||||||
|
-unity-background-image-tint-color: rgb(255, 255, 255);
|
||||||
|
border-top-width: 1px;
|
||||||
|
border-right-width: 1px;
|
||||||
|
border-bottom-width: 1px;
|
||||||
|
border-left-width: 1px;
|
||||||
|
border-top-color: rgb(255, 255, 255);
|
||||||
|
border-left-color: rgb(255, 255, 255);
|
||||||
|
border-right-color: rgb(255, 255, 255);
|
||||||
|
border-bottom-color: rgb(255, 255, 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
OnScreenButton:hover {
|
||||||
|
background-color: rgba(200, 200, 200, 0.5);
|
||||||
|
-unity-background-image-tint-color: rgb(255, 255, 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
OnScreenButton:active {
|
||||||
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
|
-unity-background-image-tint-color: rgb(255, 255, 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
OnScreenButton.selected {
|
||||||
|
border-left-color: rgb(255, 0, 0);
|
||||||
|
border-right-color: rgb(255, 0, 0);
|
||||||
|
border-top-color: rgb(255, 0, 0);
|
||||||
|
border-bottom-color: rgb(255, 0, 0);
|
||||||
|
border-top-width: 4px;
|
||||||
|
border-right-width: 4px;
|
||||||
|
border-bottom-width: 4px;
|
||||||
|
border-left-width: 4px;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gamepad-button {
|
||||||
|
border-left-color: rgb(255, 255, 255);
|
||||||
|
border-right-color: rgb(255, 255, 255);
|
||||||
|
border-top-color: rgb(255, 255, 255);
|
||||||
|
border-bottom-color: rgb(255, 255, 255);
|
||||||
|
border-top-width: 1px;
|
||||||
|
border-right-width: 1px;
|
||||||
|
border-bottom-width: 1px;
|
||||||
|
border-left-width: 1px;
|
||||||
|
margin-top: 4px;
|
||||||
|
margin-right: 4px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gamepad-button:hover {
|
||||||
|
border-left-color: rgb(255, 255, 255);
|
||||||
|
border-right-color: rgb(255, 255, 255);
|
||||||
|
border-top-color: rgb(255, 255, 255);
|
||||||
|
border-bottom-color: rgb(255, 255, 255);
|
||||||
|
border-top-width: 1px;
|
||||||
|
border-right-width: 1px;
|
||||||
|
border-bottom-width: 1px;
|
||||||
|
border-left-width: 1px;
|
||||||
|
background-color: rgba(255, 255, 255, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
.gamepad-button:active {
|
||||||
|
background-color: rgba(255, 255, 255, 0.5);
|
||||||
|
-unity-background-image-tint-color: rgba(0, 0, 0, 0.5);
|
||||||
|
border-left-color: rgba(0, 0, 0, 0.5);
|
||||||
|
border-right-color: rgba(0, 0, 0, 0.5);
|
||||||
|
border-top-color: rgba(0, 0, 0, 0.5);
|
||||||
|
border-bottom-color: rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.gamepad-button--nw {
|
||||||
|
background-image: url("project://database/Assets/BITKit/Unity/Art/Icons/Arrows/icon_keyboard-arrow-up-left-rounded.png?fileID=21300000&guid=e2a7dc01d1a854b429e7698649c340bd&type=3#icon_keyboard-arrow-up-left-rounded");
|
||||||
|
transform-origin: right bottom;
|
||||||
|
scale: 0.8 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gamepad-button--n {
|
||||||
|
background-image: url("project://database/Assets/BITKit/Unity/Art/Icons/Arrows/icon_keyboard-arrow-up-rounded.png?fileID=21300000&guid=f75638302ccf8ba41acbf96be794e86d&type=3#icon_keyboard-arrow-up-rounded");
|
||||||
|
}
|
||||||
|
|
||||||
|
.gamepad-button--ne {
|
||||||
|
background-image: url("project://database/Assets/BITKit/Unity/Art/Icons/Arrows/icon_keyboard-arrow-up-right-rounded.png?fileID=21300000&guid=08e2edf7cdff08240a792ce62c67014d&type=3#icon_keyboard-arrow-up-right-rounded");
|
||||||
|
transform-origin: left bottom;
|
||||||
|
scale: 0.8 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gamepad-button--w {
|
||||||
|
background-image: url("project://database/Assets/BITKit/Unity/Art/Icons/Arrows/icon_chevron-left-rounded.png?fileID=21300000&guid=76da1f1cbb542714283e16db9aa8af7c&type=3#icon_chevron-left-rounded");
|
||||||
|
}
|
||||||
|
|
||||||
|
.gamepad-button--c {
|
||||||
|
}
|
||||||
|
|
||||||
|
.gamepad-button--e {
|
||||||
|
background-image: url("project://database/Assets/BITKit/Unity/Art/Icons/Arrows/icon_chevron-right-rounded.png?fileID=21300000&guid=9e83d4b468bd75a47ab3d72155f367e5&type=3#icon_chevron-right-rounded");
|
||||||
|
}
|
||||||
|
|
||||||
|
.gamepad-button--sw {
|
||||||
|
background-image: url("project://database/Assets/BITKit/Unity/Art/Icons/Arrows/icon_keyboard-arrow-down-left-rounded.png?fileID=21300000&guid=93b327f2e8bb65f40a1b47d13ecfafcf&type=3#icon_keyboard-arrow-down-left-rounded");
|
||||||
|
transform-origin: right top;
|
||||||
|
scale: 0.8 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gamepad-button--s {
|
||||||
|
background-image: url("project://database/Assets/BITKit/Unity/Art/Icons/icon_keyboard-arrow-down.png?fileID=21300000&guid=6f14c0574452bf543b5f2f2cd2a24104&type=3#icon_keyboard-arrow-down");
|
||||||
|
}
|
||||||
|
|
||||||
|
.gamepad-button--se {
|
||||||
|
background-image: url("project://database/Assets/BITKit/Unity/Art/Icons/Arrows/icon_keyboard-arrow-down-right-rounded.png?fileID=21300000&guid=6103653931b39ca41a64af379712495c&type=3#icon_keyboard-arrow-down-right-rounded");
|
||||||
|
transform-origin: left top;
|
||||||
|
scale: 0.8 0.8;
|
||||||
|
}
|
||||||
|
|
|
@ -13,13 +13,9 @@ MonoBehaviour:
|
||||||
m_Name: Common_Mobile
|
m_Name: Common_Mobile
|
||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
themeUss: {fileID: -4733365628477956816, guid: ac803f0924e239645ac6b2fc9baebc65, type: 3}
|
themeUss: {fileID: -4733365628477956816, guid: ac803f0924e239645ac6b2fc9baebc65, type: 3}
|
||||||
m_DisableNoThemeWarning: 0
|
|
||||||
m_TargetTexture: {fileID: 0}
|
m_TargetTexture: {fileID: 0}
|
||||||
m_RenderMode: 0
|
|
||||||
m_WorldSpaceLayer: 0
|
|
||||||
m_ScaleMode: 2
|
m_ScaleMode: 2
|
||||||
m_ReferenceSpritePixelsPerUnit: 100
|
m_ReferenceSpritePixelsPerUnit: 100
|
||||||
m_PixelsPerUnit: 100
|
|
||||||
m_Scale: 1
|
m_Scale: 1
|
||||||
m_ReferenceDpi: 96
|
m_ReferenceDpi: 96
|
||||||
m_FallbackDpi: 96
|
m_FallbackDpi: 96
|
||||||
|
@ -28,11 +24,9 @@ MonoBehaviour:
|
||||||
m_Match: 1
|
m_Match: 1
|
||||||
m_SortingOrder: 0
|
m_SortingOrder: 0
|
||||||
m_TargetDisplay: 0
|
m_TargetDisplay: 0
|
||||||
m_BindingLogLevel: 0
|
|
||||||
m_ClearDepthStencil: 1
|
m_ClearDepthStencil: 1
|
||||||
m_ClearColor: 0
|
m_ClearColor: 0
|
||||||
m_ColorClearValue: {r: 0, g: 0, b: 0, a: 0}
|
m_ColorClearValue: {r: 0, g: 0, b: 0, a: 0}
|
||||||
m_VertexBudget: 0
|
|
||||||
m_DynamicAtlasSettings:
|
m_DynamicAtlasSettings:
|
||||||
m_MinAtlasSize: 8
|
m_MinAtlasSize: 8
|
||||||
m_MaxAtlasSize: 4096
|
m_MaxAtlasSize: 4096
|
||||||
|
@ -41,6 +35,4 @@ MonoBehaviour:
|
||||||
m_AtlasBlitShader: {fileID: 9101, guid: 0000000000000000f000000000000000, type: 0}
|
m_AtlasBlitShader: {fileID: 9101, guid: 0000000000000000f000000000000000, type: 0}
|
||||||
m_RuntimeShader: {fileID: 9100, guid: 0000000000000000f000000000000000, type: 0}
|
m_RuntimeShader: {fileID: 9100, guid: 0000000000000000f000000000000000, type: 0}
|
||||||
m_RuntimeWorldShader: {fileID: 9102, guid: 0000000000000000f000000000000000, type: 0}
|
m_RuntimeWorldShader: {fileID: 9102, guid: 0000000000000000f000000000000000, type: 0}
|
||||||
m_ICUDataAsset: {fileID: 0}
|
|
||||||
forceGammaRendering: 0
|
|
||||||
textSettings: {fileID: 0}
|
textSettings: {fileID: 0}
|
||||||
|
|
|
@ -12,8 +12,7 @@ MonoBehaviour:
|
||||||
m_Script: {fileID: 19101, guid: 0000000000000000e000000000000000, type: 0}
|
m_Script: {fileID: 19101, guid: 0000000000000000e000000000000000, type: 0}
|
||||||
m_Name: Common_PC_Overlay
|
m_Name: Common_PC_Overlay
|
||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
themeUss: {fileID: -4733365628477956816, guid: ac803f0924e239645ac6b2fc9baebc65,
|
themeUss: {fileID: -4733365628477956816, guid: ac803f0924e239645ac6b2fc9baebc65, type: 3}
|
||||||
type: 3}
|
|
||||||
m_TargetTexture: {fileID: 0}
|
m_TargetTexture: {fileID: 0}
|
||||||
m_ScaleMode: 2
|
m_ScaleMode: 2
|
||||||
m_ReferenceSpritePixelsPerUnit: 100
|
m_ReferenceSpritePixelsPerUnit: 100
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
.rank {
|
|
||||||
}
|
|
||||||
|
|
||||||
.D1 .rank {
|
|
||||||
background-image: url("project://database/Assets/Artists/UX/USS_1/UI/UI_Settlement/%E7%AC%AC1%E5%90%8D.png?fileID=2800000&guid=24cbc98f27967534189bd6172d815874&type=3#第1名");
|
|
||||||
}
|
|
||||||
|
|
||||||
.D2 .rank {
|
|
||||||
background-image: url("project://database/Assets/Artists/UX/USS_1/UI/UI_Settlement/%E7%AC%AC2%E5%90%8D.png?fileID=2800000&guid=75f797e60a65f654cbfece5f451ec695&type=3#第2名");
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue