(client) fix:修复DefineManager没有解析数组类型的Define字段导致定义查找失败

This commit is contained in:
m0_75251201
2025-07-25 17:27:08 +08:00
parent c4ddc0d693
commit bbe4955ccf
9 changed files with 194 additions and 65 deletions

View File

@ -686,7 +686,7 @@ MonoBehaviour:
isGlobal: 1
entityLevel: {fileID: 309861628}
entityPrefab: {fileID: 3332598847335032684, guid: 6cd8b01a0f57372438dc30c864ae1530, type: 3}
defaultEntityPrefab: {fileID: 0}
defaultEntityPrefab: {fileID: 7975757421877276383, guid: 89661daa5f100c64783f0ad9cd37a7ff, type: 3}
--- !u!114 &2036983434
MonoBehaviour:
m_ObjectHideFlags: 0

View File

@ -87,7 +87,7 @@ namespace Data
position = StringToVector(xmlDef.Attribute("position")?.Value ?? "(0 0)");
FPS = float.TryParse(xmlDef.Attribute("FPS")?.Value, out float result) ? result : 1.0f;
foreach (var childNode in xmlDef.Elements("DrawNodeDef"))
foreach (var childNode in xmlDef.Elements())
{
var child = new DrawNodeDef();
child.Init(childNode);

View File

@ -53,7 +53,6 @@ namespace Entity
aiTree = ConvertToAIBase(pawnDef.behaviorTree);
affiliation = pawnDef.affiliation;
InitBody(pawnDef.drawingOrder);
}
public virtual void InitBody(DrawingOrderDef drawingOrder)
@ -71,8 +70,7 @@ namespace Entity
if (drawNode == null) continue;
var directionRoot = new GameObject(orientation.ToString());
directionRoot.transform.SetParent(body.transform, false);
InitBodyPart(drawNode, directionRoot);
InitBodyPart(drawNode, directionRoot,drawingOrder.texturePath);
bodyNodes[orientation] = directionRoot;
}
currentOrientation = Orientation.Down;
@ -85,31 +83,50 @@ namespace Entity
}
// 递归初始化单个绘图节点及其子节点
public virtual void InitBodyPart(DrawNodeDef drawNode, GameObject parent)
public virtual void InitBodyPart(DrawNodeDef drawNode, GameObject parent,string folderPath)
{
if(drawNode==null) return;
GameObject nodeObject;
switch (drawNode.drawNodeType)
if (drawNode.nodeName == "noName")
{
case DrawNodeType.Image:
nodeObject = Instantiate(imagePrefab.gameObject,parent.transform);
break;
nodeObject = new();
nodeObject.transform.SetParent(parent.transform);
}
else
{
switch (drawNode.drawNodeType)
{
case DrawNodeType.Image:
nodeObject = Instantiate(imagePrefab.gameObject, parent.transform);
var texture =
Managers.PackagesImageManager.Instance.FindBodyTextures(drawNode.packID, folderPath,
$"{drawNode.nodeName}_{currentOrientation}");
var image = nodeObject.GetComponent<ImagePrefab>();
image.SetSprite(texture[0]);
break;
case DrawNodeType.Animation:
nodeObject = Instantiate(animatorPrefab.gameObject,parent.transform);
ITick tick = nodeObject.GetComponent<SpriteAnimator>();
if (tick != null)
bodyAnimationNode[currentOrientation].Add(tick);
break;
default:
throw new ArgumentOutOfRangeException();
case DrawNodeType.Animation:
nodeObject = Instantiate(animatorPrefab.gameObject, parent.transform);
ITick tick = nodeObject.GetComponent<SpriteAnimator>();
if (tick != null)
bodyAnimationNode[currentOrientation].Add(tick);
var textures = Managers.PackagesImageManager.Instance.FindBodyTextures(drawNode.packID,
folderPath,
$"{drawNode.nodeName}_{currentOrientation}");
var animator = nodeObject.GetComponent<SpriteAnimator>();
animator.SetSprites(textures);
break;
default:
throw new ArgumentOutOfRangeException();
}
}
nodeObject.transform.localPosition = drawNode.position;
nodeObject.name = drawNode.nodeName;
// 递归初始化子节点
foreach (var child in drawNode.children)
{
InitBodyPart(child, nodeObject);
InitBodyPart(child, nodeObject,folderPath);
}
}
public void Tick()

View File

@ -1,4 +1,5 @@
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
@ -51,46 +52,93 @@ namespace Managers
string currentPackID = string.Empty;
void ProcessDefine(Define def)
{
if (def == null || def.isReferene)
return;
def.packID = currentPackID;
// 如果字段信息已经缓存,则直接使用缓存
if (!fieldCache.TryGetValue(def.GetType(), out var defineFields))
{
// 获取所有字段类型为 Define 或其派生类型的字段
defineFields = def.GetType()
.GetFields(BindingFlags.Public | BindingFlags.Instance)
.Where(field => typeof(Define).IsAssignableFrom(field.FieldType))
.ToArray();
.ToArray(); // 不再过滤,先获取所有字段
// 缓存字段信息
fieldCache[def.GetType()] = defineFields;
}
foreach (var defineField in defineFields)
{
var defRef = (Define)defineField.GetValue(def);
if (defRef == null)
continue;
if (defRef.isReferene)
var fieldType = defineField.FieldType;
// 处理单个 Define 类型的字段
if (typeof(Define).IsAssignableFrom(fieldType))
{
defineCache.Add(new Tuple<Define, FieldInfo, Define>(def, defineField, defRef));
}
else
{
if (string.IsNullOrEmpty(defRef.defName))
var defRef = (Define)defineField.GetValue(def);
if (defRef == null)
continue;
if (defRef.isReferene)
{
var typeName = defRef.GetType().Name;
if (!anonymousDefines.ContainsKey(typeName))
anonymousDefines.Add(typeName, new List<Define>());
anonymousDefines[typeName].Add(defRef);
defineCache.Add(new Tuple<Define, FieldInfo, Define>(def, defineField, defRef));
}
else
{
if (string.IsNullOrEmpty(defRef.defName))
{
var typeName = defRef.GetType().Name;
if (!anonymousDefines.ContainsKey(typeName))
anonymousDefines.Add(typeName, new List<Define>());
anonymousDefines[typeName].Add(defRef);
}
ProcessDefine(defRef);
}
}
// 处理集合类型字段
else if (fieldType.IsGenericType && fieldType.GetGenericTypeDefinition() == typeof(List<>))
{
var elementType = fieldType.GenericTypeArguments[0];
if (typeof(Define).IsAssignableFrom(elementType))
{
var list = (IList)defineField.GetValue(def);
if (list != null)
{
foreach (var item in list)
{
if (item is Define defItem && !defItem.isReferene)
{
ProcessDefine(defItem);
}
}
}
}
}
// 处理数组类型字段
else if (fieldType.IsArray)
{
var elementType = fieldType.GetElementType();
if (typeof(Define).IsAssignableFrom(elementType))
{
var array = (Array)defineField.GetValue(def);
if (array != null)
{
foreach (var item in array)
{
if (item is Define defItem && !defItem.isReferene)
{
ProcessDefine(defItem);
}
}
}
}
ProcessDefine(defRef);
}
}
}
foreach (var pack in packs)
{
currentPackID = pack.Value.packID;
@ -380,4 +428,5 @@ namespace Managers
return result.ToString();
}
}
}
}

View File

@ -101,7 +101,7 @@ namespace Managers
catch (System.Exception ex)
{
// 捕获并记录任何异常
Debug.LogError($"An error occurred while generating the entity: {ex.Message}");
Debug.LogError($"An error occurred while generating the entity: {ex.Message}\nStack Trace: {ex.StackTrace}");
GenerateDefaultEntity(pos);
}
}

View File

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Data;
using NUnit.Framework;
using UnityEngine;
@ -15,7 +16,7 @@ namespace Managers
//包名,图片名
public Dictionary<string, Dictionary<string, Sprite>> sprites = new();
//包名,文件路径,身体部件名
public Dictionary<string, Dictionary<string, Dictionary<string, List<Sprite>>>> bodyTexture = new();
public Dictionary<string, Dictionary<string, Dictionary<string, Sprite>>> bodyTexture = new();
public void Init()
{
@ -83,7 +84,8 @@ namespace Managers
new Vector2(0.5f, 0.5f) // 中心点
);
var name=Path.GetFileNameWithoutExtension(path);
InsertBodySprite(drawOrder.packID, drawOrder.texturePath, name, spr);
InsertBodyTexture(drawOrder.packID, drawOrder.texturePath, name, spr);
}
}
}
@ -115,7 +117,7 @@ namespace Managers
if (!sprites.ContainsKey(packId))
sprites[packId] = new Dictionary<string, Sprite>();
Rect spriteRect = new Rect(0, 0, textureWidth, textureHeight);
var spriteRect = new Rect(0, 0, textureWidth, textureHeight);
var sprite = Sprite.Create(texture, spriteRect, new Vector2(0.5f, 0.5f), pixelsPerUnit);
sprites[packId][baseName] = sprite;
return;
@ -180,34 +182,95 @@ namespace Managers
return GetSprite(packID, fullName);
}
/// <summary>
/// 插入 Sprite 到指定的嵌套字典中
/// 向 bodyTexture 插入一张 Sprite
/// 如果包名、路径或部件名原本不存在,会自动建立对应的 Dictionary。
/// </summary>
/// <param name="packageName">包名</param>
/// <param name="filePath">文件路径</param>
/// <param name="bodyPartName">身体部件名</param>
/// <param name="sprite">要插入的 Sprite 对象。</param>
public void InsertBodySprite(string packageName, string filePath, string bodyPartName, Sprite sprite)
/// <param name="packageName">包名</param>
/// <param name="filePath">文件路径</param>
/// <param name="bodyPartName">身体部件名</param>
/// <param name="sprite">要插入的 Sprite</param>
public void InsertBodyTexture(string packageName,
string filePath,
string bodyPartName,
Sprite sprite)
{
// 确保第一层字典(包名)存在
if (!bodyTexture.ContainsKey(packageName))
if (sprite == null)
{
bodyTexture[packageName] = new Dictionary<string, Dictionary<string, List<Sprite>>>();
Debug.LogWarning("InsertBodyTexture: sprite 为 null已忽略。");
return;
}
// 确保第二层字典(文件路径)存在
if (!bodyTexture[packageName].ContainsKey(filePath))
// 1) 处理包名层级
if (!bodyTexture.TryGetValue(packageName, out var pathDict))
{
bodyTexture[packageName][filePath] = new Dictionary<string, List<Sprite>>();
pathDict = new Dictionary<string, Dictionary<string, Sprite>>();
bodyTexture[packageName] = pathDict;
}
// 确保第三层字典(身体部件名)存在
if (!bodyTexture[packageName][filePath].ContainsKey(bodyPartName))
// 2) 处理文件路径层级
if (!pathDict.TryGetValue(filePath, out var partDict))
{
bodyTexture[packageName][filePath][bodyPartName] = new List<Sprite>();
partDict = new Dictionary<string, Sprite>();
pathDict[filePath] = partDict;
}
// 将 Sprite 添加到列表中
bodyTexture[packageName][filePath][bodyPartName].Add(sprite);
// 3) 插入或覆盖部件名
partDict[bodyPartName] = sprite;
}
/// <summary>
/// 查找身体部件的所有Sprite变体支持带编号的图片
/// </summary>
/// <param name="packageName">包名</param>
/// <param name="filePath">文件路径</param>
/// <param name="bodyPartName">身体部件名</param>
/// <returns>按编号排序的Sprite数组未找到时返回空数组</returns>
public Sprite[] FindBodyTextures(string packageName, string filePath, string bodyPartName)
{
// 检查包名是否存在
if (!bodyTexture.TryGetValue(packageName, out var packageDict))
{
Debug.LogWarning($"Package '{packageName}' not found.");
return Array.Empty<Sprite>();
}
// 检查文件路径是否存在
if (!packageDict.TryGetValue(filePath, out var pathDict))
{
Debug.LogWarning($"File path '{filePath}' not found in package '{packageName}'.");
return Array.Empty<Sprite>();
}
// 收集所有匹配的Sprite
var sprites = new List<(int order, Sprite sprite)>();
// 查找完全匹配的项(无编号)
if (pathDict.TryGetValue(bodyPartName, out var baseSprite))
{
sprites.Add((0, baseSprite));
}
// 查找带编号的变体
var prefix = bodyPartName + "_";
foreach (var (key, value) in pathDict)
{
// 检查是否以部件名+下划线开头
if (key.StartsWith(prefix) && key.Length > prefix.Length)
{
var suffix = key.Substring(prefix.Length);
// 尝试解析编号
if (int.TryParse(suffix, out var number))
{
sprites.Add((number, Value: value));
}
}
}
// 按编号排序无编号视为0
return sprites
.OrderBy(x => x.order)
.Select(x => x.sprite)
.ToArray();
}
}
}

File diff suppressed because one or more lines are too long

View File

@ -14,9 +14,9 @@
<attributes>TestCharacter</attributes>
<affiliation>player</affiliation>
<drawingOrder>
<texturePath>Resources/Character/CatGirl</texturePath>
<texturePath>Resources\Character\Test</texturePath>
<drawingOrder_down>
<node name="body"/>
<node name="Body"/>
</drawingOrder_down>
</drawingOrder>
<behaviorTree>