Files
Gen_Hack-and-Slash-Roguelite/Client/Assets/Scripts/Utils/StringUtils.cs

214 lines
9.8 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 文件: Assets/Scripts/Utils/StringUtils.cs (或你的实际路径)
using System;
using System.Reflection;
using Map;
namespace Utils
{
using UnityEngine; // 引入Unity命名空间以便使用Vector2和Vector3
public static class StringUtils
{
/// <summary>
/// 尝试从字符串中解析出指定数量的浮点数组件。
/// 这是StringToVector2和StringToVector3的核心辅助方法。
/// </summary>
/// <param name="source">要解析的源字符串。</param>
/// <param name="expectedComponentCount">期望的组件数量例如Vector2为2Vector3为3。</param>
/// <param name="parsedComponents">如果解析成功,包含解析出的浮点数;否则为 null。</param>
/// <param name="defaultComponentValue">在解析失败时用于填充parsedComponents数组的默认值。</param>
/// <returns>如果所有组件都成功解析,则返回 true否则返回 false。</returns>
private static bool TryParseVectorComponents(
string source,
int expectedComponentCount,
out float[] parsedComponents,
float defaultComponentValue = 0f)
{
parsedComponents = new float[expectedComponentCount];
if (string.IsNullOrWhiteSpace(source))
{
// 如果字符串为空或空白,则用默认值填充并失败
for (int i = 0; i < expectedComponentCount; i++)
{
parsedComponents[i] = defaultComponentValue;
}
return false;
}
// 移除所有可能存在的括号或方括号
// 采用Replace而不是Regex是因为简单字符替换的性能优势
string cleanedSource = source
.Replace("[", "")
.Replace("]", "")
.Replace("(", "")
.Replace(")", "");
// 定义所有可能的分隔符:逗号、空格、分号
// 使用 StringSplitOptions.RemoveEmptyEntries 确保即使有多个分隔符连续出现,也不会创建空字符串项
char[] delimiters = { ',', ' ', ';' };
string[] componentStrings = cleanedSource.Split(
delimiters,
System.StringSplitOptions.RemoveEmptyEntries);
if (componentStrings.Length < expectedComponentCount)
{
// 如果组件数量不足,则用默认值填充并失败
for (int i = 0; i < expectedComponentCount; i++)
{
parsedComponents[i] = defaultComponentValue;
}
return false;
}
for (int i = 0; i < expectedComponentCount; i++)
{
// 尝试解析每个组件,并去除前后空格
if (!float.TryParse(componentStrings[i].Trim(), out parsedComponents[i]))
{
// 如果任何一个组件解析失败,则用默认值填充所有组件并返回 false
for (int j = 0; j < expectedComponentCount; j++)
{
parsedComponents[j] = defaultComponentValue;
}
return false;
}
}
return true; // 所有组件都成功解析
}
/// <summary>
/// 将字符串转换为 Unity 的 Vector2。
/// 支持格式如 "1,2", "[1 2]", "(1;2)",并能处理空格。
/// </summary>
/// <param name="str">要转换的字符串。</param>
/// <param name="defaultValue">转换失败时返回的默认 Vector2 值。</param>
/// <returns>转换后的 Vector2 值或默认值。</returns>
public static Vector2 StringToVector2(string str, Vector2 defaultValue = default)
{
if (defaultValue == default)
{
defaultValue = Vector2.zero; // 如果未指定,则使用 Vector2.zero 作为默认值
}
// 默认浮点值为0f用于内部解析失败填充
if (TryParseVectorComponents(str, 2, out var components))
{
return new Vector2(components[0], components[1]);
}
return defaultValue;
}
/// <summary>
/// 将字符串转换为 Unity 的 Vector3。
/// 支持格式如 "1,2,3", "[1 2 3]", "(1;2;3)",并能处理空格。
/// </summary>
/// <param name="str">要转换的字符串。</param>
/// <param name="defaultValue">转换失败时返回的默认 Vector3 值。</param>
/// <returns>转换后的 Vector3 值或默认值。</returns>
public static Vector3 StringToVector3(string str, Vector3 defaultValue = default)
{
if (defaultValue == default)
{
defaultValue = Vector3.zero; // 如果未指定,则使用 Vector3.zero 作为默认值
}
// 默认浮点值为0f用于内部解析失败填充
if (TryParseVectorComponents(str, 3, out var components))
{
return new Vector3(components[0], components[1], components[2]);
}
return defaultValue;
}
/// <summary>
/// 根据类名字符串创建并返回一个继承自 MapGeneratorWorkClassBase 的实例。
/// </summary>
/// <param name="className">不含命名空间的类名。</param>
/// <returns>对应的 MapGeneratorWorkClassBase 实例,如果找不到或类型不匹配则返回 null。</returns>
public static MapGeneratorWorkClassBase CreateMapGeneratorInstance(string className)
{
// 定义优先查找的命名空间
const string preferredNamespace = "Map";
Type foundType = null;
// 第一遍:优先在指定的命名空间下查找
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
{
string fullClassNameInPreferredNamespace = preferredNamespace + "." + className;
Type type = assembly.GetType(fullClassNameInPreferredNamespace);
if (type != null)
{
foundType = type;
break; // 找到后立即退出循环,因为我们找到了优先的类型
}
}
// 如果在优先命名空间中没有找到则进行第二遍在所有命名空间中查找不指定命名空间即只用className
if (foundType == null)
{
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
{
Type type = assembly.GetType(className);
if (type != null)
{
// 如果找到多个同名的类型在不同命名空间但都不在preferredNamespace
// 这里的处理是取第一个找到的。如果需要更复杂的选择逻辑,例如按顺序优先级,
// 则需要收集所有可能类型并进行筛选。
// 但对于通常的应用如果className本身是不带命名空间的这通常意味着它在全局作用域
// 或者我们期望它在一个特定的命名空间如preferredNamespace中。
foundType = type;
// 注意这里没有break;的话如果不同程序集有同名类会继续查找并覆盖foundType。
// 如果你期望找到第一个就返回可以加上break;
// 如果你期望找到一个满足条件的就返回,那么把后续的检查放到这里。
// 为了简化我们只在这里找到一个可用的Type然后统一在后面检查。
break; // 找到了一个,先用这个。
}
}
}
// 对找到的类型进行有效性检查和实例创建
if (foundType != null)
{
// 检查类型是否:
// 1. 是 MapGeneratorWorkClassBase 的子类或本身就是 MapGeneratorWorkClassBase
// 2. 不是抽象类
// 3. 有一个无参构造函数
if (typeof(MapGeneratorWorkClassBase).IsAssignableFrom(foundType) &&
!foundType.IsAbstract &&
foundType.GetConstructor(Type.EmptyTypes) != null) // 检查是否有无参构造函数
{
try
{
// 使用 Activator.CreateInstance 创建实例
return (MapGeneratorWorkClassBase)Activator.CreateInstance(foundType);
}
catch (Exception ex)
{
Debug.LogError($"Error creating instance of {foundType.FullName}: {ex.Message}");
return null;
}
}
string foundTypeName = foundType.FullName;
Debug.LogError($"Type '{foundTypeName}' found but does not meet criteria:" +
$" IsAssignableFrom({nameof(MapGeneratorWorkClassBase)}): {typeof(MapGeneratorWorkClassBase).IsAssignableFrom(foundType)}," +
$" IsAbstract: {foundType.IsAbstract}," +
$" HasParameterlessConstructor: {foundType.GetConstructor(Type.EmptyTypes) != null}");
return null; // 类型不满足条件
}
Debug.LogError(
$"Type '{className}' not found in preferred namespace '{preferredNamespace}' or any loaded assembly.");
return null; // 类型未找到
}
}
}