调整部分数据表配置,优化 SpriteCache 功能
This commit is contained in:
@@ -5,7 +5,6 @@ using SepCore.EnemyManager;
|
||||
using SepCore.HPBar;
|
||||
using SepCore.InputModule.Runtime;
|
||||
using SepCore.CameraModule;
|
||||
using SepCore.SpriteCache;
|
||||
using SepCore.UIRouter;
|
||||
using SepCore.Simulation;
|
||||
using SepCore.Timer;
|
||||
@@ -27,8 +26,6 @@ public partial class GameEntry
|
||||
|
||||
public static SimulationWorld SimulationWorld { get; private set; }
|
||||
|
||||
public static SpriteCacheComponent SpriteCache { get; private set; }
|
||||
|
||||
public static UIRouterComponent UIRouter { get; private set; }
|
||||
|
||||
public static InputModuleComponent InputModule { get; private set; }
|
||||
@@ -45,7 +42,6 @@ public partial class GameEntry
|
||||
DamageText = UnityGameFramework.Runtime.GameEntry.GetComponent<DamageTextComponent>();
|
||||
EnemyManager = UnityGameFramework.Runtime.GameEntry.GetComponent<EnemyManagerComponent>();
|
||||
SimulationWorld = UnityGameFramework.Runtime.GameEntry.GetComponent<SimulationWorld>();
|
||||
SpriteCache = UnityGameFramework.Runtime.GameEntry.GetComponent<SpriteCacheComponent>();
|
||||
UIRouter = UnityGameFramework.Runtime.GameEntry.GetComponent<UIRouterComponent>();
|
||||
InputModule = UnityGameFramework.Runtime.GameEntry.GetComponent<InputModuleComponent>();
|
||||
CameraModule = UnityGameFramework.Runtime.GameEntry.GetComponent<CameraModuleComponent>();
|
||||
|
||||
@@ -5,7 +5,6 @@ using Cysharp.Threading.Tasks;
|
||||
using SepCore.CustomUtility;
|
||||
using SepCore.Definition;
|
||||
using SepCore.Entity;
|
||||
using SepCore.Entity.Weapon;
|
||||
using UnityGameFramework.Runtime;
|
||||
using HideEntityCompleteEventArgs = UnityGameFramework.Runtime.HideEntityCompleteEventArgs;
|
||||
using ShowEntityFailureEventArgs = UnityGameFramework.Runtime.ShowEntityFailureEventArgs;
|
||||
@@ -162,22 +161,11 @@ namespace SepCore.AsyncTask
|
||||
float timeout = 30f,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (data == null)
|
||||
{
|
||||
Log.Warning("Enemy data is invalid.");
|
||||
return UniTask.FromResult<EnemyBase>(null);
|
||||
}
|
||||
|
||||
Type enemyType = TryGetType(data.EnemyType.ToString());
|
||||
Type enemyType = GetLogicType(data.LogicType);
|
||||
EntityConfig entityConfig = GameEntry.Luban.Get<EntityConfig>(data.AssetName);
|
||||
if (enemyType == null || entityConfig == null)
|
||||
{
|
||||
Log.Warning("Can not load enemy logic type or entity config for assetName '{0}'.", data.AssetName);
|
||||
return UniTask.FromResult<EnemyBase>(null);
|
||||
}
|
||||
|
||||
return entityComponent
|
||||
.ShowEntityAsync(data.Id, enemyType, AssetUtility.GetEntityAsset(entityConfig.PrefabPath), "Enemy",
|
||||
return entityComponent.ShowEntityAsync(
|
||||
data.Id, enemyType, AssetUtility.GetEntityAsset(entityConfig.PrefabPath), "Enemy",
|
||||
Constant.AssetPriority.EnemyAsset, data, timeout, cancellationToken)
|
||||
.ContinueWith(entity => entity?.Logic as EnemyBase);
|
||||
}
|
||||
@@ -190,22 +178,11 @@ namespace SepCore.AsyncTask
|
||||
float timeout = 30f,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (data == null)
|
||||
{
|
||||
Log.Warning("Weapon data is invalid.");
|
||||
return UniTask.FromResult<WeaponBase>(null);
|
||||
}
|
||||
|
||||
Type weaponType = TryGetType("Weapon." + data.WeaponType);
|
||||
Type weaponType = GetLogicType(data.LogicType);
|
||||
EntityConfig entityConfig = GameEntry.Luban.Get<EntityConfig>(data.AssetName);
|
||||
if (weaponType == null || entityConfig == null)
|
||||
{
|
||||
Log.Warning("Can not load weapon logic type or entity config for assetName '{0}'.", data.AssetName);
|
||||
return UniTask.FromResult<WeaponBase>(null);
|
||||
}
|
||||
|
||||
return entityComponent
|
||||
.ShowEntityAsync(data.Id, weaponType, AssetUtility.GetEntityAsset(entityConfig.PrefabPath), "Weapon",
|
||||
return entityComponent.ShowEntityAsync(
|
||||
data.Id, weaponType, AssetUtility.GetEntityAsset(entityConfig.PrefabPath), "Weapon",
|
||||
Constant.AssetPriority.WeaponAsset, data, timeout, cancellationToken)
|
||||
.ContinueWith(entity => entity?.Logic as WeaponBase);
|
||||
}
|
||||
@@ -298,24 +275,13 @@ namespace SepCore.AsyncTask
|
||||
float timeout,
|
||||
CancellationToken cancellationToken) where T : EntityLogic
|
||||
{
|
||||
if (data == null)
|
||||
{
|
||||
Log.Warning("Data is invalid.");
|
||||
return UniTask.FromResult<T>(null);
|
||||
}
|
||||
|
||||
EntityConfig entityConfig = GameEntry.Luban.Get<EntityConfig>(data.AssetName);
|
||||
if (entityConfig == null)
|
||||
{
|
||||
Log.Warning("Can not load entity assetName '{0}' from data table.", data.AssetName);
|
||||
return UniTask.FromResult<T>(null);
|
||||
}
|
||||
|
||||
return entityComponent.ShowEntityAsync<T>(data.Id, AssetUtility.GetEntityAsset(entityConfig.PrefabPath),
|
||||
entityGroupName, priority, data, timeout, cancellationToken);
|
||||
}
|
||||
|
||||
private static Type TryGetType(string rawTypeName)
|
||||
private static Type GetLogicType(string rawTypeName)
|
||||
{
|
||||
string typeName = EntityNamespace + rawTypeName;
|
||||
if (!_typeDict.TryGetValue(typeName, out Type type))
|
||||
@@ -323,8 +289,7 @@ namespace SepCore.AsyncTask
|
||||
type = Type.GetType(typeName);
|
||||
if (type == null)
|
||||
{
|
||||
Log.Warning("Can not load entity type '{0}'.", typeName);
|
||||
return null;
|
||||
throw new InvalidOperationException($"Can not load entity type '{typeName}'.");
|
||||
}
|
||||
|
||||
_typeDict.Add(typeName, type);
|
||||
|
||||
+27
-7
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using GameFramework.Resource;
|
||||
using UnityGameFramework.Runtime;
|
||||
@@ -20,14 +21,33 @@ namespace SepCore.AsyncTask
|
||||
/// <param name="resourceComponent">资源组件</param>
|
||||
/// <param name="assetName">资源名称</param>
|
||||
/// <param name="priority">加载优先级</param>
|
||||
/// <returns>加载完成的资源</returns>
|
||||
public static UniTask<T> LoadAssetAsync<T>(this ResourceComponent resourceComponent, string assetName, int priority = 0)
|
||||
/// <param name="userData">用户自定义数据</param>
|
||||
/// <param name="progress">加载进度</param>
|
||||
/// <param name="timeout">超时时间(秒),0表示不超时</param>
|
||||
/// <returns>加载的资源</returns>
|
||||
public static UniTask<T> LoadAssetAsync<T>(this ResourceComponent resourceComponent,
|
||||
string assetName,
|
||||
int priority = 0,
|
||||
object userData = null,
|
||||
IProgress<float> progress = null,
|
||||
float timeout = 0f) where T : class
|
||||
{
|
||||
var tcs = AutoResetUniTaskCompletionSource<T>.Create();
|
||||
resourceComponent.LoadAsset(assetName, priority, new LoadAssetCallbacks(
|
||||
(_, asset, _, _) => tcs.TrySetResult((T)asset),
|
||||
(_, _, errorMessage, _) => tcs.TrySetException(new Exception(errorMessage))
|
||||
));
|
||||
var tcs = new UniTaskCompletionSource<T>();
|
||||
|
||||
var callbacks = new LoadAssetCallbacks(
|
||||
(name, asset, duration, ud) => tcs.TrySetResult((T)asset),
|
||||
(name, status, errorMessage, ud) => tcs.TrySetException(new Exception($"加载资源失败: {name}, status: {status}, error: {errorMessage}")),
|
||||
(name, p, ud) => progress?.Report(p)
|
||||
);
|
||||
|
||||
resourceComponent.LoadAsset(assetName, typeof(T), priority, callbacks, userData);
|
||||
|
||||
if (timeout > 0f)
|
||||
{
|
||||
UniTask.Delay(TimeSpan.FromSeconds(timeout), cancellationToken: CancellationToken.None)
|
||||
.ContinueWith(() => tcs.TrySetException(new TimeoutException($"加载资源超时: {assetName}, {timeout}秒")));
|
||||
}
|
||||
|
||||
return tcs.Task;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,202 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using SepCore.CustomUtility;
|
||||
using SepCore.Definition;
|
||||
using UnityEngine;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace SepCore.AsyncTask
|
||||
{
|
||||
/// <summary>
|
||||
/// 图集 Sprite 加载器,通过图集名 + 序号定位 Sprite。
|
||||
/// 序号 -1 表示图集本身就是一张完整 Sprite,不需要切分。
|
||||
/// </summary>
|
||||
public static class SpriteLoader
|
||||
{
|
||||
private const float DefaultPixelsPerUnit = 32f;
|
||||
|
||||
private static readonly Dictionary<string, Texture2D> _textureCache = new();
|
||||
private static readonly Dictionary<string, Task<Texture2D>> _loadingTextures = new();
|
||||
private static readonly Dictionary<string, Dictionary<int, Sprite>> _spriteCache = new();
|
||||
|
||||
/// <summary>
|
||||
/// 异步加载图集 Sprite
|
||||
/// </summary>
|
||||
/// <param name="config">Sprite 配置</param>
|
||||
/// <param name="tileSize">切分块尺寸(像素),默认 32</param>
|
||||
/// <param name="pixelsPerUnit">Sprite 像素单位比,默认 32</param>
|
||||
/// <param name="timeout">超时时间(秒),0 表示不超时</param>
|
||||
/// <returns>加载的 Sprite,失败时返回 null</returns>
|
||||
public static UniTask<Sprite> LoadSpriteAsync(SpriteConfig config, int tileSize = 32,
|
||||
float pixelsPerUnit = DefaultPixelsPerUnit, float timeout = 0f)
|
||||
{
|
||||
return LoadSpriteAsync(config.AtlasPath, config.SpriteIndex, tileSize, pixelsPerUnit, timeout);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步加载图集 Sprite,按资源键查 tbspriteconfig 表定位
|
||||
/// </summary>
|
||||
/// <param name="key">tbspriteconfig 的资源键</param>
|
||||
/// <param name="tileSize">切分块尺寸(像素),默认 32</param>
|
||||
/// <param name="pixelsPerUnit">Sprite 像素单位比,默认 32</param>
|
||||
/// <param name="timeout">超时时间(秒),0 表示不超时</param>
|
||||
/// <returns>加载的 Sprite,失败时返回 null</returns>
|
||||
public static UniTask<Sprite> LoadSpriteByKeyAsync(string key, int tileSize = 32,
|
||||
float pixelsPerUnit = DefaultPixelsPerUnit, float timeout = 0f)
|
||||
{
|
||||
SpriteConfig config = global::GameEntry.Luban.Get<SpriteConfig>(key);
|
||||
if (config == null)
|
||||
{
|
||||
Log.Error("Sprite config not found: {0}", key);
|
||||
return default;
|
||||
}
|
||||
|
||||
return LoadSpriteAsync(config, tileSize, pixelsPerUnit, timeout);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步加载图集 Sprite
|
||||
/// </summary>
|
||||
/// <param name="atlasName">图集名称(相对 Assets/GameMain/Textures 的路径,含扩展名,如 32rogues/monsters.png)</param>
|
||||
/// <param name="index">序号,-1 表示整张图集作为一张 Sprite</param>
|
||||
/// <param name="tileSize">切分块尺寸(像素),默认 32</param>
|
||||
/// <param name="pixelsPerUnit">Sprite 像素单位比,默认 32</param>
|
||||
/// <param name="timeout">超时时间(秒),0 表示不超时</param>
|
||||
/// <returns>加载的 Sprite,失败时返回 null</returns>
|
||||
public static async UniTask<Sprite> LoadSpriteAsync(string atlasName, int index, int tileSize = 32,
|
||||
float pixelsPerUnit = DefaultPixelsPerUnit, float timeout = 0f)
|
||||
{
|
||||
Texture2D texture = await GetTextureAsync(atlasName, timeout);
|
||||
if (texture == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
int cacheKey = index < 0 ? -1 : index;
|
||||
if (!_spriteCache.TryGetValue(atlasName, out Dictionary<int, Sprite> sprites))
|
||||
{
|
||||
sprites = new Dictionary<int, Sprite>();
|
||||
_spriteCache[atlasName] = sprites;
|
||||
}
|
||||
|
||||
if (sprites.TryGetValue(cacheKey, out Sprite cached))
|
||||
{
|
||||
return cached;
|
||||
}
|
||||
|
||||
Sprite sprite = CreateSprite(texture, cacheKey, tileSize, pixelsPerUnit);
|
||||
if (sprite != null)
|
||||
{
|
||||
sprites[cacheKey] = sprite;
|
||||
}
|
||||
return sprite;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 释放指定图集的所有 Sprite 和纹理引用
|
||||
/// </summary>
|
||||
public static void Release(string atlasName)
|
||||
{
|
||||
if (_spriteCache.TryGetValue(atlasName, out Dictionary<int, Sprite> sprites))
|
||||
{
|
||||
foreach (Sprite sprite in sprites.Values)
|
||||
{
|
||||
if (sprite != null)
|
||||
{
|
||||
UnityEngine.Object.Destroy(sprite);
|
||||
}
|
||||
}
|
||||
sprites.Clear();
|
||||
_spriteCache.Remove(atlasName);
|
||||
}
|
||||
|
||||
if (_textureCache.TryGetValue(atlasName, out Texture2D texture))
|
||||
{
|
||||
global::GameEntry.Resource.UnloadAsset(texture);
|
||||
_textureCache.Remove(atlasName);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 释放所有图集的 Sprite 和纹理引用
|
||||
/// </summary>
|
||||
public static void ReleaseAll()
|
||||
{
|
||||
List<string> atlasNames = new List<string>(_textureCache.Keys);
|
||||
foreach (string atlasName in atlasNames)
|
||||
{
|
||||
Release(atlasName);
|
||||
}
|
||||
}
|
||||
|
||||
private static async UniTask<Texture2D> GetTextureAsync(string atlasName, float timeout)
|
||||
{
|
||||
if (_textureCache.TryGetValue(atlasName, out Texture2D cached))
|
||||
{
|
||||
return cached;
|
||||
}
|
||||
|
||||
if (_loadingTextures.TryGetValue(atlasName, out Task<Texture2D> loading))
|
||||
{
|
||||
return await loading;
|
||||
}
|
||||
|
||||
Task<Texture2D> task = LoadTextureAsync(atlasName, timeout).AsTask();
|
||||
_loadingTextures[atlasName] = task;
|
||||
try
|
||||
{
|
||||
Texture2D texture = await task;
|
||||
if (texture != null)
|
||||
{
|
||||
_textureCache[atlasName] = texture;
|
||||
}
|
||||
return texture;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_loadingTextures.Remove(atlasName);
|
||||
}
|
||||
}
|
||||
|
||||
private static async UniTask<Texture2D> LoadTextureAsync(string atlasName, float timeout)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await global::GameEntry.Resource.LoadAssetAsync<Texture2D>(
|
||||
AssetUtility.GetSpriteAsset(atlasName), Constant.AssetPriority.SpriteAsset, timeout: timeout);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error("加载图集失败: {0}, error: {1}", atlasName, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static Sprite CreateSprite(Texture2D texture, int index, int tileSize, float pixelsPerUnit)
|
||||
{
|
||||
if (index < 0)
|
||||
{
|
||||
return Sprite.Create(texture, new Rect(0f, 0f, texture.width, texture.height),
|
||||
new Vector2(0.5f, 0.5f), pixelsPerUnit, 0, SpriteMeshType.FullRect);
|
||||
}
|
||||
|
||||
int columns = Mathf.Max(1, texture.width / tileSize);
|
||||
int rows = Mathf.Max(1, texture.height / tileSize);
|
||||
int column = index % columns;
|
||||
int row = index / columns;
|
||||
if (row >= rows)
|
||||
{
|
||||
Log.Error("图集 {0} 序号 {1} 超出范围 (cols: {2}, rows: {3})", texture.name, index, columns, rows);
|
||||
return null;
|
||||
}
|
||||
|
||||
float x = column * tileSize;
|
||||
float y = texture.height - (row + 1) * tileSize;
|
||||
// 交互描边需要完整矩形网格,才能在 Shader 中为图案四周扩展留白。
|
||||
return Sprite.Create(texture, new Rect(x, y, tileSize, tileSize),
|
||||
new Vector2(0.5f, 0.5f), pixelsPerUnit, 0, SpriteMeshType.FullRect);
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aae7fd2af99064a4088471109952ad96
|
||||
guid: d7c896f5a3874033ab7cb99a06dbc0b7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
@@ -1,23 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using SepCore.Definition;
|
||||
using UnityGameFramework.Runtime;
|
||||
using SepCore.CustomUtility;
|
||||
|
||||
namespace SepCore.Entity
|
||||
{
|
||||
public static class EntityExtension
|
||||
{
|
||||
private static int s_SerialId = -10;
|
||||
private static int _serialId = 0;
|
||||
|
||||
private const string EntityNamespace = "SepCore.Entity.";
|
||||
private static readonly Dictionary<string, Type> _typeDict;
|
||||
|
||||
static EntityExtension()
|
||||
{
|
||||
_typeDict = new Dictionary<string, Type>();
|
||||
}
|
||||
|
||||
public static EntityBase GetGameEntity(this EntityComponent entityComponent, int entityId)
|
||||
{
|
||||
@@ -41,116 +28,9 @@ namespace SepCore.Entity
|
||||
entityComponent.AttachEntity(entityBase.Entity, ownerId, parentTransformPath, userData);
|
||||
}
|
||||
|
||||
public static void ShowEntity<T>(this EntityComponent entityComponent, EntityDataBase data, string group,
|
||||
int priority) where T : EntityBase
|
||||
{
|
||||
if (data == null)
|
||||
{
|
||||
Log.Warning("Data is invalid.");
|
||||
return;
|
||||
}
|
||||
|
||||
EntityConfig entityConfig = GameEntry.Luban.Get<EntityConfig>(data.AssetName);
|
||||
if (entityConfig == null)
|
||||
{
|
||||
Log.Warning("Can not load entity assetName '{0}' from data table.", data.AssetName);
|
||||
return;
|
||||
}
|
||||
|
||||
entityComponent.ShowEntity(data.Id, typeof(T), AssetUtility.GetEntityAsset(entityConfig.PrefabPath), group,
|
||||
priority, data);
|
||||
}
|
||||
|
||||
public static void ShowPlayer(this EntityComponent entityComponent, PlayerData data)
|
||||
{
|
||||
entityComponent.ShowEntity(typeof(Player), "Player", Constant.AssetPriority.PlayerAsset, data);
|
||||
}
|
||||
|
||||
public static void ShowEnemy(this EntityComponent entityComponent, EnemyData data)
|
||||
{
|
||||
if (data == null)
|
||||
{
|
||||
Log.Warning("Enemy data is invalid.");
|
||||
return;
|
||||
}
|
||||
|
||||
var enemyType = TryGetType(data.EnemyType.ToString());
|
||||
entityComponent.ShowEntity(enemyType, "Enemy", Constant.AssetPriority.EnemyAsset, data);
|
||||
}
|
||||
|
||||
public static void ShowWeapon(this EntityComponent entityComponent, WeaponData data)
|
||||
{
|
||||
if (data == null)
|
||||
{
|
||||
Log.Warning("Weapon data is invalid.");
|
||||
return;
|
||||
}
|
||||
|
||||
var weaponType = TryGetType("Weapon." + data.WeaponType);
|
||||
entityComponent.ShowEntity(weaponType, "Weapon", Constant.AssetPriority.WeaponAsset, data);
|
||||
}
|
||||
|
||||
public static void ShowEffect(this EntityComponent entityComponent, EffectData data)
|
||||
{
|
||||
entityComponent.ShowEntity(typeof(Effect), "Effect", Constant.AssetPriority.EffectAsset, data);
|
||||
}
|
||||
|
||||
public static void ShowCoin(this EntityComponent entityComponent, CoinData data)
|
||||
{
|
||||
entityComponent.ShowEntity(typeof(CoinEntity), "Drop", Constant.AssetPriority.EffectAsset, data);
|
||||
}
|
||||
|
||||
public static void ShowExp(this EntityComponent entityComponent, ExpData data)
|
||||
{
|
||||
entityComponent.ShowEntity(typeof(ExpEntity), "Drop", Constant.AssetPriority.EffectAsset, data);
|
||||
}
|
||||
|
||||
private static void ShowEntity(this EntityComponent entityComponent, Type logicType, string entityGroup,
|
||||
int priority, EntityDataBase data)
|
||||
{
|
||||
if (data == null)
|
||||
{
|
||||
Log.Warning("Data is invalid.");
|
||||
return;
|
||||
}
|
||||
|
||||
EntityConfig entityConfig = GameEntry.Luban.Get<EntityConfig>(data.AssetName);
|
||||
if (entityConfig == null)
|
||||
{
|
||||
Log.Warning("Can not load entity assetName '{0}' from data table.", data.AssetName);
|
||||
return;
|
||||
}
|
||||
|
||||
entityComponent.ShowEntity(data.Id, logicType, AssetUtility.GetEntityAsset(entityConfig.PrefabPath), entityGroup,
|
||||
priority, data);
|
||||
}
|
||||
|
||||
private static Type TryGetType(string rawTypeName)
|
||||
{
|
||||
string typeName = EntityNamespace + rawTypeName;
|
||||
if (!_typeDict.TryGetValue(typeName, out Type type))
|
||||
{
|
||||
type = Type.GetType(typeName);
|
||||
if (type == null)
|
||||
{
|
||||
Log.Warning("Can not load entity type '{0}'.", typeName);
|
||||
return null;
|
||||
}
|
||||
|
||||
_typeDict.Add(typeName, type);
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
public static int NextId(this EntityComponent entityComponent)
|
||||
{
|
||||
return --s_SerialId;
|
||||
}
|
||||
|
||||
public static int SerialId(this EntityComponent entityComponent)
|
||||
{
|
||||
return ++_serialId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using SepCore.Entity;
|
||||
using SepCore.Entity.Weapon;
|
||||
using UnityEngine;
|
||||
|
||||
namespace SepCore.Components
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using SepCore.Definition;
|
||||
using SepCore.Entity.Weapon;
|
||||
using SepCore.Entity;
|
||||
using UnityEngine;
|
||||
|
||||
@@ -8,11 +7,6 @@ namespace SepCore.Components
|
||||
{
|
||||
public class BackpackComponent : MonoBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// 武器槽容量,由 RoleConfig 决定。
|
||||
/// </summary>
|
||||
private int _weaponCapacity;
|
||||
|
||||
/// <summary>
|
||||
/// 玩家类引用。
|
||||
/// </summary>
|
||||
@@ -40,14 +34,13 @@ namespace SepCore.Components
|
||||
|
||||
public IReadOnlyList<WeaponBase> Weapons => _weapons;
|
||||
public IReadOnlyList<PropItem> Props => _props;
|
||||
public int WeaponCapacity => _weaponCapacity;
|
||||
public int WeaponCapacity => GameEntry.Luban.Global.WeaponCapacity;
|
||||
|
||||
public void OnInit(Player player, int weaponCapacity)
|
||||
public void OnInit(Player player)
|
||||
{
|
||||
_weaponCapacity = weaponCapacity;
|
||||
_player = player;
|
||||
|
||||
_weapons = new List<WeaponBase>(_weaponCapacity);
|
||||
_weapons = new List<WeaponBase>(WeaponCapacity);
|
||||
_props = new List<PropItem>();
|
||||
_statComponent = GetComponent<StatComponent>();
|
||||
}
|
||||
@@ -60,7 +53,7 @@ namespace SepCore.Components
|
||||
|
||||
public bool AttachWeapon(WeaponBase weapon)
|
||||
{
|
||||
if (_weapons.Count == _weaponCapacity) return false;
|
||||
if (_weapons.Count == WeaponCapacity) return false;
|
||||
GameEntry.Entity.AttachEntity(weapon.Id, _player.Id, _weaponSlots[_weapons.Count]);
|
||||
_weapons.Add(weapon);
|
||||
weapon.SetEnabled(true);
|
||||
|
||||
+13
-8
@@ -19,7 +19,7 @@ namespace SepCore.EnemyManager
|
||||
private EnemyRegistry _enemyRegistry;
|
||||
private EnemySpawnScheduler _spawnScheduler;
|
||||
|
||||
public IReadOnlyCollection<EntityBase> Enemies => _enemyRegistry?.Enemies;
|
||||
public IReadOnlyCollection<EntityBase> Enemies => _enemyRegistry.Enemies;
|
||||
|
||||
[SerializeField] private int _spawnEnemyMaxCount = 5000;
|
||||
[SerializeField] private int _spawnDistanceFromPlayer = 20;
|
||||
@@ -38,10 +38,10 @@ namespace SepCore.EnemyManager
|
||||
// 此时 _isStopped 为真,由 OnShowEntitySuccess 在出生瞬间兜底 Hide 掉。
|
||||
private bool _isStopped;
|
||||
|
||||
public float SpawnRateScale => _spawnScheduler?.SpawnRateScale ?? 1f;
|
||||
public float SpawnRateScale => _spawnScheduler.SpawnRateScale;
|
||||
public float BattleDuration => _duration;
|
||||
public float ElapsedBattleTime => _spawnScheduler?.ElapsedTime ?? 0f;
|
||||
public int CurrentEnemyCount => _enemyRegistry?.Count ?? 0;
|
||||
public float ElapsedBattleTime => _spawnScheduler.ElapsedTime;
|
||||
public int CurrentEnemyCount => _enemyRegistry.Count;
|
||||
|
||||
#region Lifecycle
|
||||
|
||||
@@ -71,9 +71,15 @@ namespace SepCore.EnemyManager
|
||||
|
||||
public void OnInit(LevelConfig level, Player player)
|
||||
{
|
||||
if (player == null)
|
||||
{
|
||||
Log.Error("Can not init enemy manager without a player.");
|
||||
return;
|
||||
}
|
||||
|
||||
_isStopped = false;
|
||||
|
||||
_player = player != null ? player.CachedTransform : null;
|
||||
_player = player.CachedTransform;
|
||||
_spawnPositionStrategy = new RandomCircleSpawnStrategy(_spawnDistanceFromPlayer);
|
||||
|
||||
_baseDuration = level.Duration;
|
||||
@@ -116,14 +122,13 @@ namespace SepCore.EnemyManager
|
||||
_currentLevel = 0;
|
||||
_baseDuration = 0;
|
||||
_duration = 0;
|
||||
_player = null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private async UniTaskVoid SpawnEnemyAsync(EnemyType enemyType)
|
||||
{
|
||||
if (_player == null) return;
|
||||
|
||||
if (_enemyRegistry.Count >= _spawnEnemyMaxCount) return;
|
||||
int entityId = _currentSpawnEnemyId++;
|
||||
|
||||
@@ -198,7 +203,7 @@ namespace SepCore.EnemyManager
|
||||
private void OnShowEntitySuccess(object sender, GameEventArgs e)
|
||||
{
|
||||
if (e is not ShowEntitySuccessEventArgs ne) return;
|
||||
if (ne.Entity.EntityGroup?.Name != EnemyGroupName)
|
||||
if (ne.Entity.EntityGroup.Name != EnemyGroupName)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ namespace SepCore.EnemyManager
|
||||
public class EnemyRegistry
|
||||
{
|
||||
private readonly Dictionary<int, EntityBase> _enemyById;
|
||||
// PruneInvalidEntries 由 OnUpdate 每帧调用,复用缓冲避免每帧分配。
|
||||
private readonly List<int> _pruneBuffer;
|
||||
|
||||
public int Count => _enemyById.Count;
|
||||
public IReadOnlyCollection<EntityBase> Enemies => _enemyById.Values;
|
||||
@@ -13,11 +15,11 @@ namespace SepCore.EnemyManager
|
||||
public EnemyRegistry()
|
||||
{
|
||||
_enemyById = new Dictionary<int, EntityBase>();
|
||||
_pruneBuffer = new List<int>();
|
||||
}
|
||||
|
||||
public void Register(EnemyBase enemy)
|
||||
{
|
||||
if (enemy == null) return;
|
||||
_enemyById[enemy.Id] = enemy;
|
||||
}
|
||||
|
||||
@@ -35,16 +37,16 @@ namespace SepCore.EnemyManager
|
||||
|
||||
public void PruneInvalidEntries()
|
||||
{
|
||||
var invalidIds = new List<int>();
|
||||
_pruneBuffer.Clear();
|
||||
foreach (var kvp in _enemyById)
|
||||
{
|
||||
if (kvp.Value == null || !kvp.Value.Available)
|
||||
{
|
||||
invalidIds.Add(kvp.Key);
|
||||
_pruneBuffer.Add(kvp.Key);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (int id in invalidIds)
|
||||
foreach (int id in _pruneBuffer)
|
||||
{
|
||||
_enemyById.Remove(id);
|
||||
}
|
||||
|
||||
+10
-5
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using SepCore.CustomUtility;
|
||||
using SepCore.Definition;
|
||||
using SepCore.Timer;
|
||||
using UnityGameFramework.Runtime;
|
||||
using UnityEngine;
|
||||
|
||||
namespace SepCore.EnemyManager
|
||||
@@ -20,7 +20,7 @@ namespace SepCore.EnemyManager
|
||||
|
||||
public float SpawnRateScale => _spawnRateScale;
|
||||
public float ElapsedTime => _elapsedTime;
|
||||
public int WaveCount => _enemyTypes?.Length ?? 0;
|
||||
public int WaveCount => _enemyTypes.Length;
|
||||
|
||||
public void Init(LevelConfig level, Action<EnemyType, int> onSpawn)
|
||||
{
|
||||
@@ -37,7 +37,7 @@ namespace SepCore.EnemyManager
|
||||
{
|
||||
var spawnConfig = level.EnemySpawnConfigs[i];
|
||||
_baseIntervals[i] = spawnConfig.Interval / 1000f;
|
||||
_enemyTypes[i] = EntityDataFactory.GetEnemyType(spawnConfig.EnemyName);
|
||||
_enemyTypes[i] = spawnConfig.EnemyType;
|
||||
_spawnCounts[i] = spawnConfig.EnemyCount;
|
||||
}
|
||||
|
||||
@@ -57,8 +57,13 @@ namespace SepCore.EnemyManager
|
||||
|
||||
public void SetSpawnRateScale(float scale)
|
||||
{
|
||||
if (_waveHandles == null)
|
||||
{
|
||||
Log.Error("Can not set spawn rate scale before scheduler init.");
|
||||
return;
|
||||
}
|
||||
|
||||
_spawnRateScale = Mathf.Max(MinSpawnRateScale, scale);
|
||||
if (_waveHandles == null) return;
|
||||
|
||||
for (int i = 0; i < _waveHandles.Length; i++)
|
||||
{
|
||||
@@ -81,7 +86,7 @@ namespace SepCore.EnemyManager
|
||||
|
||||
private void OnWaveTick(int waveIndex)
|
||||
{
|
||||
_onSpawn?.Invoke(_enemyTypes[waveIndex], _spawnCounts[waveIndex]);
|
||||
_onSpawn(_enemyTypes[waveIndex], _spawnCounts[waveIndex]);
|
||||
}
|
||||
|
||||
private static float GetScaledInterval(float baseInterval, float scale)
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace SepCore.CustomComponent
|
||||
{
|
||||
{
|
||||
typeof(EnemyConfig),
|
||||
StringAccessor(tables => key => tables.TbEnemyConfig.GetOrDefault(key),
|
||||
Accessor(tables => key => tables.TbEnemyConfig.GetOrDefault((EnemyType)key),
|
||||
tables => tables.TbEnemyConfig.DataList)
|
||||
},
|
||||
{
|
||||
@@ -124,7 +124,7 @@ namespace SepCore.CustomComponent
|
||||
},
|
||||
{
|
||||
typeof(WeaponConfig),
|
||||
Accessor(tables => id => tables.TbWeaponConfig.GetOrDefault(id),
|
||||
Accessor(tables => id => tables.TbWeaponConfig.GetOrDefault((WeaponType)id),
|
||||
tables => tables.TbWeaponConfig.DataList)
|
||||
},
|
||||
};
|
||||
|
||||
-1
@@ -1,7 +1,6 @@
|
||||
using SepCore.Event;
|
||||
using SepCore.Definition;
|
||||
using SepCore.Entity;
|
||||
using SepCore.Entity.Weapon;
|
||||
using UnityEngine;
|
||||
|
||||
namespace SepCore.Simulation
|
||||
|
||||
-1
@@ -1,5 +1,4 @@
|
||||
using SepCore.Entity;
|
||||
using SepCore.Entity.Weapon;
|
||||
using UnityEngine;
|
||||
|
||||
namespace SepCore.Simulation
|
||||
|
||||
-1
@@ -1,7 +1,6 @@
|
||||
using SepCore.Event;
|
||||
using SepCore.Entity;
|
||||
using SepCore.AsyncTask;
|
||||
using SepCore.Entity.Weapon;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using GameFramework.Event;
|
||||
using UnityEngine;
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3069a4f1cc8f5b84d98b3bf5745c6450
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,50 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using GameFramework.Resource;
|
||||
using SepCore.AsyncTask;
|
||||
using SepCore.CustomUtility;
|
||||
using SepCore.Definition;
|
||||
using UnityEngine;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace SepCore.SpriteCache
|
||||
{
|
||||
public class SpriteCacheComponent : GameFrameworkComponent
|
||||
{
|
||||
[SerializeField] private float _pixelsPerUnit = 100f;
|
||||
[SerializeField] private Vector2 _defaultPivot = new(0.5f, 0.5f);
|
||||
|
||||
private Dictionary<string, Sprite> _spriteCache;
|
||||
private ResourceComponent _resource;
|
||||
|
||||
void Start()
|
||||
{
|
||||
_spriteCache = new Dictionary<string, Sprite>();
|
||||
_resource = GameEntry.Resource;
|
||||
}
|
||||
|
||||
public async UniTask<Sprite> GetSprite(string assetName)
|
||||
{
|
||||
if (_spriteCache.TryGetValue(assetName, out var sprite))
|
||||
return sprite;
|
||||
|
||||
var texture = await _resource.LoadAssetAsync<Texture2D>(
|
||||
AssetUtility.GetUITextureIconAsset(assetName),
|
||||
Constant.AssetPriority.UIFormAsset);
|
||||
|
||||
var newSprite = Sprite.Create(
|
||||
texture,
|
||||
new Rect(0, 0, texture.width, texture.height),
|
||||
_defaultPivot,
|
||||
_pixelsPerUnit);
|
||||
_spriteCache.TryAdd(assetName, newSprite);
|
||||
return newSprite;
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
_spriteCache.Clear();
|
||||
_resource = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -53,7 +53,7 @@ public abstract class EnemyBase : TargetableObject
|
||||
{
|
||||
if (Random.value < _enemyData.DropPercent)
|
||||
{
|
||||
var data = new CoinData(_enemyData.DropCoin, GameEntry.Entity.NextId(), 10001)
|
||||
var data = new CoinData(_enemyData.DropCoin, GameEntry.Entity.NextId())
|
||||
{
|
||||
Position = this.CachedTransform.position
|
||||
};
|
||||
@@ -62,7 +62,7 @@ public abstract class EnemyBase : TargetableObject
|
||||
|
||||
if (Random.value < _enemyData.DropPercent)
|
||||
{
|
||||
var data = new ExpData(_enemyData.DropExp, GameEntry.Entity.NextId(), 10002)
|
||||
var data = new ExpData(_enemyData.DropExp, GameEntry.Entity.NextId())
|
||||
{
|
||||
Position = this.CachedTransform.position
|
||||
};
|
||||
+3
-4
@@ -4,7 +4,7 @@ using Cysharp.Threading.Tasks;
|
||||
using SepCore.Components;
|
||||
using SepCore.Event;
|
||||
using SepCore.Definition;
|
||||
using SepCore.Entity.Weapon;
|
||||
using SepCore.Entity;
|
||||
using SepCore.CustomUtility;
|
||||
using SepCore.AsyncTask;
|
||||
|
||||
@@ -164,9 +164,8 @@ namespace SepCore.Entity
|
||||
|
||||
// BackpackComponent
|
||||
Coin = role.Coin;
|
||||
_backpackComponent.OnInit(this, role.WeaponCapacity);
|
||||
AddWeaponAsync(EntityDataFactory.Create(GameEntry.Entity.NextId(),
|
||||
WeaponType.WeaponKnife, Id, _playerData.Camp)).Forget();
|
||||
_backpackComponent.OnInit(this);
|
||||
AddWeaponAsync(EntityDataFactory.Create(GameEntry.Entity.NextId(), WeaponType.Knife, Id, _playerData.Camp)).Forget();
|
||||
|
||||
// StatComponent
|
||||
if (role.Modifiers != null)
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
using GameFramework.ObjectPool;
|
||||
using UnityEngine;
|
||||
|
||||
namespace SepCore.Entity.Weapon
|
||||
namespace SepCore.Entity
|
||||
{
|
||||
public sealed class HandgunHitMarkerAttackEffect : IWeaponAttackEffect
|
||||
{
|
||||
+1
-1
@@ -2,7 +2,7 @@ using GameFramework;
|
||||
using GameFramework.ObjectPool;
|
||||
using UnityEngine;
|
||||
|
||||
namespace SepCore.Entity.Weapon
|
||||
namespace SepCore.Entity
|
||||
{
|
||||
public sealed class HandgunHitMarkerPoolObject : ObjectBase
|
||||
{
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
using GameFramework.ObjectPool;
|
||||
using UnityEngine;
|
||||
|
||||
namespace SepCore.Entity.Weapon
|
||||
namespace SepCore.Entity
|
||||
{
|
||||
public sealed class HandgunHitMarkerPooledInstance : MonoBehaviour
|
||||
{
|
||||
+2
-2
@@ -1,9 +1,9 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace SepCore.Entity.Weapon
|
||||
namespace SepCore.Entity
|
||||
{
|
||||
public interface IWeaponAttackEffect
|
||||
{
|
||||
void Play(WeaponBase weapon, Vector3 position, EntityBase target, float radius);
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace SepCore.Entity.Weapon
|
||||
namespace SepCore.Entity
|
||||
{
|
||||
public sealed class KnifeRangeAttackEffect : IWeaponAttackEffect
|
||||
{
|
||||
@@ -60,4 +60,4 @@ namespace SepCore.Entity.Weapon
|
||||
Object.Destroy(indicator, Mathf.Max(0.01f, _duration));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace SepCore.Entity.Weapon
|
||||
namespace SepCore.Entity
|
||||
{
|
||||
public sealed class LanceThrustAttackEffect : IWeaponAttackEffect
|
||||
{
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace SepCore.Entity.Weapon
|
||||
namespace SepCore.Entity
|
||||
{
|
||||
public sealed class LightningStrikeAttackEffect : IWeaponAttackEffect
|
||||
{
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace SepCore.Entity.Weapon
|
||||
namespace SepCore.Entity
|
||||
{
|
||||
public sealed class SlashSectorAttackEffect : IWeaponAttackEffect
|
||||
{
|
||||
@@ -83,4 +83,4 @@ namespace SepCore.Entity.Weapon
|
||||
UnityEngine.Object.Destroy(indicator, Mathf.Max(0.01f, _duration));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -2,7 +2,7 @@ using System.Collections.Generic;
|
||||
using SepCore.Components;
|
||||
using SepCore.CustomUtility;
|
||||
|
||||
namespace SepCore.Entity.Weapon
|
||||
namespace SepCore.Entity
|
||||
{
|
||||
public sealed class HighestHealthTargetSelector : ITargetSelector
|
||||
{
|
||||
+2
-2
@@ -1,9 +1,9 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SepCore.Entity.Weapon
|
||||
namespace SepCore.Entity
|
||||
{
|
||||
public interface ITargetSelector
|
||||
{
|
||||
EntityBase SelectTarget(WeaponBase weapon, IEnumerable<EntityBase> candidates, float maxSqrRange);
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -3,7 +3,7 @@ using SepCore.Components;
|
||||
using SepCore.Definition;
|
||||
using SepCore.CustomUtility;
|
||||
|
||||
namespace SepCore.Entity.Weapon
|
||||
namespace SepCore.Entity
|
||||
{
|
||||
public sealed class LowestHealthTargetSelector : ITargetSelector
|
||||
{
|
||||
+1
-1
@@ -2,7 +2,7 @@ using System.Collections.Generic;
|
||||
using SepCore.EnemyManager;
|
||||
using SepCore.CustomUtility;
|
||||
|
||||
namespace SepCore.Entity.Weapon
|
||||
namespace SepCore.Entity
|
||||
{
|
||||
public sealed class NearestTargetSelector : ITargetSelector
|
||||
{
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
namespace SepCore.Entity.Weapon
|
||||
namespace SepCore.Entity
|
||||
{
|
||||
public enum TargetSelectorType
|
||||
{
|
||||
+1
-1
@@ -8,7 +8,7 @@ using SepCore.Timer;
|
||||
using UnityEngine;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace SepCore.Entity.Weapon
|
||||
namespace SepCore.Entity
|
||||
{
|
||||
public enum WeaponStateType
|
||||
{
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
namespace SepCore.Entity.Weapon
|
||||
namespace SepCore.Entity
|
||||
{
|
||||
public partial class WeaponHandgun
|
||||
{
|
||||
@@ -22,4 +22,4 @@ namespace SepCore.Entity.Weapon
|
||||
public override void OnLeave() { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
namespace SepCore.Entity.Weapon
|
||||
namespace SepCore.Entity
|
||||
{
|
||||
public partial class WeaponHandgun
|
||||
{
|
||||
@@ -42,4 +42,4 @@ namespace SepCore.Entity.Weapon
|
||||
public override void OnLeave() { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
namespace SepCore.Entity.Weapon
|
||||
namespace SepCore.Entity
|
||||
{
|
||||
public partial class WeaponHandgun
|
||||
{
|
||||
@@ -29,4 +29,4 @@ namespace SepCore.Entity.Weapon
|
||||
public override void OnLeave() { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
namespace SepCore.Entity.Weapon
|
||||
namespace SepCore.Entity
|
||||
{
|
||||
public partial class WeaponHandgun
|
||||
{
|
||||
@@ -23,4 +23,4 @@ namespace SepCore.Entity.Weapon
|
||||
public override void OnLeave() { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-2
@@ -1,10 +1,9 @@
|
||||
using SepCore.Definition;
|
||||
using SepCore.Entity;
|
||||
using SepCore.CustomUtility;
|
||||
using UnityEngine;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace SepCore.Entity.Weapon
|
||||
namespace SepCore.Entity
|
||||
{
|
||||
public partial class WeaponHandgun : WeaponBase
|
||||
{
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
namespace SepCore.Entity.Weapon
|
||||
namespace SepCore.Entity
|
||||
{
|
||||
public partial class WeaponKnife
|
||||
{
|
||||
@@ -28,4 +28,4 @@ namespace SepCore.Entity.Weapon
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
namespace SepCore.Entity.Weapon
|
||||
namespace SepCore.Entity
|
||||
{
|
||||
public partial class WeaponKnife
|
||||
{
|
||||
@@ -45,4 +45,4 @@ namespace SepCore.Entity.Weapon
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
namespace SepCore.Entity.Weapon
|
||||
namespace SepCore.Entity
|
||||
{
|
||||
public partial class WeaponKnife
|
||||
{
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
namespace SepCore.Entity.Weapon
|
||||
namespace SepCore.Entity
|
||||
{
|
||||
public partial class WeaponKnife
|
||||
{
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user