迁移数据表到 Luban,移除 JsonNet、EnumUtility

This commit is contained in:
2026-09-13 14:08:14 +08:00
parent 4003b3aaba
commit de53890de6
607 changed files with 18515 additions and 3257 deletions
@@ -0,0 +1,6 @@
namespace SepCore.Entity
{
public class BatEnemy : MeleeEnemy
{
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 42fe1320652aa5444ab6b8ed8936d053
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,88 @@
using Cysharp.Threading.Tasks;
using SepCore.AsyncTask;
using SepCore.Definition;
using SepCore.Entity;
using SepCore.Timer;
using UnityEngine;
public abstract class EnemyBase : TargetableObject
{
protected Transform _target;
public abstract override ImpactData GetImpactData();
public virtual float AttackRange => 1f;
public virtual void SetTarget(Transform target) => _target = target;
protected EnemyData _enemyData;
protected bool _canAttack;
protected TimerHandle _attackTimerHandle;
protected void StartAttackCooldown(float cooldown)
{
_canAttack = false;
_attackTimerHandle = GameEntry.Timer.ScheduleOnce(cooldown, () => _canAttack = true, this);
}
protected void ResetAttackCooldown(float cooldown)
{
GameEntry.Timer.Cancel(_attackTimerHandle);
_canAttack = false;
_attackTimerHandle = GameEntry.Timer.ScheduleOnce(cooldown, () => _canAttack = true, this);
}
protected void CancelAttackCooldown()
{
GameEntry.Timer.Cancel(_attackTimerHandle);
_attackTimerHandle = TimerHandle.Invalid;
_canAttack = false;
}
protected override void OnShow(object userData)
{
base.OnShow(userData);
if (userData is EnemyData enemyData)
{
ApplyVisualParams(enemyData);
}
}
protected override void OnDead(EntityBase attacker)
{
if (Random.value < _enemyData.DropPercent)
{
var data = new CoinData(_enemyData.DropCoin, GameEntry.Entity.NextId(), 10001)
{
Position = this.CachedTransform.position
};
GameEntry.Entity.ShowCoinAsync(data).Forget();
}
if (Random.value < _enemyData.DropPercent)
{
var data = new ExpData(_enemyData.DropExp, GameEntry.Entity.NextId(), 10002)
{
Position = this.CachedTransform.position
};
GameEntry.Entity.ShowExpAsync(data).Forget();
}
base.OnDead(attacker);
}
private void ApplyVisualParams(EnemyData data)
{
CachedTransform.localScale = Vector3.one * Mathf.Max(0.1f, data.Scale);
var renderer = GetComponentInChildren<Renderer>();
if (renderer != null)
{
var block = new MaterialPropertyBlock();
block.SetColor("_BaseColor", data.Color);
renderer.SetPropertyBlock(block);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d33d6ac2d1874d4418780e3354e6b4e3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,107 @@
using SepCore.Definition;
using SepCore.Entity;
using UnityEngine;
using UnityGameFramework.Runtime;
namespace SepCore.Entity
{
public class EnemyProjectile : EntityBase
{
private EnemyProjectileData _projectileData;
private Vector3 _direction = Vector3.forward;
private bool _isActive;
private ImpactData _impactData;
private Collider[] _cachedColliders;
public bool IsActive => _isActive;
public ImpactData GetImpactData() => _impactData;
protected override void OnShow(object userData)
{
base.OnShow(userData);
_projectileData = userData as EnemyProjectileData;
if (_projectileData == null)
{
Log.Error("Enemy projectile data is invalid.");
_isActive = false;
GameEntry.Entity.HideEntity(this);
return;
}
_isActive = true;
_impactData = new ImpactData(_projectileData.OwnerCamp, _projectileData.AttackDamage);
_direction = _projectileData.Direction;
_direction.y = 0f;
if (_direction.sqrMagnitude <= Mathf.Epsilon)
{
_direction = CachedTransform.forward;
_direction.y = 0f;
}
if (_direction.sqrMagnitude <= Mathf.Epsilon)
{
_direction = Vector3.forward;
}
else
{
_direction.Normalize();
}
CachedTransform.rotation = Quaternion.LookRotation(_direction, Vector3.up);
if (_projectileData.OwnerCamp == CampType.Player)
{
gameObject.layer = LayerMask.NameToLayer("PlayerWeapon");
}
else if (_projectileData.OwnerCamp == CampType.Enemy)
{
gameObject.layer = LayerMask.NameToLayer("EnemyWeapon");
}
SetColliderEnabled(false);
}
protected override void OnUpdate(float elapseSeconds, float realElapseSeconds)
{
base.OnUpdate(elapseSeconds, realElapseSeconds);
if (!_isActive || _projectileData == null) return;
}
protected override void OnHide(bool isShutdown, object userData)
{
_isActive = false;
_projectileData = null;
_impactData = default;
_direction = Vector3.forward;
base.OnHide(isShutdown, userData);
}
public void Expire()
{
if (!_isActive) return;
_isActive = false;
GameEntry.Entity.HideEntity(this);
}
private void SetColliderEnabled(bool enabled)
{
_cachedColliders ??= GetComponentsInChildren<Collider>(true);
if (_cachedColliders == null) return;
for (int i = 0; i < _cachedColliders.Length; i++)
{
Collider collider = _cachedColliders[i];
if (collider == null)
{
continue;
}
collider.enabled = enabled;
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 22624f81b9364c8681b32d993f5e618f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,6 @@
namespace SepCore.Entity
{
public class FireMageEnemy : RemoteEnemy
{
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3c04fa71c274a6f4088722608ba26587
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,6 @@
namespace SepCore.Entity
{
public class GhostEnemy : RemoteEnemy
{
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2effd123b7296e448aea20b34fd24ce8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,238 @@
using SepCore.Components;
using SepCore.CustomUtility;
using SepCore.Definition;
using UnityEngine;
using UnityGameFramework.Runtime;
namespace SepCore.Entity
{
public class MeleeEnemy : EnemyBase
{
private enum AttackStateType
{
Idle,
Check_OutRange,
Check_InRange,
Attack
}
private MovementComponent _movementComponent;
private float _attackRange = 1f;
private float _attackCooldown = 1f;
private int _attackDamage = 1;
private float _sqrAttackRange;
private AttackStateType _attackState = AttackStateType.Idle;
private EnemyData _meleeEnemyData
{
get => _enemyData;
set => _enemyData = value;
}
private TargetableObject _targetableTarget;
protected override TargetableObjectData _targetableObjectData => _meleeEnemyData;
public override float AttackRange => _attackRange;
public override ImpactData GetImpactData()
{
return new ImpactData(_meleeEnemyData.Camp, _attackDamage);
}
#region FSM
protected override void OnInit(object userData)
{
base.OnInit(userData);
_movementComponent = GetComponent<MovementComponent>();
_healthComponent = GetComponent<HealthComponent>();
}
protected override void OnShow(object userData)
{
base.OnShow(userData);
if (userData is EnemyData enemyData)
{
_meleeEnemyData = enemyData;
_healthComponent.OnInit(enemyData.MaxHealthBase);
_movementComponent.OnInit(_meleeEnemyData.SpeedBase, this.CachedTransform, null, true);
_movementComponent.SetMove(true);
_attackRange = Mathf.Max(0.1f, _meleeEnemyData.AttackRange);
_attackCooldown = Mathf.Max(0.01f, _meleeEnemyData.AttackCooldown);
_attackDamage = Mathf.Max(1, _meleeEnemyData.AttackDamage);
_sqrAttackRange = _attackRange * _attackRange;
StartAttackCooldown(_attackCooldown);
_attackState = AttackStateType.Idle;
_targetableTarget = null;
this.CachedTransform.position = enemyData.Position;
}
else
{
Log.Error($"Invalid data type. Data type: {userData?.GetType()}");
}
}
protected override void OnUpdate(float elapseSeconds, float realElapseSeconds)
{
base.OnUpdate(elapseSeconds, realElapseSeconds);
UpdateAttackState(elapseSeconds);
}
protected override void OnHide(bool isShutdown, object userData)
{
_movementComponent.OnReset();
_healthComponent.OnReset();
_targetableTarget = null;
CancelAttackCooldown();
_attackState = AttackStateType.Idle;
base.OnHide(isShutdown, userData);
}
#endregion
public override void SetTarget(Transform target)
{
base.SetTarget(target);
_targetableTarget = target != null ? target.GetComponent<TargetableObject>() : null;
}
private void UpdateAttackState(float elapseSeconds)
{
switch (_attackState)
{
case AttackStateType.Idle:
SetMove(false);
if (HasValidTarget())
{
TransitionTo(AttackStateType.Check_OutRange);
}
break;
case AttackStateType.Check_OutRange:
if (!HasValidTarget())
{
TransitionTo(AttackStateType.Idle);
return;
}
if (IsTargetInRange())
{
TransitionTo(AttackStateType.Check_InRange);
return;
}
SetMove(true);
_movementComponent.SetDirection(GetTargetDirection());
break;
case AttackStateType.Check_InRange:
if (!HasValidTarget())
{
TransitionTo(AttackStateType.Idle);
return;
}
SetMove(false);
if (!IsTargetInRange())
{
TransitionTo(AttackStateType.Check_OutRange);
return;
}
if (_canAttack)
{
ResetAttackCooldown(_attackCooldown);
TransitionTo(AttackStateType.Attack);
}
break;
}
}
private void TransitionTo(AttackStateType newState)
{
_attackState = newState;
if (_attackState == AttackStateType.Check_InRange)
{
SetMove(false);
}
if (_attackState == AttackStateType.Attack)
{
SetMove(false);
ExecuteAttack();
TransitionTo(AttackStateType.Check_InRange);
}
}
private bool HasValidTarget()
{
if (_target == null) return false;
if (_targetableTarget == null || _targetableTarget.CachedTransform != _target)
{
_targetableTarget = _target.GetComponent<TargetableObject>();
}
return _targetableTarget != null && _targetableTarget.Available && !_targetableTarget.IsDead;
}
private bool IsTargetInRange()
{
if (_target == null) return false;
Vector3 delta = _target.position - this.CachedTransform.position;
delta.y = 0f;
return delta.sqrMagnitude <= _sqrAttackRange;
}
private void ExecuteAttack()
{
if (!HasValidTarget() || !IsTargetInRange()) return;
ImpactData targetImpactData = _targetableTarget.GetImpactData();
ImpactData selfImpactData = GetImpactData();
if (AIUtility.GetRelation(selfImpactData.Camp, targetImpactData.Camp) == RelationType.Friendly)
{
return;
}
int damage = AIUtility.CalcDamageHP(_attackDamage, null, targetImpactData.DefenseStat,
targetImpactData.DodgeStat);
_targetableTarget.ApplyDamage(this, damage);
}
private void SetMove(bool value)
{
if (_movementComponent != null)
{
_movementComponent.SetMove(value);
}
}
private Vector3 GetTargetDirection()
{
if (_target == null)
{
return Vector3.zero;
}
return new Vector3(
_target.position.x - this.CachedTransform.position.x,
0f,
_target.position.z - this.CachedTransform.position.z
).normalized;
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 112f2a17ab82438484782c9a763fdee1
timeCreated: 1768892870
@@ -0,0 +1,234 @@
using SepCore.Components;
using SepCore.AsyncTask;
using SepCore.CustomUtility;
using SepCore.Definition;
using Cysharp.Threading.Tasks;
using UnityEngine;
using UnityGameFramework.Runtime;
namespace SepCore.Entity
{
public class RemoteEnemy : EnemyBase
{
private const string EnemyProjectileGroupName = "Bullet";
private const float EnemyProjectileGroupAutoReleaseInterval = 60f;
private const int EnemyProjectileGroupCapacity = 64;
private const float EnemyProjectileGroupExpireTime = 60f;
private const int EnemyProjectileGroupPriority = 0;
private const string ProjectileSpeedParamKey = "ProjectileSpeed";
private const string ProjectileLifeTimeParamKey = "ProjectileLifeTime";
private const string ProjectileSpawnForwardOffsetParamKey = "ProjectileSpawnForwardOffset";
private const string ProjectileSpawnHeightOffsetParamKey = "ProjectileSpawnHeightOffset";
private const string ProjectileAssetNameParamKey = "ProjectileAssetName";
private MovementComponent _movementComponent;
private float _attackRange = 1f;
private float _attackRangeSquared;
private float _attackCooldown = 1f;
private int _attackDamage = 1;
[SerializeField] private float _projectileSpeed = 12f;
[SerializeField] private float _projectileLifeTime = 3f;
[SerializeField] private float _projectileSpawnForwardOffset = 0.7f;
[SerializeField] private float _projectileSpawnHeightOffset = 0.6f;
[SerializeField] private string _projectileAssetName = "BulletHandgun";
private EnemyData _remoteEnemyData
{
get => _enemyData;
set => _enemyData = value;
}
protected override TargetableObjectData _targetableObjectData => _remoteEnemyData;
public override float AttackRange => _attackRange;
public override ImpactData GetImpactData()
{
return new ImpactData(_remoteEnemyData.Camp, _attackDamage);
}
protected override void OnInit(object userData)
{
base.OnInit(userData);
_movementComponent = GetComponent<MovementComponent>();
_healthComponent = GetComponent<HealthComponent>();
}
protected override void OnShow(object userData)
{
base.OnShow(userData);
if (userData is EnemyData enemyData)
{
_remoteEnemyData = enemyData;
_healthComponent.OnInit(enemyData.MaxHealthBase);
_movementComponent.OnInit(_remoteEnemyData.SpeedBase, this.CachedTransform, null, true);
_movementComponent.SetMove(true);
_attackRange = Mathf.Max(0.1f, _remoteEnemyData.AttackRange);
_attackRangeSquared = _attackRange * _attackRange;
_attackCooldown = Mathf.Max(0.01f, _remoteEnemyData.AttackCooldown);
_attackDamage = Mathf.Max(1, _remoteEnemyData.AttackDamage);
_projectileSpeed = ReadPositiveParam(ProjectileSpeedParamKey, _projectileSpeed);
_projectileLifeTime = ReadPositiveParam(ProjectileLifeTimeParamKey, _projectileLifeTime);
_projectileSpawnForwardOffset = ReadPositiveParam(ProjectileSpawnForwardOffsetParamKey,
_projectileSpawnForwardOffset);
_projectileSpawnHeightOffset = ReadPositiveParam(ProjectileSpawnHeightOffsetParamKey,
_projectileSpawnHeightOffset);
_projectileAssetName = ReadStringParam(ProjectileAssetNameParamKey, _projectileAssetName);
StartAttackCooldown(_attackCooldown);
this.CachedTransform.position = enemyData.Position;
}
else
{
Log.Error($"Invalid data type. Data type: {userData?.GetType()}");
}
}
protected override void OnUpdate(float elapseSeconds, float realElapseSeconds)
{
base.OnUpdate(elapseSeconds, realElapseSeconds);
if (_target == null)
{
_movementComponent.SetMove(false);
return;
}
Vector3 toTarget = _target.position - this.CachedTransform.position;
toTarget.y = 0f;
float distanceSquared = toTarget.sqrMagnitude;
if (distanceSquared <= _attackRangeSquared)
{
_movementComponent.SetMove(false);
if (_canAttack)
{
TryFireProjectile();
ResetAttackCooldown(_attackCooldown);
}
}
else
{
_movementComponent.SetMove(true);
_movementComponent.SetDirection(GetTargetDirection());
}
}
protected override void OnHide(bool isShutdown, object userData)
{
_movementComponent.OnReset();
_healthComponent.OnReset();
CancelAttackCooldown();
base.OnHide(isShutdown, userData);
}
private void TryFireProjectile()
{
if (!EnsureEnemyProjectileGroup()) return;
Vector3 spawnPosition = this.CachedTransform.position +
this.CachedTransform.forward * _projectileSpawnForwardOffset +
Vector3.up * _projectileSpawnHeightOffset;
Vector3 direction = _target.position - spawnPosition;
direction.y = 0f;
if (direction.sqrMagnitude <= Mathf.Epsilon)
{
direction = this.CachedTransform.forward;
direction.y = 0f;
}
if (direction.sqrMagnitude <= Mathf.Epsilon)
{
direction = Vector3.forward;
}
else
{
direction.Normalize();
}
int projectileEntityId = GameEntry.Entity.NextId();
var projectileData = new EnemyProjectileData(projectileEntityId, Id, _remoteEnemyData.Camp,
_attackDamage, _projectileSpeed, _projectileLifeTime, direction)
{
Position = spawnPosition,
Rotation = Quaternion.LookRotation(direction, Vector3.up)
};
GameEntry.Entity.ShowEntityAsync<EnemyProjectile>(
projectileEntityId,
AssetUtility.GetEntityAsset(_projectileAssetName),
EnemyProjectileGroupName,
Constant.AssetPriority.BulletAsset,
projectileData).Forget();
}
private static bool EnsureEnemyProjectileGroup()
{
var entityComponent = GameEntry.Entity;
if (entityComponent == null) return false;
if (entityComponent.HasEntityGroup(EnemyProjectileGroupName))
{
return true;
}
bool addResult = entityComponent.AddEntityGroup(
EnemyProjectileGroupName,
EnemyProjectileGroupAutoReleaseInterval,
EnemyProjectileGroupCapacity,
EnemyProjectileGroupExpireTime,
EnemyProjectileGroupPriority);
if (!addResult)
{
Log.Warning("Can not create entity group '{0}'.", EnemyProjectileGroupName);
return false;
}
return true;
}
private float ReadPositiveParam(string paramName, float defaultValue)
{
if (_remoteEnemyData != null &&
_remoteEnemyData.TryGetParam(paramName, out string rawValue) &&
float.TryParse(rawValue, out float parsedValue))
{
return Mathf.Max(0.01f, parsedValue);
}
return Mathf.Max(0.01f, defaultValue);
}
private string ReadStringParam(string paramName, string defaultValue)
{
if (_remoteEnemyData != null &&
_remoteEnemyData.TryGetParam(paramName, out string rawValue) &&
!string.IsNullOrWhiteSpace(rawValue))
{
return rawValue;
}
return defaultValue;
}
private Vector3 GetTargetDirection()
{
if (_target == null)
{
return Vector3.zero;
}
return new Vector3(
_target.position.x - this.CachedTransform.position.x,
0f,
_target.position.z - this.CachedTransform.position.z
).normalized;
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b90e05d1e7a5475bb928b2445e113767
timeCreated: 1770209676
@@ -0,0 +1,6 @@
namespace SepCore.Entity
{
public class SkeletonEnemy : MeleeEnemy
{
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 21ea777a602cd034cb6177ef0efdea42
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,6 @@
namespace SepCore.Entity
{
public class SkeletonGiantEnemy : MeleeEnemy
{
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3698c16c2f366404cbdd54efa880612b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: