This commit is contained in:
CortexCore
2024-03-31 23:31:00 +08:00
parent e179d2eb53
commit b7b89ee71a
641 changed files with 31286 additions and 22134 deletions

View File

@@ -1,19 +1,116 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using AYellowpaper.SerializedCollections;
using UnityEngine;
using YooAsset;
using Object = UnityEngine.Object;
using Random = UnityEngine.Random;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace BITKit
{
public class AddressableHelper
public class AddressableHelper:MonoBehaviour
{
public static string GetAddressablePath(Object obj)
private static IDictionary<ulong,string> PathsById { get; } = new Dictionary<ulong, string>();
public static T Get<T>(ulong id) where T : Object
{
#if UNITY_EDITOR
return string.Empty;
#else
throw new NotImplementedException();
#endif
var task = YooAssets.LoadAssetAsync<T>(PathsById[id]);
task.WaitForAsyncComplete();
return task.AssetObject.As<T>();
}
[SerializeField] private SerializedDictionary<ulong,string> pathsById;
private void Start()
{
PathsById.Clear();
foreach (var x in pathsById)
{
PathsById.Add(x.Key,x.Value);
}
}
#if UNITY_EDITOR
[BIT]
private void BuildCache()
{
var guids = AssetDatabase.FindAssets($"t:Object",new[] {"Assets"});
var paths = guids.Select(AssetDatabase.GUIDToAssetPath);
var objects = new List<IAddressable>();
var stringBuilder = new System.Text.StringBuilder();
foreach (var path in paths)
{
var asset = AssetDatabase.LoadAssetAtPath<Object>(path);
switch (asset)
{
case GameObject go when go.TryGetComponent(out IAddressable addressable):
objects.Add(addressable);
break;
case IAddressable addressable:
objects.Add(addressable);
break;
}
}
stringBuilder.AppendLine($"所有资源数量:{guids.Length},其中包含{objects.Count}个Addressable资源");
pathsById.Clear();
foreach (var x in objects)
{
if (x is not Object unityObject) continue;
//if (x.AddressableId is ulong.MinValue or ulong.MaxValue)
{
x.AddressableId = RandomUlong.NextUlong;
EditorUtility.SetDirty(unityObject);
}
try
{
if (x.AddressableId is not ulong.MinValue && !string.IsNullOrEmpty(x.AddressablePath))
{
if (pathsById.TryAdd(x.AddressableId, x.AddressablePath))
{
}
else
{
stringBuilder.AppendLine($"资源{unityObject.name}的AddressableId:{x.AddressableId}已经存在");
}
}
else
{
stringBuilder.AppendLine($"{unityObject.name}的AddressableId或AddressablePath为空");
}
}
catch (Exception e)
{
stringBuilder.AppendLine($"{unityObject.name}遇到了错误:{e.Message}");
}
}
EditorUtility.SetDirty(this);
Debug.Log(stringBuilder);
}
#endif
}
public static class RandomUlong
{
private static readonly System.Random _random = new();
public static ulong NextUlong
{
get
{
var buf = new byte[8];
_random.NextBytes(buf);
return BitConverter.ToUInt64(buf, 0);
}
}
}
}

View File

@@ -9,8 +9,18 @@ namespace BITKit
private void OnAnimatorMove()
{
if (root is not null)
root.SendMessage(nameof(OnAnimatorMove));
if (root)
root.SendMessageUpwards(nameof(OnAnimatorMove),SendMessageOptions.DontRequireReceiver);
}
private void AIAnimationEvent(string actionName)
{
if (root)
root.SendMessage(nameof(AIAnimationEvent), actionName,SendMessageOptions.DontRequireReceiver);
}
public void AnimationEvent(string eventName)
{
if(root)
root.SendMessage(nameof(AnimationEvent), eventName,SendMessageOptions.DontRequireReceiver);
}
}
}

View File

@@ -7,15 +7,23 @@ namespace BITKit.Animations
{
public class OverrideAnimatorFallbackController : MonoBehaviour
{
[SerializeField,ReadOnly] private bool _isOverride;
[SerializeField, ReadOnly] private bool _isOverride;
[SerializeField, ReadOnly] private string _buildReport="None";
[SerializeField] private AnimatorOverrideController overrideController;
[SerializeField] private AnimatorOverrideController[] additionalOverrideControllers;
private void Start()
{
if (!overrideController) return;
if (!TryGetComponent<Animator>(out var animator) ||
animator.runtimeAnimatorController is not AnimatorOverrideController sourceController) return;
animator.runtimeAnimatorController = sourceController.CopyAndFillMissingContent(overrideController);
var controller = sourceController.CopyAndFillMissingContent(overrideController);
foreach (var additional in additionalOverrideControllers)
{
controller = controller.CopyAndFillMissingContent(additional);
}
animator.runtimeAnimatorController = controller;
_isOverride = true;
}
}

View File

@@ -195,6 +195,7 @@ namespace BITKit.Animations
private void Update()
{
if (!animator.runtimeAnimatorController) return;
for (var i = 0; i < animator.layerCount; i++)
{
this[i].currentState = animator.GetCurrentAnimatorStateInfo(i);

View File

@@ -3,6 +3,7 @@ using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using BITKit.IO;
using BITKit.UX;
using Cysharp.Threading.Tasks;
using UnityEngine;
@@ -39,105 +40,153 @@ namespace BITKit
// BIT4Log.Log<BITFramework>($"BITFramework加载完成,耗时:{Stopwatch.ElapsedMilliseconds}ms");
// }
[SerializeField] private string addressableName;
[SerializeField] private UXBar progressBar;
[SerializeField] private UIDocument document;
[SerializeField] private UXLabel progressLabel;
[SerializeReference, SubclassSelector] private IReference addressableName;
[SerializeReference, SubclassSelector] private IReference packageName = new Reference("DefaultPackages");
[SerializeReference, SubclassSelector] private IRemoteServices remoteServices;
[SerializeReference, SubclassSelector] private IBuildinQueryServices buildinQueryServices;
[SerializeField] private UIDocument document;
[SerializeField] private bool isOffline;
[SerializeField] private bool IsEditorSimulateMode;
private float CurrentOpacity
{
get => document.rootVisualElement.GetOpacity();
set => document.rootVisualElement.SetOpacity(value);
}
[UXBindPath("progress-bar")]
private ProgressBar _progressBar;
[UXBindPath("progress-label")]
private Label _progressLabel;
private async void Start()
{
#if UNITY_EDITOR
#else
IsEditorSimulateMode=false;
#endif
progressBar.Set(0f);
var stopwatch = new Stopwatch();
stopwatch.Start();
DontDestroyOnLoad(gameObject);
// 初始化资源系统
YooAssets.Initialize();
const string PackageName = "DefaultPackages";
// 创建默认的资源包
var package = YooAssets.TryGetPackage(PackageName) ?? YooAssets.CreatePackage(PackageName);
// 设置该资源包为默认的资源包可以使用YooAssets相关加载接口加载该资源包内容。
YooAssets.SetDefaultPackage(package);
const string defaultHostServer = "http://127.0.0.1/CDN/PC/v1.0";
const string fallbackHostServer = "http://127.0.0.1/CDN/PC/v1.0";
InitializeParameters initParameters = new HostPlayModeParameters
try
{
BuildinQueryServices = new GameQueryServices(),
RemoteServices = new RemoteServices(defaultHostServer, fallbackHostServer)
};
if (IsEditorSimulateMode)
{
var editorParameters = new EditorSimulateModeParameters
#if UNITY_EDITOR
#else
IsEditorSimulateMode = false;
#endif
UXUtils.Inject(this);
_progressBar.value=0f;
var stopwatch = new Stopwatch();
stopwatch.Start();
DontDestroyOnLoad(gameObject);
// 初始化资源系统
YooAssets.Initialize();
// 创建默认的资源包
var package = YooAssets.TryGetPackage(packageName.Value) ?? YooAssets.CreatePackage(packageName.Value);
// 设置该资源包为默认的资源包可以使用YooAssets相关加载接口加载该资源包内容。
YooAssets.SetDefaultPackage(package);
InitializeParameters initParameters = new HostPlayModeParameters
{
SimulateManifestFilePath = EditorSimulateModeHelper.SimulateBuild("BuiltinBuildPipeline",PackageName)
BuildinQueryServices = buildinQueryServices,
RemoteServices = remoteServices
};
initParameters = editorParameters;
}
var initOperation = package.InitializeAsync(initParameters);
progressLabel.Set("正在初始化资源系统...");
while (initOperation.IsDone is false)
{
await UniTask.NextFrame(destroyCancellationToken);
progressBar.Set(initOperation.Progress);
}
if (IsEditorSimulateMode)
{
var editorParameters = new EditorSimulateModeParameters
{
SimulateManifestFilePath =
EditorSimulateModeHelper.SimulateBuild("ScriptableBuildPipeline", packageName.Value)
};
initParameters = editorParameters;
}else if (isOffline)
{
initParameters = new OfflinePlayModeParameters();
}
progressLabel.Set("正在更新资源包版本...");
var operation = package.UpdatePackageVersionAsync();
while (operation.IsDone is false)
{
await UniTask.NextFrame(destroyCancellationToken);
progressBar.Set(operation.Progress);
}
InitializationOperation initOperation = null;
try
{
initOperation = package.InitializeAsync(initParameters);
_progressLabel.text ="正在初始化资源系统...";
}
catch (Exception e)
{
_progressLabel.text =e.Message;
if (operation.Status == EOperationStatus.Succeed)
{
//更新成功
string packageVersion = operation.PackageVersion;
Debug.Log($"Updated package Version : {packageVersion}");
}
else
{
//更新失败
Debug.LogError(operation.Error);
}
initParameters = new HostPlayModeParameters
{
BuildinQueryServices = buildinQueryServices,
RemoteServices = remoteServices
};
progressLabel.Set("正在初始化Framework");
var frameworkHandle = YooAssets.LoadAssetAsync<GameObject>(addressableName);
while (frameworkHandle.IsDone is false)
{
await UniTask.NextFrame(destroyCancellationToken);
progressBar.Set(frameworkHandle.Progress);
}
initOperation = package.InitializeAsync(initParameters);
}
var framework = Instantiate(frameworkHandle.AssetObject);
DontDestroyOnLoad(framework);
progressLabel.Set("已加载完成");
while (initOperation.IsDone is false)
{
await UniTask.NextFrame(destroyCancellationToken);
_progressBar.value =initOperation.Progress;
}
try
{
_progressLabel.text="正在更新资源包版本...";
var operation = package.UpdatePackageVersionAsync();
while (operation.IsDone is false)
{
await UniTask.NextFrame(destroyCancellationToken);
_progressBar.value = operation.Progress;
}
if (operation.Status == EOperationStatus.Succeed)
{
//更新成功
string packageVersion = operation.PackageVersion;
Debug.Log($"Updated package Version : {packageVersion}");
}
else
{
//更新失败
Debug.LogError(operation.Error);
}
}
catch (Exception e)
{
BIT4Log.LogException(e);
_progressLabel.text =e.Message;
}
stopwatch.Stop();
Destroy(document);
BIT4Log.Log<BITFramework>("BITFramework加载完成,耗时:" + stopwatch.ElapsedMilliseconds + "ms");
SceneManager.LoadScene(1);
if (addressableName is not null)
{
_progressLabel.text ="正在初始化Framework";
var frameworkHandle = YooAssets.LoadAssetAsync<GameObject>(addressableName.Value);
while (frameworkHandle.IsDone is false)
{
await UniTask.NextFrame(destroyCancellationToken);
_progressBar.value=frameworkHandle.Progress;
}
var framework = Instantiate(frameworkHandle.AssetObject);
DontDestroyOnLoad(framework);
_progressLabel.text="已加载完成";
BIT4Log.Log<BITFramework>("BITFramework加载完成,耗时:" + stopwatch.ElapsedMilliseconds + "ms");
}
stopwatch.Stop();
YooAssetUtils.RegisterPackage(packageName.Value);
YooAssetUtils.RegisterResourcePackage(package);
if (document)
Destroy(document);
SceneManager.LoadScene(1);
}
catch (Exception e)
{
_progressBar.value =0;
_progressLabel.text = e.Message;
}
}
private void OnDestroy()
@@ -146,23 +195,43 @@ namespace BITKit
}
}
public class GameQueryServices : IBuildinQueryServices
[Serializable]
public sealed class GameQueryServices : IBuildinQueryServices
{
public bool Query(string packageName, string fileName)
{
// 注意fileName包含文件格式
return StreamingAssetsHelper.FileExists(packageName, fileName);
}
public bool Query(string packageName, string fileName, string fileCRC)=>Query(packageName,fileName);
}
[Serializable]
public sealed class LocalQueryServices : IBuildinQueryServices
{
public readonly string Path;
public LocalQueryServices(string path)
{
Path = path;
}
public bool Query(string packageName, string fileName, string fileCRC)
{
return File.Exists(System.IO.Path.Combine(Path, fileName));
}
}
/// <summary>
/// 远端资源地址查询服务类
/// </summary>
public class RemoteServices : IRemoteServices
[Serializable]
public sealed class RemoteServices : IRemoteServices
{
private readonly string _defaultHostServer;
private readonly string _fallbackHostServer;
[SerializeField] private string _defaultHostServer;
[SerializeField] private string _fallbackHostServer;
public RemoteServices(){}
public RemoteServices(string defaultHostServer, string fallbackHostServer)
{
_defaultHostServer = defaultHostServer;

View File

@@ -5,7 +5,9 @@
"GUID:14fe60d984bf9f84eac55c6ea033a8f4",
"GUID:e34a5702dd353724aa315fb8011f08c3",
"GUID:f51ebe6a0ceec4240a699833d6309b23",
"GUID:6ef4ed8ff60a7aa4bb60a8030e6f4008"
"GUID:6ef4ed8ff60a7aa4bb60a8030e6f4008",
"GUID:d525ad6bd40672747bde77962f1c401e",
"GUID:49b49c76ee64f6b41bf28ef951cb0e50"
],
"includePlatforms": [],
"excludePlatforms": [],

View File

@@ -13,6 +13,8 @@ public class GameQueryServices : IBuildinQueryServices
// 注意fileName包含文件格式
return StreamingAssetsHelper.FileExists(packageName, fileName);
}
public bool Query(string packageName, string fileName, string fileCRC)=>Query(packageName,fileName);
}
/// <summary>

View File

@@ -0,0 +1,48 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using YooAsset;
namespace BITKit.IO
{
public class YooAssetUtils
{
[RuntimeInitializeOnLoadMethod]
private static void Reload()
{
OnPackageRegistered = null;
OnPackageUnregistered = null;
_registeredPackages.Clear();
_registeredResourcePackages.Clear();
}
public static event Action<string> OnPackageRegistered;
public static event Action<string> OnPackageUnregistered;
public static IEnumerable<string> RegisteredPackages => _registeredPackages.ToArray();
public static IEnumerable<ResourcePackage> RegisteredResourcePackages => _registeredResourcePackages.ToArray();
private static readonly List<ResourcePackage> _registeredResourcePackages = new();
private static readonly List<string> _registeredPackages = new();
public static void RegisterPackage(string packageName)
{
if (_registeredPackages.Contains(packageName))
{
return;
}
_registeredPackages.Add(packageName);
OnPackageRegistered?.Invoke(packageName);
}
public static void UnregisterPackage(string packageName)
{
if (!_registeredPackages.Contains(packageName))
{
return;
}
_registeredPackages.Remove(packageName);
OnPackageUnregistered?.Invoke(packageName);
}
public static void RegisterResourcePackage(ResourcePackage package)=>_registeredResourcePackages.Add(package);
public static void UnregisterResourcePackage(ResourcePackage package)=>_registeredResourcePackages.Remove(package);
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: e6b88c0718e45444c886e28026f920cc
guid: ec8acf90d1797fe46b793e0d1c2f24f4
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -5,11 +5,46 @@ using System.Diagnostics;
using UnityEngine;
using Cysharp.Threading.Tasks;
using System.Threading.Tasks;
using BITKit.UX;
using Cinemachine.Utility;
using UnityEngine.InputSystem;
using Debug = UnityEngine.Debug;
#if !UNITY_EDITOR
using UnityEngine;
using UnityEngine.Rendering;
public class SkipSplash
{
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSplashScreen)]
private static void BeforeSplashScreen()
{
#if UNITY_WEBGL
Application.focusChanged += Application_focusChanged;
#else
System.Threading.Tasks.Task.Run(AsyncSkip);
#endif
}
#if UNITY_WEBGL
private static void Application_focusChanged(bool obj)
{
Application.focusChanged -= Application_focusChanged;
SplashScreen.Stop(SplashScreen.StopBehavior.StopImmediate);
}
#else
private static void AsyncSkip()
{
SplashScreen.Stop(SplashScreen.StopBehavior.StopImmediate);
}
#endif
}
#endif
namespace BITKit
{
public class MouseNotOverGameViewException : System.Exception
{
public MouseNotOverGameViewException()
@@ -22,10 +57,11 @@ namespace BITKit
[Serializable]
public class OpenUrl:IAction
{
[SerializeField] private string url;
public void Execute()
[SerializeField] public string url;
[SerializeReference,SubclassSelector] public IReference urlReference;
public virtual void Execute()
{
Application.OpenURL(url);
Application.OpenURL(urlReference is not null?urlReference.Value:url);
}
}
@@ -43,6 +79,17 @@ namespace BITKit
}
public static bool IsPlaying { get;private set; }
public static bool IsPointerOverUI { get; set; }
public static bool IsEditor
{
get
{
#if UNITY_EDITOR
return true;
#endif
return false;
}
}
public static ValidHandle AllowCursor = new();
public static ValidHandle AllowTouchSupport = new();
public static GameObject GameObject;
@@ -59,6 +106,16 @@ namespace BITKit
public static void ThrowIfWindowNotFocus()
{
#if UNITY_EDITOR
switch (Camera.main)
{
case {} camera:
if (camera.pixelRect.Contains(Input.mousePosition) is false)
{
throw new MouseNotOverGameViewException();
}
break;
}
var window = UnityEditor.EditorWindow.focusedWindow;
var windowName = window is not null ? window.ToString() : string.Empty;
switch (windowName)
@@ -106,8 +163,9 @@ namespace BITKit
}
}
[BITCommand]
public static void Exit()
public static async void Exit()
{
await BITApp.SwitchToMainThread();
BITApp.Stop();
#if UNITY_EDITOR
UnityEditor.EditorApplication.isPlaying = false;

View File

@@ -228,7 +228,8 @@ namespace BITKit
private void OnView(InputAction.CallbackContext context)
{
if (allowInput.OnCheck() is false) return;
if (allowInput is { Allow: false }) return;
var playerConfig = PlayerConfig.Singleton;
var sensitivity = playerConfig.Sensitivity * playerConfig.M_Yaw;
var delta = context.ReadValue<Vector2>();
@@ -266,6 +267,7 @@ namespace BITKit
{
try
{
if (allowInput is { Allow: false }) return;
BITAppForUnity.ThrowIfWindowNotFocus();
switch (context.control.device)
{
@@ -309,6 +311,8 @@ namespace BITKit
private void OnEntry(InputAction.CallbackContext context)
{
if (allowInput is { Allow: false }) return;
if (context.started)
{
var delta = viewAction.action.ReadValue<Vector2>();
@@ -323,6 +327,8 @@ namespace BITKit
private void OnMovement(InputAction.CallbackContext context)
{
if (allowInput is { Allow: false }) return;
switch (context.control.device)
{
case Mouse mouse:

View File

@@ -9,9 +9,12 @@ namespace BITKit
{
private void Start()
{
foreach (var x in GetComponentsInChildren<SkinnedMeshRenderer>())
foreach (var x in GetComponentsInChildren<Renderer>(true))
{
x.updateWhenOffscreen = true;
if (x is SkinnedMeshRenderer skinnedMeshRenderer)
{
skinnedMeshRenderer.updateWhenOffscreen = true;
}
x.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
}
}

View File

@@ -6,7 +6,7 @@ namespace BITKit
public class AutoSetLayer : MonoBehaviour
{
public int layer;
void Start()
private void Start()
{
GetComponentsInChildren<Transform>(true).ForEach(x=>
{

View File

@@ -1,40 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Cysharp.Threading.Tasks;
namespace BITKit
{
public class EffectPlayer : MonoBehaviour
{
[Header(Constant.Header.Settings)]
[SerializeField] float duration;
[Header(Constant.Header.Components)]
[SerializeField] ParticleSystem[] particleSystems;
[SerializeField] Behaviour[] behaviours;
void Start()
{
particleSystems.ForEach(x => x.Stop());
behaviours.ForEach(x => x.enabled = false);
}
public async void Excute()
{
particleSystems.ForEach(x =>
{
x.time = 0;
x.Play(true);
});
behaviours.ForEach(x =>
{
x.enabled = true;
});
await UniTask.Delay(System.TimeSpan.FromSeconds(duration));
if (BehaviourHelper.Actived)
{
behaviours.ForEach(x =>
{
x.enabled = false;
});
}
}
}
}

View File

@@ -31,7 +31,7 @@ namespace BITKit
public override VisualElement CreateInspectorGUI()
{
CreateSubTitle("TextAsset Reader");
FillDefaultInspector(root, serializedObject, true);
FillDefaultInspector();
var excute = root.Create<Button>();
//excute.bindingPath = nameof(ReadFromTextAsset.Excute);

View File

@@ -24,7 +24,7 @@ namespace BITKit
{
public override VisualElement CreateInspectorGUI()
{
FillDefaultInspector(root, serializedObject, true);
FillDefaultInspector();
var slider = root.Create<Slider>();
slider.SetValueWithoutNotify(agent.asset.renderScale);

View File

@@ -14,6 +14,7 @@ namespace BITKit
[SerializeReference,SubclassSelector] private IProvider pingOutput;
[SerializeReference,SubclassSelector] private IProvider resolutionOutput;
[SerializeReference,SubclassSelector] private IProvider frameRateOutput;
[SerializeReference, SubclassSelector] private INetClient clientPing;
private readonly DeltaTimer timer = new();
private Ping ping;
[Header(Constant.Header.InternalVariables)]
@@ -28,7 +29,12 @@ namespace BITKit
if (fpsInterval.AllowUpdate)
fpsOutput.Set((string)timer);
if (pingOutput is not null)
if (clientPing is not null)
{
pingOutput.Set(clientPing.Ping.ToString());
}
else if (pingOutput is not null)
{
switch (ping)
{

View File

@@ -1,5 +1,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace BITKit
@@ -9,4 +11,22 @@ namespace BITKit
string GetConfig(params object[] args);
void Configure(params object[] args);
}
[Serializable]
public sealed class ConfigProviders:IConfigProvider
{
[SerializeReference,SubclassSelector] private IConfigProvider[] providers;
public string GetConfig(params object[] args)
{
return string.Join("\n",providers.Select(x=>x.GetConfig(args)));
}
public void Configure(params object[] args)
{
foreach (var provider in providers)
{
provider.Configure(args);
}
}
}
}

View File

@@ -9,6 +9,6 @@ namespace BITKit
public float Sensitivity = 1.81f;
public float TouchSensitivity = 0.22f;
public float M_Yaw = 0.022f;
public float Fov = 75;
public float Fov = 90;
}
}

View File

@@ -3,12 +3,29 @@ using System.Collections;
using System.Collections.Generic;
using System.IO;
using BITKit;
using BITKit.Core.Tuple;
using UnityEngine;
using UnityEngine.Rendering;
namespace BITKit
{
[Serializable]
public sealed class CommandConfigProvider:IConfigProvider
{
[SerializeField] private UnityTuple<string, string>[] pairs;
public string GetConfig(params object[] args)
{
return string.Join("\n",pairs);
}
public void Configure(params object[] args)
{
foreach (var pair in pairs)
{
BITCommands.Excute($"set {pair.Item1} {pair.Item2}");
}
}
}
public class ScriptableExec : MonoBehaviour
{
[SerializeReference,SubclassSelector] private IConfigProvider configProvider;

View File

@@ -1,12 +1,20 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
#if RH_SerializedDictionary
using RotaryHeart.Lib.SerializableDictionary;
#endif
using AYellowpaper.SerializedCollections;
namespace BITKit
{
public sealed class TranslateSO : ScriptableObject
{
#if RH_SerializedDictionary
public SerializableDictionaryBase<string, string> dictionary = new();
#else
public SerializedDictionary<string, string> dictionary = new();
#endif
public string Get(string text, bool isLocalization = true)
{
foreach (var word in dictionary)
@@ -14,7 +22,11 @@ namespace BITKit
var value = word.Value;
if (isLocalization)
{
value = DI.Get<ITranslator>().Translate(value);
try
{
value = DI.Get<ITranslator>().Translate(value);
}
catch (NullReferenceException){}
}
text = text.Replace(word.Key, value);
}
@@ -22,11 +34,18 @@ namespace BITKit
}
public string GetAt(string key, bool isLocalization = true)
{
var translater = DI.Get<ITranslator>();
if (dictionary.TryGetValue(key, out var value))
{
if (isLocalization)
value = translater.Translate(value);
try
{
if (isLocalization)
{
var translater = DI.Get<ITranslator>();
value = translater.Translate(value);
}
}
catch (NullReferenceException){}
return value;
}
else

View File

@@ -1,5 +1,6 @@
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;
@@ -10,12 +11,86 @@ using UnityEngine.InputSystem;
using Cysharp.Threading.Tasks;
using System.Text;
using System.IO;
using System.Reflection;
using System.Reflection.Emit;
using Google.Apis.Http;
using UnityEngine.InputSystem.Interactions;
using Label = UnityEngine.UIElements.Label;
// ReSharper disable PossibleMultipleEnumeration
namespace BITKit.Console
{
public class BITConsole : MonoBehaviour
{
[RuntimeInitializeOnLoadMethod]
private static void Reload()
{
Application.logMessageReceivedThreaded += EnqueueLog;
}
private class CommandSelector
{
public VisualElement Container { get; set; }
public int Index
{
get => _index;
set
{
if (_methods.Length is 0)
{
_index = -1;
return;
}
_index = (value+_methods.Length)%_methods.Length;
Rebuild();
}
}
public event Action<MethodInfo> OnSelected;
private int _index;
private MethodInfo[] _methods=Array.Empty<MethodInfo>();
public void Rebuild()
{
Container.Clear();
for (var i = 0; i < _methods.Length; i++)
{
var method = _methods[i];
var button = Container.Create<Button>();
StringBuilder stringBuilder = new(method.Name);
foreach (var parameterInfo in method.GetParameters())
{
stringBuilder.Append($" {parameterInfo.ParameterType.Name}:{parameterInfo.Name}");
}
button.clicked+= () =>
{
OnSelected?.Invoke(method);
Rebuild();
};
button.text = stringBuilder.ToString();
Container.Add(button);
}
}
public void SetMethods(IEnumerable<MethodInfo> methods)
{
if (methods.IsValid())
{
if (_methods.SequenceEqual(methods)) return;
}
_methods=methods.IsValid()?methods.ToArray():Array.Empty<MethodInfo>();
if (_methods!.Length is 0)
{
_index = -1;
}
Rebuild();
}
}
[BITCommand]
public static async void Clear()
{
@@ -23,75 +98,92 @@ namespace BITKit.Console
singleton.outputString.Clear();
singleton.text.text = string.Empty;
}
static BITConsole singleton;
const string textFieldName = "TextField";
const string commandListViewName = "commands-listview";
const string textName = "Text";
const string scrollViewName = "context-scrollview";
private static BITConsole singleton;
[SerializeField] private UIDocument document;
[SerializeReference] private InputActionReference toggleAction;
[SerializeReference] public InputActionReference nextOrPreviousAction;
private static ConcurrentQueue<(string condition, string stackTrace, LogType type)> logQueue = new();
private static void EnqueueLog(string condition, string stackTrace, LogType type)
{
logQueue.Enqueue((condition, stackTrace, type));
}
private readonly InputActionGroup _inputActionGroup=new()
{
allowGlobalActivation = false
};
public int logLineLimit = 64;
private ListView commandListView;
[UXBindPath("commands-container")]
private VisualElement commandContainer;
[UXBindPath("TextField")]
private TextField textField;
[UXBindPath("Text")]
private Label text;
[UXBindPath( "context-scrollview")]
private ScrollView scrollView;
private bool isActived;
private bool _isRunning;
private List<string> outputString = new();
private void Awake()
{
Application.logMessageReceivedThreaded += LogCallback;
}
private CommandSelector _commandSelector;
private void Start()
{
UXUtils.Inject(this);
_commandSelector = new()
{
Container = commandContainer,
};
_commandSelector.OnSelected += x =>
{
textField.SetValueWithoutNotify(x.Name);
textField.Blur();
textField.Focus();
};
singleton = this;
var visualElement = document.rootVisualElement;
textField = visualElement.Q<TextField>(textFieldName);
commandListView = visualElement.Q<ListView>(commandListViewName);
text = visualElement.Q<Label>(textName);
scrollView = visualElement.Q<ScrollView>(scrollViewName);
textField.RegisterValueChangedCallback(OnTextFieldValieChanged);
textField.RegisterValueChangedCallback(OnTextFieldValueChanged);
textField.RegisterCallback<KeyDownEvent>(OnKeyDown);
commandListView.selectionChanged += OnSelectionChange;
nextOrPreviousAction.action.performed += OnNextCommand;
text.text = string.Empty;
BIT4Log.OnNextLine += () =>
{
if (outputString.Count is not 0 && outputString.Last() != string.Empty)
outputString.Add(string.Empty);
};
commandListView.SetActive(false);
_inputActionGroup.RegisterCallback(toggleAction,Toggle);
_inputActionGroup.RegisterCallback(nextOrPreviousAction, OnNextCommand);
//_inputActionGroup.RegisterCallback(nextOrPreviousAction, OnNextCommand);
_inputActionGroup.allowInput.AddElement(this);
Toggle(false);
BIT4Log.OnNextLine += OnNextLine;
destroyCancellationToken.Register(() =>
{
BIT4Log.OnNextLine -= OnNextLine;
});
}
private void OnNextLine()
{
if (outputString.Count is not 0 && outputString.Last() != string.Empty)
outputString.Add(string.Empty);
}
private void OnDestroy()
{
_inputActionGroup.allowInput.RemoveElement(this);
Application.logMessageReceivedThreaded -= LogCallback;
}
public async void Toggle(bool active)
{
_commandSelector.SetMethods(null);
document.rootVisualElement.SetActive(active);
isActived = active;
_isRunning = active;
BITAppForUnity.AllowCursor.SetElements(this,active);
BITInputSystem.AllowInput.SetDisableElements(this,active);
@@ -110,41 +202,26 @@ namespace BITKit.Console
text.Blur();
}
}
private void OnTextFieldValieChanged(ChangeEvent<string> callback)
private void OnTextFieldValueChanged(ChangeEvent<string> callback)
{
if (callback.newValue.IsValid())
if (string.IsNullOrEmpty(callback.newValue) is false)
{
var commands = BITCommands.GetMethodInfos(callback.newValue).Select(x => x.Name).ToList();
if (commands.Count is 0)
{
commandListView.SetActive(false);
}
else
{
commandListView.itemsSource = commands;
commandListView.SetActive(true);
}
var commands = BITCommands.GetMethodInfos(callback.newValue).ToArray();
_commandSelector.SetMethods(commands);
commandContainer.SetActive(commands.Length is not 0);
}
else
{
commandListView.SetActive(false);
commandContainer.SetActive(false);
_commandSelector.SetMethods(null);
}
}
private void OnDropdownValueChanged(ChangeEvent<string> callback)
{
textField.SetValueWithoutNotify(callback.newValue);
OnTextFieldValieChanged(callback);
textField.Focus();
}
private void OnNextCommand(InputAction.CallbackContext context)
{
if (context.started)
{
var index = context.ReadValue<Vector2>().y;
}
}
private void OnKeyDown(KeyDownEvent keyDownEvent)
private async void OnKeyDown(KeyDownEvent keyDownEvent)
{
var nextStop=true;
switch (keyDownEvent.keyCode)
{
case KeyCode.Return:
@@ -153,13 +230,38 @@ namespace BITKit.Console
LogCallback($">{cmd}", string.Empty, LogType.Log);
textField.SetValueWithoutNotify(string.Empty);
await UniTask.NextFrame();
if (destroyCancellationToken.IsCancellationRequested) return;
textField.Blur();
textField.Focus();
BITCommands.Excute(cmd);
_commandSelector.SetMethods(null);
break;
case KeyCode.Tab:
break;
case KeyCode.DownArrow when string.IsNullOrEmpty(textField.text) is false:
_commandSelector.Index-=1;
break;
case KeyCode.UpArrow when string.IsNullOrEmpty(textField.text) is false:
_commandSelector.Index+=1;
break;
default:
nextStop = false;
break;
}
if (nextStop)
{
keyDownEvent.StopPropagation();
keyDownEvent.PreventDefault();
}
}
@@ -168,7 +270,7 @@ namespace BITKit.Console
switch (context)
{
case { interaction: PressInteraction, performed: true }:
Toggle(!isActived);
Toggle(!_isRunning);
break;
}
}
@@ -205,6 +307,7 @@ namespace BITKit.Console
await BITApp.SwitchToMainThread();
scrollView.ScrollToBottomAutomatic();
text.text = stringBuilder.ToString();
}
catch (OperationCanceledException)
{
@@ -218,24 +321,23 @@ namespace BITKit.Console
private void Update()
{
while (logQueue.TryDequeue(out var log))
{
LogCallback(log.condition, log.stackTrace, log.type);
}
if (_isRunning is false) return;
var pos = textField.worldTransform.GetPosition();
var size = textField.layout.size;
commandListView.style.left = 0;
commandListView.style.top = 0;
commandContainer.style.left = 0;
commandContainer.style.top = 0;
pos.y += size.y;
commandListView.transform.position = pos;
commandContainer.transform.position = pos;
commandListView.style.width = size.x;
}
private void OnSelectionChange(IEnumerable<object> selected)
{
var _selected = selected.First() as string;
textField.SetValueWithoutNotify(_selected);
commandListView.itemsSource?.Clear();
commandListView.SetActive(false);
commandContainer.style.width = size.x;
}
}
}

View File

@@ -69,7 +69,7 @@ namespace BITKit
TextField textField;
public override VisualElement CreateInspectorGUI()
{
FillDefaultInspector(root, serializedObject, true);
FillDefaultInspector();
textField = root.Create<TextField>();
var button = root.Create<Button>();

View File

@@ -1,74 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace BITKit
{
public class PhysicsDoor : MonoBehaviour, IAction,IDescription
{
public enum State
{
Close,
Open,
HalfOpen,
Locked,
}
[SerializeField] private string description;
[SerializeField] private bool allowPhysics = true;
[SerializeField] private Rigidbody root;
[SerializeField] private Vector3 openEuler;
[SerializeField] private Vector3 closeEuler;
[SerializeField] private State state;
[SerializeField] private Collider[] ignoreColliders;
private void Start()
{
var selfColliders = GetComponentsInChildren<Collider>(true);
var parentCollider = GetComponentInParent<Collider>(true);
foreach (var self in selfColliders)
{
foreach (var ignore in ignoreColliders)
{
Physics.IgnoreCollision(self, ignore, true);
}
if (parentCollider is not null)
Physics.IgnoreCollision(self, parentCollider, true);
}
Set();
}
public void Execute()
{
switch (state)
{
case State.Open:
state = State.Close;
Set();
break;
case State.Close:
state = State.Open;
Set();
break;
}
}
public void Set(bool isClosed)
{
state = isClosed ? State.Close : State.Open;
root.transform.localEulerAngles = isClosed ? closeEuler : openEuler;
if (allowPhysics)
root.isKinematic = isClosed;
}
private void Set()
{
var isClosed = state switch
{
State.Locked => true,
State.Close => true,
State.Open => false,
_ => true
};
Set(isClosed);
}
public string Name => description;
}
}

View File

@@ -1,22 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace BITKit
{
public class PhysicsDoorManager : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 1b5481cf34bf4a145898ac81e58abf8f
guid: bf1c155248e26c446b9f5bd892f84eef
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@@ -0,0 +1,137 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Text;
using Cysharp.Threading.Tasks;
using Newtonsoft.Json;
using Unity.SharpZipLib.Utils;
using UnityEngine;
using UnityEngine.Experimental.Audio;
using UnityEngine.Networking;
namespace BITKit.Mod
{
public class DotNetSdkRoslynService
{
private const string _InstalledFilesKey = "DotNetSdkRoslyn_InstalledFiles";
public static string DownloadUrl =>
"http://server.bitfall.icu:3000/root/BITKit.DotNetSdkRoslyn.Unity/archive/main.zip";
public static bool Installed=>File.Exists(CSCPath);
public static string CSCPath =>
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), nameof(BITKit),"DotnetSdkRoslyn","csc.dll");
public static string FolderPath =>
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), nameof(BITKit),"DotnetSdkRoslyn");
public static event Action OnInstall;
public static event Action OnInstalled;
public static event Action OnUnInstalled;
public static event Action<Exception> OnInstallFailed;
public static event Action<float> OnDownloadProgress;
private static string[] _InstalledFiles
{
get
{
if (!PlayerPrefs.HasKey(_InstalledFilesKey)) return Array.Empty<string>();
var json = PlayerPrefs.GetString(_InstalledFilesKey);
try
{
return JsonConvert.DeserializeObject<string[]>(json);
}
catch (Exception e)
{
BIT4Log.LogException(e);
}
return Array.Empty<string>();
}
set
{
PlayerPrefs.SetString(_InstalledFilesKey, JsonConvert.SerializeObject(value));
PlayerPrefs.Save();
}
}
public static async UniTask Install()
{
await UniTask.SwitchToMainThread();
OnInstall?.Invoke();
var request = UnityWebRequest.Get(DownloadUrl);
try
{
request.SendWebRequest();
while (request.isDone is false)
{
await UniTask.SwitchToMainThread();
OnDownloadProgress?.Invoke(request.downloadProgress);
await UniTask.NextFrame();
}
OnDownloadProgress?.Invoke(1);
using var ms = new MemoryStream(request.downloadHandler.data);
request.Dispose();
await UniTask.SwitchToTaskPool();
var zipArchive = new ZipArchive(ms);
PathHelper.EnsureDirectoryCreated(FolderPath);
List<string> installedFiles = new();
var reportBuilder =new StringBuilder();
reportBuilder.AppendLine($"正在安装文件到:{FolderPath}");
var entryFolder = zipArchive.Entries[0].FullName;
foreach (var zipArchiveEntry in zipArchive.Entries)
{
var entryPath = Path.Combine(FolderPath, zipArchiveEntry.FullName.Replace(entryFolder,string.Empty));
if (zipArchiveEntry.Name is "")
{
reportBuilder.AppendLine($"正在创建目录:{entryPath}");
PathHelper.EnsureDirectoryCreated(entryPath);
}
else
{
reportBuilder.AppendLine($"正在解压文件:{entryPath}");
await using var entryStream = zipArchiveEntry.Open();
await using var fs = System.IO.File.Create(entryPath);
await entryStream.CopyToAsync(fs);
installedFiles.Add(entryPath);
}
}
await UniTask.SwitchToMainThread();
_InstalledFiles = installedFiles.ToArray();
installedFiles.Clear();
}
catch (Exception e)
{
await UniTask.SwitchToMainThread();
request.Dispose();
OnInstallFailed?.Invoke(e);
return;
}
OnInstalled?.Invoke();
}
public static async UniTask UnInstall()
{
if (Installed is false)
{
BIT4Log.Warning<DotNetSdkRoslynService>("未安装,无法卸载");
return;
}
await UniTask.SwitchToMainThread();
var files = _InstalledFiles;
await UniTask.SwitchToTaskPool();
foreach (var path in files)
{
File.Delete(path);
}
await UniTask.SwitchToMainThread();
PlayerPrefs.DeleteKey(_InstalledFilesKey);
PlayerPrefs.Save();
OnUnInstalled?.Invoke();
}
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 97e364d5d74ebe94da6abf95c6d42c5b
guid: 56389bdbeb2065541a8e62a4ae5bd746
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -16,7 +16,8 @@
"GUID:d525ad6bd40672747bde77962f1c401e",
"GUID:be17a8778dbfe454890ed8279279e153",
"GUID:96f476e982d6fb945bfc9140ba094b7f",
"GUID:4307f53044263cf4b835bd812fc161a4"
"GUID:4307f53044263cf4b835bd812fc161a4",
"GUID:d8b63aba1907145bea998dd612889d6b"
],
"includePlatforms": [],
"excludePlatforms": [],

View File

@@ -1,105 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using BITKit.PlayerCamera;
using UnityEngine;
using UnityEngine.Rendering;
namespace BITKit.Entities.Player.Character
{
public class EntityCharacter : EntityPlayerBehavior
{
[Header(Constant.Header.Components)]
[SerializeField] private Renderer[] fpvRenderer = Array.Empty<Renderer>();
[SerializeField] private Renderer[] tpvRenderer = Array.Empty<Renderer>();
[SerializeField] private Renderer[] fpvOverrideRenderers = Array.Empty<Renderer>();
[SerializeField] private Transform[] tpvRendererGroup = Array.Empty<Transform>();
[Header(Constant.Header.Reference)]
[SerializeReference, SubclassSelector] public IReference getDamage;
[Inject(true)] private IHealth _health;
[Inject(true)] private IPlayerCameraService _cameraService;
[Inject(true)] private IEntityOverride _entityOverride;
private Renderer[] _tpvRendererGroup;
public override void OnStart()
{
if (_health is not null)
{
_health.OnSetAlive += _ => UpdateMeshState();
_health.OnSetHealthPoint += OnSetHP;
}
if (_cameraService is not null)
_cameraService.OnCameraActivated += _ => UpdateMeshState();
if(_entityOverride is not null)
_entityOverride.OnOverride += _ => UpdateMeshState();
_tpvRendererGroup = tpvRendererGroup.SelectMany(x => x.GetComponentsInChildren<Renderer>(true)).ToArray();
}
public override void OnPlayerInitialized()
{
UpdateMeshState();
}
public override void OnPlayerDispose()
{
SetFPV(false);
}
private void OnSetHP(int hp)
{
UnityEntity.Invoke<string>(Constant.Animation.Play, getDamage.Value);
}
private void UpdateMeshState()
{
switch (_health, _cameraService)
{
case (null, null):
SetFPV(true);
break;
case (null, not null):
SetFPV(_cameraService.IsCameraActivated);
break;
case (not null, null):
SetFPV(_health.IsAlive);
break;
case (not null, not null):
SetFPV(_health.IsAlive && _cameraService.IsCameraActivated);
break;
}
}
private void SetFPV(bool isFpv)
{
var shadowMode = isFpv ?
ShadowCastingMode.ShadowsOnly :
ShadowCastingMode.On;
foreach (var x in fpvRenderer)
{
x.enabled = isFpv;
}
foreach (var x in tpvRenderer)
{
x.shadowCastingMode = shadowMode;
}
foreach (var x in _tpvRendererGroup)
{
x.shadowCastingMode =
_entityOverride is not null
? _entityOverride.IsOvering ? ShadowCastingMode.On : shadowMode
: shadowMode;
}
if (_entityOverride is not null)
{
foreach (var x in fpvOverrideRenderers)
{
x.enabled = isFpv && _entityOverride.IsOvering;
}
}
}
}
}

View File

@@ -62,6 +62,7 @@ namespace BITKit.Entities
/// </summary>
public interface IEntityMovement:IStateMachine<IEntityMovementState>
{
float ReferenceSpeed => 2.5f;
Vector3 Position { get; set; }
Quaternion Rotation { get; set; }
Vector3 Forward { get; }
@@ -113,12 +114,12 @@ namespace BITKit.Entities
/// 基于相对坐标的移动
/// </summary>
/// <param name="relativeVector"></param>
void Movement(Vector3 relativeVector);
void OnMovement(Vector3 relativeVector);
/// <summary>
/// 基于InputAction的移动
/// </summary>
/// <param name="context"></param>
void Movement(InputAction.CallbackContext context);
void OnMovement(InputAction.CallbackContext context);
/// <summary>
/// 执行命令
/// </summary>

View File

@@ -12,8 +12,8 @@ namespace BITKit.Entities.Movement
[SerializeField] private new Rigidbody rigidbody;
[SerializeField] private Animator animator;
[SerializeField] private bool allowRootMotion;
public Vector3 Position { get; set; }
public Quaternion Rotation { get; set; }
public Vector3 Forward { get; }
@@ -35,11 +35,11 @@ namespace BITKit.Entities.Movement
{
}
public void Movement(Vector3 relativeVector)
public void OnMovement(Vector3 relativeVector)
{
}
public void Movement(InputAction.CallbackContext context)
public void OnMovement(InputAction.CallbackContext context)
{
}

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using BITKit;
using BITKit.SubSystems;
@@ -9,14 +10,16 @@ namespace BITKit.Entities
{
public interface IDamageType { }
public interface IDamageService
{
public event Action<DamageMessage> OnEntityDamaged;
public event Action<DamageMessage> OnEntityKilled;
void Execute(DamageMessage damageMessage);
}
public struct MeleeDamageMessage:IDamageType{}
public struct MeleeDamageMessage : IDamageType
{
public bool Bleeding;
}
public struct BulletDamageMessage:IDamageType{}
[Serializable]
public class DamageServiceSingleton:IDamageService
@@ -71,6 +74,34 @@ namespace BITKit.Entities
public Vector3 Position;
public Quaternion Rotation;
public IDamageType DamageType;
public RaycastHit? RaycastHit;
}
public sealed class DamageMessageNetMessageWriter : NetMessageReader<DamageMessage>
{
public override DamageMessage ReadBinary(BinaryReader reader)
{
UnityEntitiesService.TryGetEntity(reader.ReadUInt64(),out var initiator);
UnityEntitiesService.TryGetEntity(reader.ReadUInt64(),out var target);
return new DamageMessage()
{
Initiator = initiator as Entity,
Target = target as Entity,
RawDamage = reader.ReadBoolean(),
Damage = reader.ReadInt32(),
Position = reader.ReadFloat3(),
Rotation = reader.ReadQuaternion(),
};
}
public override void WriteBinary(BinaryWriter writer, DamageMessage value)
{
writer.Write(value.Initiator?.Id ?? 0);
writer.Write(value.Target?.Id ?? 0);
writer.Write(value.RawDamage);
writer.Write(value.Damage);
writer.WriteFloat3(value.Position);
writer.WriteQuaternion(value.Rotation);
}
}
public interface IDamageCallback
@@ -79,35 +110,65 @@ namespace BITKit.Entities
}
public interface IDamagable
{
IHealth Health { get; }
IUnityEntity UnityEntity { get; }
Rigidbody Rigidbody { get; }
void GiveDamage(DamageMessage message);
}
public class DamageService:MonoBehaviour,IDamageService
{
internal static IDamageService Singleton { get; set; }
public static IDamageService Singleton { get;private set; }
private readonly Queue<DamageMessage> Messages = new();
[SerializeReference,SubclassSelector] private INetClient netClient;
[SerializeReference,SubclassSelector] private INetServer netServer;
private INetProvider netClientProvider => netClient.Source as INetProvider;
private INetProvider netServerProvider => netServer.Source as INetProvider;
private void Awake()
{
Singleton = this;
}
private void Start()
{
netClientProvider.AddCommandListener<DamageMessage>(ExecuteInternal);
}
private void FixedUpdate()
{
if (!netServer.IsRunningServer && netClient.IsConnected) return;
while (Messages.TryDequeue(out var damageMessage))
{
var unityEntity = (Entity)damageMessage.Target;
if (!unityEntity || !unityEntity.TryGetComponent<IHealth>(out var heal) || !heal.IsAlive) continue;
damageMessage.Initiator?.Invoke(damageMessage);
damageMessage.Target?.Invoke(damageMessage);
ExecuteInternal(damageMessage);
netServerProvider?.AllClientCommand(damageMessage);
}
}
private void ExecuteInternal(DamageMessage damageMessage)
{
IHealth heal = null;
if (damageMessage.Target?.TryGetComponent<IHealth>(out heal) is false)
{
return;
}
damageMessage.Initiator?.Invoke(damageMessage);
damageMessage.Target?.Invoke(damageMessage);
if (heal!.IsAlive)
{
OnEntityDamaged?.Invoke(damageMessage);
if (heal.IsAlive is false)
{
OnEntityKilled?.Invoke(damageMessage);
}
}
else
{
OnEntityKilled?.Invoke(damageMessage);
}
}

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Remoting.Contexts;
using UnityEngine;
@@ -20,21 +21,34 @@ namespace BITKit.Entities
/// <summary>
/// 当受到伤害时的回调
/// </summary>
public event Func<DamageMessage,int,int> OnDamageFactory;
public event Func<DamageMessage,int,int> OnDamageFactory;
/// <summary>
/// 收到伤害时的回调
/// </summary>
public event Action<DamageMessage> OnDamageRelease;
/// <summary>
/// 当伤害被阻止时的回调
/// </summary>
public event Action<DamageMessage> OnDamageVoid;
int HealthPoint { get; set; }
int MaxHealthPoint { get; set; }
bool IsAlive { get; }
}
[CustomType(typeof(IHealth))]
public class EntityHealth : EntityBehavior, IHealth
public class EntityHealth : EntityBehavior, IHealth,IEntityBinaryComponent
{
[Header(Constant.Header.Settings)]
[SerializeField] private int healthPoint = 100;
[SerializeField] private int maxHealthPoint = 100;
public int Id { get; } = 84946486;
public event Action<int> OnSetHealthPoint;
public event Action<bool> OnSetAlive;
public event Func<DamageMessage,int, int> OnDamageFactory;
public event Action<DamageMessage> OnDamageRelease;
public event Action<DamageMessage> OnDamageVoid;
public int HealthPoint
{
@@ -61,7 +75,7 @@ namespace BITKit.Entities
private void OnHealthPointChangedInternal(int old, int newHP)
{
healthPoint = newHP;
healthPoint =Mathf.Clamp(newHP,-1,maxHealthPoint) ;
var _isAlive = newHP >= 0;
if (_isAlive != IsAlive)
{
@@ -84,15 +98,28 @@ namespace BITKit.Entities
private void OnGetDamage(DamageMessage damageMessage)
{
if (damageMessage.Target != UnityEntity) return;
if (IsAlive is false) return;
var damage = damageMessage.Damage;
foreach (var x in OnDamageFactory.CastAsFunc().Reverse())
if (IsAlive is false)
{
damage = x.Invoke(damageMessage, damage);
if (damage <= 0) break;
OnDamageVoid?.Invoke(damageMessage);
}
else
{
var damage = damageMessage.Damage;
foreach (var x in OnDamageFactory.CastAsFunc())
{
damage = x.Invoke(damageMessage, damage);
if (damage <= 0)
{
OnDamageVoid?.Invoke(damageMessage);
break;
}
}
if (Data.Get<bool>("god") is false)
AddHP(-damage);
damageMessage.Damage = damage;
OnDamageRelease?.Invoke(damageMessage);
}
if (Data.Get<bool>("god") is false)
AddHP(-damage);
}
#if UNITY_EDITOR
[BIT]
@@ -109,6 +136,17 @@ namespace BITKit.Entities
OnHealthPointChangedInternal(100, -1);
}
#endif
public void Serialize(BinaryWriter writer)
{
writer.Write(HealthPoint);
}
public void Deserialize(BinaryReader reader)
{
var newHealthPoint = reader.ReadInt32();
if (HealthPoint != newHealthPoint)
HealthPoint = newHealthPoint;
}
}
}

View File

@@ -4,15 +4,52 @@ using UnityEngine;
using BITKit;
namespace BITKit.Entities
{
public class EntityHitbox : EntityBehavior,IDamagable
public class EntityHitbox : MonoBehaviour,IDamagable
{
IUnityEntity IDamagable.UnityEntity => UnityEntity;
public Rigidbody Rigidbody => m_rigidbody;
public IHealth Health
{
get
{
EnsureConfigure();
return _health;
}
}
public IUnityEntity UnityEntity
{
get
{
EnsureConfigure();
return _unityEntity;
}
}
public Rigidbody Rigidbody
{
get=>m_rigidbody;
set=>m_rigidbody=value;
}
public void GiveDamage(DamageMessage message)
{
UnityEntity.Invoke(message);
if (_unityEntity is not null)
UnityEntity.Invoke(message);
}
[SerializeField]private Rigidbody m_rigidbody;
[Inject(true)]
private IHealth _health;
private IUnityEntity _unityEntity;
private bool _initialized;
private void EnsureConfigure()
{
if (_initialized) return;
_unityEntity = GetComponentInParent<IUnityEntity>(true);
_unityEntity?.Inject(this);
_initialized = true;
}
}
}

View File

@@ -0,0 +1,77 @@
using System.Collections;
using System.Collections.Generic;
using BITFALL.Rig;
using BITKit.Entities;
using Cysharp.Threading.Tasks.Triggers;
using UnityEditor;
using UnityEngine;
namespace BITKit
{
public class EntityHitboxBuilder : MonoBehaviour
{
[SerializeField] private Collider[] colliders;
[SerializeField] private EntityHitbox[] hitboxes;
[SerializeReference,SubclassSelector] private IReference[] tagReferences;
[BIT]
private void Build()
{
foreach (var x in hitboxes)
{
DestroyImmediate(x.gameObject);
}
hitboxes = new EntityHitbox[colliders.Length];
for (var i = 0; i < colliders.Length; i++)
{
var collider = colliders[i];
var newGameObject = new GameObject($"Hitbox_{collider.gameObject.name}");
newGameObject.layer = gameObject.layer;
newGameObject.transform.SetParent(transform);
var transform1 = collider.transform;
newGameObject.transform.position = transform1.position;
newGameObject.transform.rotation = transform1.rotation;
var hitbox =hitboxes[i] = newGameObject.AddComponent<EntityHitbox>();
var tag = newGameObject.AddComponent<Tag>();
var tickOverride = newGameObject.AddComponent<TickOverrideTransform>();
tickOverride.Source = newGameObject.transform;
tickOverride.Target = collider.transform;
if (collider.TryGetComponent<Rigidbody>(out var newRigidbody))
{
hitbox.Rigidbody = newRigidbody;
}
switch (collider)
{
case BoxCollider boxCollider:
var box = newGameObject.AddComponent<BoxCollider>();
box.size = boxCollider.size;
box.center = boxCollider.center;
break;
case SphereCollider sphereCollider:
var sphere = newGameObject.AddComponent<SphereCollider>();
sphere.radius = sphereCollider.radius;
sphere.center = sphereCollider.center;
break;
case CapsuleCollider capsuleCollider:
var capsule = newGameObject.AddComponent<CapsuleCollider>();
capsule.radius = capsuleCollider.radius;
capsule.height = capsuleCollider.height;
capsule.direction = capsuleCollider.direction;
capsule.center = capsuleCollider.center;
break;
}
tag.SetTags(tagReferences);
EditorUtility.SetDirty(hitbox);
EditorUtility.SetDirty(tag);
}
EditorUtility.SetDirty(this);
}
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: c8cf20e38c0584247ab1573e085274d4
guid: 21e16997211c6f44c837beae9450cb58
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -13,7 +13,8 @@ namespace BITKit.Entities.InputSystem
{
protected readonly InputActionGroup inputActionGroup = new()
{
allowGlobalActivation = true
allowGlobalActivation = true,
Source = nameof(EntityInputSystem)
};
[Inject(true)]
private IHealth _health;

View File

@@ -1,141 +0,0 @@
using System;
using BITKit.PlayerCamera;
using BITKit.Selection;
using BITKit.Sensors;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Interactions;
namespace BITKit.Entities.Player
{
[CustomType(typeof(ISelector))]
public class EntityInteractive : EntityPlayerBehavior,ISelector
{
[Header(Constant.Header.Settings)]
[SerializeReference, SubclassSelector] private ISensor sensor;
[Header(Constant.Header.Gameobjects)]
[SerializeField] private Transform sensorTransform;
[Header(Constant.Header.InternalVariables)]
private ISelectable selected;
private IntervalUpdate cd = new(0.08f);
[Inject]
private IHealth _health;
[Inject(true)] private IEntityMovement _movement;
[Inject(true)] IPlayerCameraService _cameraService;
public override void OnStart()
{
_health.OnSetAlive += OnSetAlive;
}
private void OnSetAlive(bool obj)
{
TryDeSelected();
}
public override void OnUpdate(float deltaTime)
{
if (_cameraService is not null && _movement is not null)
{
if (_cameraService.IsCameraActivated)
{
sensorTransform.SetPositionAndRotation(_cameraService.CameraPosition, _cameraService.CameraRotation);
}
else
{
sensorTransform.position = _movement.Position + _movement.Rotation * _movement.ViewCenter;
sensorTransform.rotation = _movement.ViewRotation;
}
}
//if (sensor.Get().TryGetAny(x=>x.TryGetComponentAny<ISelectable>(out _),out var detected))
try
{
if (sensor.Get().TryGetAny(x=>x.GetComponentInParent<ISelectable>() is not null,out var detected))
{
if (detected.TryGetComponentAny<ISelectable>(out var _detected))
{
if (_detected == selected)
{
}
else
{
TryDeSelected();
Detected(_detected);
}
}
else
{
TryDeSelected();
}
}
else
{
TryDeSelected();
}
}
catch(MissingReferenceException e)
{}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
private void TryDeSelected()
{
if (selected is null) return;
selected.SetSelectionState(SelectionState.None);
OnInactive?.Invoke(selected);
selected = null;
}
private void Detected(ISelectable detected)
{
selected = detected;
detected.SetSelectionState(SelectionState.Hover);
OnSelected?.Invoke(selected);
}
public void Interactive(InputAction.CallbackContext context)
{
if (context.interaction is not PressInteraction || !context.performed ) return;
if (cd.AllowUpdate is false) return;
var _selected = selected;
if (_selected is not MonoBehaviour monoBehaviour) return;
if (monoBehaviour.TryGetComponentAny<IAction>(out var action))
{
action.Execute();
}
else
{
}
selected.SetSelectionState(SelectionState.Active);
OnActive?.Invoke(selected);
}
public bool TryGetCurrentSelectable(out ISelectable selectable)
{
selectable = selected;
return selected?.Transform;
}
public event Action<ISelectable> OnNone;
public event Action<ISelectable> OnHover;
public event Action<ISelectable> OnActive;
public event Action<ISelectable> OnInactive;
public event Action<ISelectable> OnFocus;
public event Action<ISelectable> OnSelected;
public event Action<ISelectable> OnEnabled;
public event Action<ISelectable> OnChecked;
public event Action<ISelectable> OnRoot;
}
}

View File

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

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 6b8ff0f400ff5fd44b5205e0adaa1969
guid: 0dcb052e1b8841743aaa68d522200c5e
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@@ -1,118 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using BITKit.Entities.Physics;
using UnityEngine;
namespace BITKit.Entities
{
[CustomType(typeof(IEntityPhysics))]
public class EntityPhysics : EntityBehavior,IEntityPhysics
{
[SerializeField] private Animator animator;
[SerializeField] private Rigidbody[] rigidbodies;
[SerializeField] private Collider[] ragdollColliders;
[SerializeField] private Joint[] joints;
[SerializeField] private new Rigidbody rigidbody;
[Inject]
private IHealth _health;
private readonly Dictionary<Joint,ConfigurableJointMotion> _jointXMotions=new();
private readonly Dictionary<Joint,ConfigurableJointMotion> _jointYMotions=new();
private readonly Dictionary<Joint,ConfigurableJointMotion> _jointZMotions=new();
private readonly Dictionary<Joint,ConfigurableJointMotion> _jointAngularXMotions=new();
private readonly Dictionary<Joint,ConfigurableJointMotion> _jointAngularYMotions=new();
private readonly Dictionary<Joint,ConfigurableJointMotion> _jointAngularZMotions=new();
public override void OnAwake()
{
_health.OnSetAlive += OnSetAlive;
_health.OnSetHealthPoint += OnSetHP;
foreach (var x in joints)
{
switch (x)
{
case ConfigurableJoint configurableJoint:
_jointXMotions.Add(configurableJoint,configurableJoint.xMotion);
_jointYMotions.Add(configurableJoint,configurableJoint.yMotion);
_jointZMotions.Add(configurableJoint,configurableJoint.zMotion);
_jointAngularXMotions.Add(configurableJoint,configurableJoint.angularXMotion);
_jointAngularYMotions.Add(configurableJoint,configurableJoint.angularYMotion);
_jointAngularZMotions.Add(configurableJoint,configurableJoint.angularZMotion);
break;
}
}
}
private async void OnSetAlive(bool alive)
{
IsPhysics = !alive;
if (animator)
animator.enabled = alive;
try
{
await Task.Delay(10, destroyCancellationToken);
if (destroyCancellationToken.IsCancellationRequested) return;
rigidbodies.ForEach(x => { x.isKinematic = alive; });
ragdollColliders.ForEach(x => { x.enabled = !alive; });
OnSetPhysics?.Invoke(!alive);
}
catch (OperationCanceledException)
{
}
foreach (var joint in joints)
{
switch (joint)
{
case ConfigurableJoint configurableJoint:
configurableJoint.xMotion = alive ? _jointXMotions[joint] : ConfigurableJointMotion.Free;
configurableJoint.yMotion = alive ? _jointYMotions[joint] : ConfigurableJointMotion.Free;
configurableJoint.zMotion = alive ? _jointZMotions[joint] : ConfigurableJointMotion.Free;
configurableJoint.angularXMotion =
alive ? _jointAngularXMotions[joint] : ConfigurableJointMotion.Free;
configurableJoint.angularYMotion =
alive ? _jointAngularYMotions[joint] : ConfigurableJointMotion.Free;
configurableJoint.angularZMotion =
alive ? _jointAngularZMotions[joint] : ConfigurableJointMotion.Free;
break;
}
}
}
public void OnSetHP(int hp)
{
}
public Vector3 Center => rigidbody.worldCenterOfMass;
public bool IsPhysics { get; private set; }
public Vector3 Velocity
{
get=>rigidbody.velocity;
set
{
foreach (var x in rigidbodies)
{
x.velocity = value;
}
}
}
public Action<bool> OnSetPhysics { get; set; }
public void AddForce(Vector3 force, ForceMode mode = ForceMode.Force)
{
foreach (var x in rigidbodies)
{
x.AddForce(force, mode);
}
}
public void AddTorque(Vector3 torque, ForceMode mode = ForceMode.Force)
{
foreach (var x in rigidbodies)
{
x.AddTorque(torque, mode);
}
}
}
}

View File

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

View File

@@ -7,15 +7,20 @@ using System.Text;
using System.Threading;
using BITKit.Entities;
using Cysharp.Threading.Tasks;
using UnityEngine.Profiling;
using UnityEngine.UIElements;
// ReSharper disable RedundantTypeArgumentsOfMethod
namespace BITKit.Entities
{
[CustomType(typeof(IUnityEntity))]
[CustomType(typeof(IEntity))]
public class Entity : MonoBehaviour, IUnityEntity
{
private readonly GenericEvent genericEvent = new();
public ulong Id { get; private set; }
public ulong Id { get; set; }
public CancellationToken CancellationToken { get; private set; }
public IEntityBehavior[] Behaviors { get;private set; }
public IEntityComponent[] Components => Behaviors.Cast<IEntityComponent>().ToArray();
@@ -31,7 +36,7 @@ namespace BITKit.Entities
foreach (var fieldInfo in obj
.GetType()
.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
.Where(fieldInfo=>fieldInfo.GetCustomAttribute<InjectAttribute>() is not null))
.Where(fieldInfo=>fieldInfo.GetCustomAttribute<InjectAttribute>(true) is not null))
{
var type = fieldInfo.FieldType;
var attribute = fieldInfo.GetCustomAttribute<InjectAttribute>();
@@ -83,19 +88,30 @@ namespace BITKit.Entities
}
private bool isInitialized;
public void WaitForInitializationComplete()
{
if (isInitialized) return;
Start();
isInitialized = true;
}
private void Awake()
{
Id = (ulong)Guid.NewGuid().GetHashCode();
if (Id.IsDefault())
Id = (ulong)Guid.NewGuid().GetHashCode();
CancellationToken = gameObject.GetCancellationTokenOnDestroy();
Set(CancellationToken);
Behaviors = GetComponentsInChildren<IEntityBehavior>(true).Distinct().ToArray();
}
private void Start()
{
if (isInitialized) return;
try
{
AddService<IEntity>(this);
AddService<Entity>(this);
AddService<IUnityEntity>(this);
Behaviors = GetComponentsInChildren<IEntityBehavior>(true).Distinct().ToArray();
var monoBehaviours = GetComponentsInChildren<MonoBehaviour>(true);
Behaviors.ForEach(x => x.Initialize(this));
foreach (var x in monoBehaviours)
@@ -108,8 +124,11 @@ namespace BITKit.Entities
.OfType<CustomTypeAttribute>()
)
{
AddService(att.Type, x);
AddService(att.Type, x);
if (att.AsGlobal)
DI.Register(att.Type, x);
}
genericEvent.Set(x.GetType(),x);
}
foreach (var x in monoBehaviours)
@@ -143,23 +162,26 @@ namespace BITKit.Entities
private void Update()
{
var deltaTime = Time.fixedDeltaTime;
foreach (var x in Behaviors)
{
x.OnUpdate(Time.deltaTime);
x.OnUpdate(deltaTime);
}
}
private void FixedUpdate()
{
var deltaTime = Time.fixedDeltaTime;
foreach (var x in Behaviors)
{
x.OnFixedUpdate(Time.fixedDeltaTime);
x.OnFixedUpdate(deltaTime);
}
}
private void LateUpdate()
{
var deltaTime = Time.fixedDeltaTime;
foreach (var x in Behaviors)
{
x.OnLateUpdate(Time.deltaTime);
x.OnLateUpdate(deltaTime);
}
}
public void AddListener<T>(Action<T> action) => genericEvent.AddListener<T>(action);

View File

@@ -0,0 +1,17 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace BITKit.Entities
{
[CustomType(typeof(IAddressable))]
public class EntityAddressableComponent : MonoBehaviour,IAddressable
{
[SerializeField] private string addressablePath;
[SerializeField] private ulong addressableId;
public string AddressablePath => addressablePath;
public ulong AddressableId => addressableId;
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 2b1d23c488f41754ea714f972c248130
guid: 22c8a583a4eb6504ab5a732954c0855c
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -1,4 +1,5 @@
using System;
using System.Threading;
using BITKit.Entities;
#if UNITY_EDITOR
using UnityEditor;

View File

@@ -0,0 +1,73 @@
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEngine;
namespace BITKit.Entities
{
[CustomType(typeof(IEntityBinaryHeader))]
public class EntityBinaryHeader : EntityBehavior,IEntityBinaryHeader
{
public int Id => (int)Entity.Id;
public IDictionary<int, IEntityBinaryComponent> ComponentDictionary { get; } =
new Dictionary<int, IEntityBinaryComponent>();
public override void OnStart()
{
base.OnStart();
foreach (var component in Entity.Components.OfType<IEntityBinaryComponent>())
{
ComponentDictionary.Add(component.Id, component);
}
}
public void Serialize(BinaryWriter writer)
{
//写入组件数量
//写入组件ID
//写入组件数据
//写入组件数据长度
var length = ComponentDictionary.Count;
writer.Write(length);
foreach (var component in ComponentDictionary.Values)
{
writer.Write(component.Id);
}
foreach (var component in ComponentDictionary.Values)
{
using var ms = new MemoryStream();
using var binaryWriter = new BinaryWriter(ms);
component.Serialize(binaryWriter);
binaryWriter.Flush();
ms.Flush();
var bytes = ms.ToArray();
writer.Write(bytes.Length);
writer.Write(bytes);
}
}
public void Deserialize(BinaryReader reader)
{
//BIT4Log.Log<EntityBinaryHeader>("源数据长度:"+reader.BaseStream.Length);
//读取组件数量
//读取组件ID
//读取组件数据
var count = reader.ReadInt32();
//BIT4Log.Log<EntityBinaryHeader>($"count:{count}");
var ids = new int[count];
for (var i = 0; i < count; i++)
{
ids[i] = reader.ReadInt32();
}
foreach (var id in ids)
{
var length = reader.ReadInt32();
var bytes = reader.ReadBytes(length);
using var stream = new MemoryStream(bytes);
using var binaryReader = new BinaryReader(stream);
//BIT4Log.Log<EntityBinaryHeader>($"id:{id},length:{length},bytes:\n{JsonHelper.Get(bytes)}");
ComponentDictionary[id].Deserialize(binaryReader);
}
}
}
}

View File

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

View File

@@ -4,21 +4,52 @@ using System.Collections.Generic;
using UnityEngine;
namespace BITKit.Entities
{
public interface IEntityOverride
{
/// <summary>
/// 是否正在被覆盖
/// </summary>
bool IsOvering { get; }
void AddOverride(object key);
void RemoveOverride(object key);
/// <summary>
/// 当前对象,用于判断是否是自己的覆盖
/// </summary>
object CurrentObject { get; }
/// <summary>
/// 当开始覆盖或者结束覆盖时触发
/// </summary>
event Action<bool> OnOverride;
/// <summary>
/// 添加覆盖
/// </summary>
void AddOverride(object key,int priority=0);
/// <summary>
/// 移除覆盖
/// </summary>
void RemoveOverride(object key,int priority=0);
}
[CustomType(typeof(IEntityOverride))]
public class EntityOverride : EntityBehavior,IEntityOverride
{
[SerializeField,ReadOnly] private bool isOvering;
[SerializeField, ReadOnly(HideLabel = true)] private string overrideKeys;
public bool IsOvering => _allowOverrideHandle;
public object CurrentObject => _prioritySelector.Current;
private readonly ValidHandle _allowOverrideHandle = new();
public void AddOverride(object key) => _allowOverrideHandle.AddElement(key);
public void RemoveOverride(object key)=>_allowOverrideHandle.RemoveElement(key);
private readonly PrioritySelector<object> _prioritySelector = new();
public void AddOverride(object key,int priority=0)
{
_prioritySelector.Set(priority,key);
_allowOverrideHandle.AddElement(key);
}
public void RemoveOverride(object key,int priority=0)
{
_prioritySelector.Remove(priority);
_allowOverrideHandle.RemoveElement(key);
}
public event Action<bool> OnOverride;
public override void Initialize(IEntity entity)
@@ -35,6 +66,7 @@ namespace BITKit.Entities
{
OnOverride?.Invoke(@override);
isOvering=@override;
overrideKeys = _allowOverrideHandle.ToString();
}
}
}

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using BITKit.Entities;
using BITKit.StateMachine;
using UnityEngine;
@@ -27,20 +28,27 @@ namespace BITKit.Entities
add => stateMachine.OnStateChanged += value;
remove => stateMachine.OnStateChanged -= value;
}
public event Action<T> OnStateRegistered;
public event Action<T> OnStateUnRegistered;
public IDictionary<Type, T> StateDictionary => stateMachine.StateDictionary;
public override void Initialize(IEntity entity)
public override void OnAwake()
{
base.Initialize(entity);
base.OnAwake();
if (stateMachine is null)
{
Debug.LogWarning(GetType().Name);
}
else
{
foreach (var x in stateMachine.states)
{
Entity.Inject(x);
}
stateMachine.Initialize();
}
}
void IStateMachine<T>.Initialize()
void IStateMachine<T>.Initialize()
{
stateMachine.Initialize();
}
@@ -62,6 +70,23 @@ namespace BITKit.Entities
{
stateMachine.TransitionState(state);
}
public virtual void Register(T newState)
{
Entity.Inject(newState);
StateMachineUtils.Register(this, newState);
}
public virtual void UnRegister(T newState)=>StateMachineUtils.UnRegister(this,newState);
public void InvokeOnStateRegistered(T state)
{
OnStateRegistered?.Invoke(state);
}
public void InvokeOnStateUnRegistered(T state)
{
OnStateUnRegistered?.Invoke(state);
}
}
}

View File

@@ -39,6 +39,10 @@ public class UnityEntitiesServiceSingleton:IEntitiesService
public CancellationToken CancellationToken => UnityEntitiesService.CancellationToken;
public IEntity Get(ulong id) => UnityEntitiesService.Get(id);
public bool TryGetEntity(ulong id, out IEntity entity) => UnityEntitiesService.TryGetEntity(id, out entity);
public IEntity GetOrAdd(ulong id, Func<ulong, IEntity> factory)=>UnityEntitiesService.GetOrAdd(id,factory);
public IEntity[] Query<T>()
{
@@ -124,6 +128,17 @@ public class UnityEntitiesService : MonoBehaviour,IEntitiesService
CancellationToken IEntitiesService.CancellationToken => CancellationToken;
public static IEntity Get(ulong id)=>Dictionary[id];
IEntity IEntitiesService.Get(ulong id)=>Get(id);
public static bool TryGetEntity(ulong id, out IEntity entity)
{
return Dictionary.TryGetValue(id, out entity);
}
bool IEntitiesService.TryGetEntity(ulong id, out IEntity entity)=>TryGetEntity(id,out entity);
public static IEntity GetOrAdd(ulong id, Func<ulong, IEntity> factory)
{
return Dictionary.GetOrAdd(id, factory);
}
IEntity IEntitiesService.GetOrAdd(ulong id, Func<ulong, IEntity> factory)=>GetOrAdd(id,factory);
IEntity[] IEntitiesService.Query<T>()=>Query<T>();
public static IEntity[] Query<T>()
{

View File

@@ -0,0 +1,74 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
namespace BITKit.Entities.GameEditor
{
public class UnityEntitiesBinaryEditor : EditorWindow
{
[MenuItem("Tools/Entities/EntitiesBinaryEditor")]
public static void Open()
{
var window = GetWindow<UnityEntitiesBinaryEditor>();
window.Show();
}
private Label _base64Label;
private void OnEnable()
{
rootVisualElement.Clear();
var button = rootVisualElement.Create<Button>();
button.clicked += PrintBytes;
button.text = "获取二进制数据";
_base64Label = rootVisualElement.Create<Label>();
var copyButton = rootVisualElement.Create<Button>();
copyButton.text = "复制到剪切板";
copyButton.clicked += () =>
{
EditorGUIUtility.systemCopyBuffer = _base64Label.text;
};
var inputField = rootVisualElement.Create<TextField>();
inputField.multiline = true;
inputField.label = "输入二进制数据";
var applyButton = rootVisualElement.Create<Button>();
applyButton.text = "应用数据";
applyButton.clicked += () =>
{
var bytes = JsonHelper.Get<byte[]>(inputField.value);
using var ms = new System.IO.MemoryStream(bytes);
using var reader = new System.IO.BinaryReader(ms);
Debug.Log($"应用数据中,长度为:{ms.Length}");
foreach (var header in UnityEntitiesService.QueryComponents<IEntityBinaryHeader>())
{
header.Deserialize(reader);
}
};
}
private void PrintBytes()
{
using var ms = new System.IO.MemoryStream();
using var writer = new System.IO.BinaryWriter(ms);
foreach (var header in UnityEntitiesService.QueryComponents<IEntityBinaryHeader>())
{
header.Serialize(writer);
}
var bytes = ms.ToArray();
writer.Dispose();
ms.Dispose();
_base64Label.text = JsonHelper.Get(bytes);
}
}
}

View File

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

View File

@@ -6,11 +6,11 @@ using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
namespace BITKit.Entities.Editor
namespace BITKit.Entities.GameEditor
{
public class UnityEntitiesServiceEditor : EditorWindow
{
[MenuItem("Tools/Entities/UnityEntitiesService")]
[MenuItem("Tools/Entities/EntitiesService")]
public static void Open()
{
var window = GetWindow<UnityEntitiesServiceEditor>();

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: b084884b824dece40b35759eb218d5c4
guid: 75d594a25b599204691b487a447d6e68
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@@ -1,15 +1,13 @@
{
"name": "BITKit.Entities.Player.Character",
"name": "BITKit.Entities.Net",
"rootNamespace": "",
"references": [
"GUID:14fe60d984bf9f84eac55c6ea033a8f4",
"GUID:709caf8d7fb6ef24bbba0ab9962a3ad0",
"GUID:f822dbf6fdfd4a5469cccaa2e4eed3b6",
"GUID:f51ebe6a0ceec4240a699833d6309b23",
"GUID:d525ad6bd40672747bde77962f1c401e",
"GUID:49b49c76ee64f6b41bf28ef951cb0e50",
"GUID:7efac18f239530141802fb139776f333",
"GUID:9354affc93e0f3e4a904785e7d4c0f59"
"GUID:9354affc93e0f3e4a904785e7d4c0f59",
"GUID:c56f2ae4d67b9b947a600c84225206a2"
],
"includePlatforms": [],
"excludePlatforms": [],

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 05850b7e403af6d48bc240ab3c2bc8f4
guid: c27e9384ceefce34796410b6135e54a5
AssemblyDefinitionImporter:
externalObjects: {}
userData:

View File

@@ -0,0 +1,172 @@
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Timers;
using BITKit.Entities.Player;
using UnityEngine;
namespace BITKit.Entities
{
[Serializable]
public struct EntitiesNetSyncCommand
{
public byte[] Data;
}
[Serializable]
public struct EntitiesNetSyncBatchCommand
{
public int Length;
public ulong[] Ids;
public ulong[] AddressablePaths;
public EntitiesNetSyncCommand[] Commands;
}
public class EntitiesNetService : MonoBehaviour
{
[Header(Constant.Header.Services)]
[SerializeReference, SubclassSelector] private ITicker ticker;
[SerializeReference, SubclassSelector] private IEntitiesService entitiesService;
[SerializeReference, SubclassSelector] private IPlayerService playerService;
[SerializeReference, SubclassSelector]private INetClient client;
[SerializeReference, SubclassSelector]private INetServer server;
private INetProvider clientNetProvider => client.Source as INetProvider;
private INetProvider serverNetProvider => server.Source as INetProvider;
[Inject]
private IEntityBinaryHeader _playerHeader;
[Inject] private IAddressable _playerAddressable;
[Inject]
private IEntity _playerEntity;
private readonly ConcurrentQueue<EntitiesNetSyncBatchCommand> _batchCommands = new();
private readonly ConcurrentQueue<EntitiesNetSyncCommand> _syncCommands = new();
private void Start()
{
ticker.Add(Tick);
clientNetProvider.AddCommandListener<EntitiesNetSyncBatchCommand>(_batchCommands.Enqueue);
serverNetProvider.AddCommandListener<EntitiesNetSyncCommand>(_syncCommands.Enqueue);
playerService.OnPlayerInitialized+=OnPlayerInitialized;
playerService.OnPlayerDisposed += OnPlayerDisposed;
destroyCancellationToken.Register(() =>
{
ticker.Remove(Tick);
playerService.OnPlayerInitialized-=OnPlayerInitialized;
});
}
private void OnPlayerDisposed(Entity obj)
{
_playerHeader = null;
_playerAddressable = null;
_playerEntity = null;
}
private void OnPlayerInitialized(Entity obj)
{
obj.Inject(this);
}
private void OnSyncCommand(EntitiesNetSyncCommand obj)
{
using var ms = new MemoryStream(obj.Data);
using var reader = new BinaryReader(ms);
var id = reader.ReadUInt64();
var path = reader.ReadUInt64();
entitiesService.GetOrAdd(id, x => AddEntity(id, path)).TryGetComponent<IEntityBinaryHeader>(out var header);
header.Deserialize(reader);
}
private void OnBatchCommand(EntitiesNetSyncBatchCommand obj)
{
for (var i = 0; i < obj.Length; i++)
{
var id = obj.Ids[i];
var path = obj.AddressablePaths[i];
var command = obj.Commands[i];
var entity = entitiesService.GetOrAdd(id,x=>AddEntity(id,path));
entity.TryGetComponent<IEntityBinaryHeader>(out var header);
using var ms = new MemoryStream(command.Data);
using var reader = new BinaryReader(ms);
header.Deserialize(reader);
}
}
private static IEntity AddEntity(ulong id,ulong addressableId)
{
var entity = AddressableHelper.Get<GameObject>(addressableId);
var instance = Instantiate(entity).GetComponent<Entity>();
instance.Id = id;
instance.WaitForInitializationComplete();
return instance;
}
private void Tick(float deltaTime)
{
while (_batchCommands.TryDequeue(out var command))
{
OnBatchCommand(command);
}
while (_syncCommands.TryDequeue(out var command))
{
OnSyncCommand(command);
}
if (client.IsConnected is false && server.IsRunningServer is false) return;
using var memoryStream = new MemoryStream();
if (client.IsConnected && _playerEntity as Entity && _playerHeader != null)
{
using var writer = new BinaryWriter(memoryStream);
writer.Write(_playerEntity.Id);
writer.Write(_playerAddressable.AddressableId);
_playerHeader.Serialize(writer);
var command = new EntitiesNetSyncCommand
{
Data = memoryStream.ToArray()
};
clientNetProvider.ServerCommand(command);
}
else if (server.IsRunningServer)
{
using var writer = new BinaryWriter(memoryStream);
var headers = entitiesService.QueryComponents<IEntity, IEntityBinaryHeader, IAddressable>();
var batchCommand = new EntitiesNetSyncBatchCommand()
{
Length = headers.Length,
Ids = new ulong[headers.Length],
AddressablePaths = new ulong[headers.Length],
Commands = new EntitiesNetSyncCommand[headers.Length]
};
var count = -1;
foreach (var (entity, header, addressable) in headers)
{
count++;
using var ms = new MemoryStream();
using var entityWriter = new BinaryWriter(ms);
header.Serialize(entityWriter);
entityWriter.Flush();
batchCommand.Ids[count] = entity.Id;
batchCommand.AddressablePaths[count] = addressable.AddressableId;
batchCommand.Commands[count] = new EntitiesNetSyncCommand { Data = ms.ToArray() };
}
serverNetProvider.AllClientCommand(batchCommand);
}
}
}
}

View File

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

View File

@@ -0,0 +1,32 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace BITKit.Entities
{
public sealed class EntityNetConfig : EntityBehavior
{
[SerializeField] private bool serverOnly;
[SerializeReference,SubclassSelector] private INetClient netClient;
[SerializeReference,SubclassSelector] private INetServer netServer;
[SerializeReference,SubclassSelector] private ITicker ticker;
public override void OnStart()
{
base.OnStart();
ticker?.Add(OnTick);
}
private void OnDestroy()
{
ticker?.Remove(OnTick);
}
private void OnTick(float deltaTime)
{
if (netClient.IsConnected && serverOnly)
{
Destroy(gameObject);
}
}
}
}

View File

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

View File

@@ -1,16 +1,20 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using UnityEngine;
namespace BITKit.Entities.Player
{
public class LocalPlayerBehavior : EntityBehavior
public class LocalPlayerBehavior : EntityBehavior,IEntityBinaryComponent
{
public int Id { get; }= new ConstantHash(nameof(LocalPlayerBehavior));
private IEntityPlayerComponent[] playerComponents;
private CancellationTokenSource initializeCancellationTokenSource;
private CancellationTokenSource disposeCancellationTokenSource;
public override async void OnStart()
{
initializeCancellationTokenSource = new CancellationTokenSource();
@@ -51,5 +55,13 @@ namespace BITKit.Entities.Player
disposeCancellationTokenSource.Dispose();
UnityPlayerServiceService.UnRegister((Entity)UnityEntity);
}
public void Serialize(BinaryWriter writer)
{
writer.Write(0);
}
public void Deserialize(BinaryReader reader)
{
}
}
}

View File

@@ -0,0 +1,36 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
namespace BITKit.Entities.Player
{
public class ProxyPlayerComponent : EntityBehavior,IEntityBinaryComponent
{
public int Id { get; } = new ConstantHash(nameof(LocalPlayerBehavior));
private readonly IntervalUpdate _timeout = new(8);
public override void OnStart()
{
base.OnStart();
_timeout.Reset();
}
public void Serialize(BinaryWriter writer)
{
}
public void Deserialize(BinaryReader reader)
{
reader.ReadInt32();
_timeout.Reset();
}
public override void OnUpdate(float deltaTime)
{
base.OnUpdate(deltaTime);
if (_timeout.AllowUpdate)
{
Destroy(gameObject);
}
}
}
}

View File

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

View File

@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using BITKit.StateMachine;
using UnityEngine;
@@ -36,6 +37,9 @@ namespace BITKit.Entities.Player
remove => stateMachine.OnStateChanged -= value;
}
public event Action<T> OnStateRegistered;
public event Action<T> OnStateUnRegistered;
public IDictionary<Type, T> StateDictionary => stateMachine.StateDictionary;
void IStateMachine<T>.Initialize()
@@ -62,5 +66,16 @@ namespace BITKit.Entities.Player
{
stateMachine.TransitionState(state);
}
public virtual void Register(T newState)=>StateMachineUtils.Register(this,newState);
public virtual void UnRegister(T newState)=>StateMachineUtils.UnRegister(this,newState);
void IStateMachine<T>.InvokeOnStateRegistered(T state)
{
OnStateRegistered?.Invoke(state);
}
void IStateMachine<T>.InvokeOnStateUnRegistered(T state)
{
OnStateUnRegistered?.Invoke(state);
}
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 80d35d9e6778dc84b88662124834dd35
guid: ea9ee800e8536fe45a4868de4bc936d9
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@@ -1,10 +1,9 @@
{
"name": "BITKit.WorkdChunk",
"name": "BITKit.Entities.Variable",
"rootNamespace": "",
"references": [
"GUID:a209c53514018594f9f482516f2a6781",
"GUID:14fe60d984bf9f84eac55c6ea033a8f4",
"GUID:9400d40641bab5b4a9702f65bf5c6eb5"
"GUID:709caf8d7fb6ef24bbba0ab9962a3ad0"
],
"includePlatforms": [],
"excludePlatforms": [],

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 0e144f3bb79485843b0a2df56bef0900
guid: f602b6f914f91d4499383d874af1decd
AssemblyDefinitionImporter:
externalObjects: {}
userData:

View File

@@ -0,0 +1,105 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.Pool;
namespace BITKit.Entities.Variables
{
public interface IVariable
{
string Variable { get; set; }
string[] Variables { get; }
event Action<string,string> OnVariableChanged;
event Func<string,bool> TryChangeVariable;
event Func<string> CollectVariables;
}
[Serializable]
public sealed class IVariableFromDI : InjectFromDI<IVariable>,IVariable
{
private IVariable _variableImplementation => Value;
public string Variable
{
get => _variableImplementation.Variable;
set => _variableImplementation.Variable = value;
}
public string[] Variables => _variableImplementation.Variables;
public event Action<string, string> OnVariableChanged
{
add => _variableImplementation.OnVariableChanged += value;
remove => _variableImplementation.OnVariableChanged -= value;
}
public event Func<string, bool> TryChangeVariable
{
add => _variableImplementation.TryChangeVariable += value;
remove => _variableImplementation.TryChangeVariable -= value;
}
public event Func<string> CollectVariables
{
add => _variableImplementation.CollectVariables += value;
remove => _variableImplementation.CollectVariables -= value;
}
}
[CustomType(typeof(IVariable),true)]
public sealed class EntityVariable:MonoBehaviour,IVariable
{
public string Variable
{
get => _variable;
set
{
if (TryChangeVariable is null || TryChangeVariable.CastAsFunc().All(Yes))
{
OnVariableChanged?.Invoke(_variable, _variable = value);
}
return;
bool Yes(Func<string, bool> arg)
{
return arg.Invoke(value);
}
}
}
public string[] Variables {
get
{
if (CollectVariables is null)
{
return Array.Empty<string>();
}
var listPool=ListPool<string>.Get();
foreach (var x in CollectVariables.CastAsFunc())
{
listPool.Add(x.Invoke());
}
var result = listPool.ToArray();
ListPool<string>.Release(listPool);
return result;
}
}
public event Action<string,string> OnVariableChanged;
public event Func<string,bool> TryChangeVariable;
public event Func<string> CollectVariables;
private string _variable="Default";
private void Awake()
{
if (GetType().GetCustomAttribute<CustomTypeAttribute>() is { AsGlobal: true })
{
DI.Register<IVariable>(this);
}
}
}
}

View File

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

View File

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

View File

@@ -1,12 +1,11 @@
{
"name": "BITKit.Entities.Physics.Runtime",
"name": "BITKit.Entities.World.Runtime",
"rootNamespace": "",
"references": [
"GUID:14fe60d984bf9f84eac55c6ea033a8f4",
"GUID:f51ebe6a0ceec4240a699833d6309b23",
"GUID:709caf8d7fb6ef24bbba0ab9962a3ad0",
"GUID:a3de65b07192e7d49bad7b4032d681de",
"GUID:7efac18f239530141802fb139776f333"
"GUID:1193c2664d97cc049a6e4c486c6bce71",
"GUID:bdb069e155d2f944cb1bf28602b6d4c1"
],
"includePlatforms": [],
"excludePlatforms": [],

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: be39401f40b20344a8e59d5ddab532bc
guid: 5835538f89758aa42ab9ebe7a5de98fb
AssemblyDefinitionImporter:
externalObjects: {}
userData:

View File

@@ -0,0 +1,24 @@
using System.Collections;
using System.Collections.Generic;
using BITKit.Entities;
using Quadtree;
using UnityEngine;
namespace BITKit.OpenWorld
{
public class EntityLOD : EntityBehavior,IWorldChunkObject
{
public Bounds GetBounds()
{
throw new System.NotImplementedException();
}
public Node<IWorldChunkObject> ParentNode { get; set; }
public void QuadTree_Root_Initialized(IQuadtreeRoot<IWorldChunkObject, Node<IWorldChunkObject>> root)
{
}
public int Id { get; set; }
public int Lod { get; set; }
}
}

View File

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

View File

@@ -26,6 +26,10 @@ namespace BITKit.Events
{
public List<UnityEventData> Targets = new List<UnityEventData>();
public void Invoke()
{
Invoke(Array.Empty<object>());
}
public void Invoke(params object[] objects)
{
foreach (var x in Targets)
@@ -170,6 +174,7 @@ namespace BITKit.Events
{
x.MethodName = changeEvent.newValue;
EditorUtility.SetDirty(_property.serializedObject.targetObject);
Update();
});
field.value = x.MethodName;

View File

@@ -1,88 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using UnityEngine;
using UnityEngine.Events;
using System.Threading.Tasks;
using System.Runtime.CompilerServices;
using System.Collections.Concurrent;
using Cysharp.Threading.Tasks;
namespace BITKit
{
public class BehaviourHelper : MonoBehaviour, IMainTicker
{
public static Action OnStop;
public static bool Actived;
static BehaviourHelper Singleton;
ConcurrentQueue<Action> queue = new();
List<Action<float>> Updates = new();
List<Action<float>> FixedUpdates = new();
public void Add(Action action)
{
queue.Enqueue(action);
}
public void AddAsUpdate(Action<float> action)
{
Updates.Add(action);
}
public void AddAsFixedUpdate(Action<float> action)
{
FixedUpdates.Add(action);
}
public void RemoveAsUpdate(Action<float> action)
{
Updates.Remove(action);
}
public void RemoveAsFixedUpdate(Action<float> action)
{
FixedUpdates.Remove(action);
}
void Update()
{
lock (queue)
{
while (queue.TryDequeue(out var action))
{
try
{
action.Invoke();
}
catch (System.Exception e)
{
Debug.LogError(e);
}
}
}
foreach (var update in Updates.ToArray())
{
update.Invoke(Time.deltaTime);
}
}
void FixedUpdate()
{
foreach (var fixedUpdate in FixedUpdates.ToArray())
{
fixedUpdate.Invoke(Time.fixedDeltaTime);
}
}
void OnDestroy()
{
OnStop?.Invoke();
}
[RuntimeInitializeOnLoadMethod]
static void Initialize()
{
GameObject go = new();
GameObject.DontDestroyOnLoad(go);
var behaviourHelper = go.AddComponent<BehaviourHelper>();
Singleton = behaviourHelper;
DI.Register<IMainTicker>(behaviourHelper);
Debug.Log($"{nameof(IMainTicker)}已创建");
go.name = nameof(BehaviourHelper);
go.hideFlags = HideFlags.NotEditable;
}
}
}

View File

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

View File

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

Binary file not shown.

View File

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

Binary file not shown.

View File

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

Binary file not shown.

View File

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

Binary file not shown.

View File

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

Binary file not shown.

View File

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

Binary file not shown.

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,53 @@
using UnityEngine;
using System.Collections;
using System.Runtime.InteropServices;
using System;
namespace System.IO
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public class OpenFileName
{
public int structSize = 0;
public IntPtr dlgOwner = IntPtr.Zero;
public IntPtr instance = IntPtr.Zero;
public String filter = null;
public String customFilter = null;
public int maxCustFilter = 0;
public int filterIndex = 0;
public String file = null;
public int maxFile = 0;
public String fileTitle = null;
public int maxFileTitle = 0;
public String initialDir = null;
public String title = null;
public int flags = 0;
public short fileOffset = 0;
public short fileExtension = 0;
public String defExt = null;
public IntPtr custData = IntPtr.Zero;
public IntPtr hook = IntPtr.Zero;
public String templateName = null;
public IntPtr reservedPtr = IntPtr.Zero;
public int reservedInt = 0;
public int flagsEx = 0;
}
public class LocalDialog
{
//链接指定系统函数 打开文件对话框
[DllImport("Comdlg32.dll", SetLastError = true, ThrowOnUnmappableChar = true, CharSet = CharSet.Auto)]
public static extern bool GetOpenFileName([In, Out] OpenFileName ofn);
public static bool GetOFN([In, Out] OpenFileName ofn)
{
return GetOpenFileName(ofn);
}
//链接指定系统函数 另存为对话框
[DllImport("Comdlg32.dll", SetLastError = true, ThrowOnUnmappableChar = true, CharSet = CharSet.Auto)]
public static extern bool GetSaveFileName([In, Out] OpenFileName ofn);
public static bool GetSFN([In,Out] OpenFileName ofn)
{
return GetSaveFileName(ofn);
}
}
}

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