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

@@ -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: 8de7270cf1d43f64fafdc3413158cea3
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,25 +0,0 @@
{
"name": "BITKit.Entities.Player.Interactive",
"rootNamespace": "",
"references": [
"GUID:14fe60d984bf9f84eac55c6ea033a8f4",
"GUID:709caf8d7fb6ef24bbba0ab9962a3ad0",
"GUID:f822dbf6fdfd4a5469cccaa2e4eed3b6",
"GUID:f51ebe6a0ceec4240a699833d6309b23",
"GUID:75469ad4d38634e559750d17036d5f7c",
"GUID:d525ad6bd40672747bde77962f1c401e",
"GUID:49b49c76ee64f6b41bf28ef951cb0e50",
"GUID:508392158bd966c4d9c21e19661a441d",
"GUID:7efac18f239530141802fb139776f333",
"GUID:9354affc93e0f3e4a904785e7d4c0f59"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

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,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

@@ -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: c8cf20e38c0584247ab1573e085274d4
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

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: c78fe9fd58f5efc4abdeb6d193bf258b
guid: 4ff33423878ac11439fbf15f38dbe628
MonoImporter:
externalObjects: {}
serializedVersion: 2

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: 80d35d9e6778dc84b88662124834dd35
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: be39401f40b20344a8e59d5ddab532bc
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: 1b5481cf34bf4a145898ac81e58abf8f
guid: ea9ee800e8536fe45a4868de4bc936d9
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

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

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 05850b7e403af6d48bc240ab3c2bc8f4
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: 0e144f3bb79485843b0a2df56bef0900
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: