(client) feat:健康给予,路径优化,结算界面,商店界面 (#60)

Co-authored-by: m0_75251201 <m0_75251201@noreply.gitcode.com>
Reviewed-on: http://47.107.252.169:3000/Roguelite-Game-Developing-Team/Gen_Hack-and-Slash-Roguelite/pulls/60
This commit is contained in:
2025-10-10 14:08:23 +08:00
parent 9a797479ff
commit 16b49f3d3a
1900 changed files with 114053 additions and 34157 deletions

View File

@@ -10,13 +10,13 @@ namespace Parsing
public static class ConditionDelegateFactory
{
// 正则表达式用于解析函数名和参数
private static readonly Regex _methodCallRegex = new Regex(
private static readonly Regex _methodCallRegex = new(
@"^(?<methodName>[a-zA-Z_][a-zA-Z0-9_]*)(?:\((?<args>.*)\))?$",
RegexOptions.Compiled
);
/// <summary>
/// 解析条件字符串并创建 Func<Entity.Entity, bool> 委托。
/// 解析条件字符串并创建 Func<Entity.Entity, bool> 委托。
/// </summary>
/// <param name="conditionString">条件字符串,如 "EntityHealth(20)" 或 "IsTargetAlive"。</param>
/// <param name="entityType">实体类型,通常是 typeof(Entity.Entity)。</param>
@@ -38,10 +38,8 @@ namespace Parsing
var match = _methodCallRegex.Match(conditionString);
if (!match.Success)
{
throw new ArgumentException(
$"条件字符串 '{conditionString}' 格式不正确。期望格式: MethodName 或 MethodName(arg1, arg2)。");
}
var methodName = match.Groups["methodName"].Value;
var argsString = match.Groups["args"].Success ? match.Groups["args"].Value : null;
@@ -146,47 +144,37 @@ namespace Parsing
// 如果没有额外参数,直接创建委托以获得最佳性能
if (parsedArgValues.Count == 0)
{
return (Func<Entity.Entity, bool>)Delegate.CreateDelegate(typeof(Func<Entity.Entity, bool>),
bestMatchMethod);
}
else
{
// 创建一个闭包来绑定解析后的参数
// 闭包捕获 finalInvokeArgs并在运行时填充第一个参数 (entity)
return (entity) =>
{
// 复制一份 finalInvokeArgs因为 Invoke 会修改数组内容(如果参数是 ref/out
// 并且需要将 entity 放入第一个位置
var invokeArgs = new object[finalInvokeArgs.Length];
invokeArgs[0] = entity;
for (var i = 1; i < finalInvokeArgs.Length; i++)
{
invokeArgs[i] = finalInvokeArgs[i];
}
return (bool)bestMatchMethod.Invoke(null, invokeArgs);
};
}
// 创建一个闭包来绑定解析后的参数
// 闭包捕获 finalInvokeArgs并在运行时填充第一个参数 (entity)
return entity =>
{
// 复制一份 finalInvokeArgs因为 Invoke 会修改数组内容(如果参数是 ref/out
// 并且需要将 entity 放入第一个位置
var invokeArgs = new object[finalInvokeArgs.Length];
invokeArgs[0] = entity;
for (var i = 1; i < finalInvokeArgs.Length; i++) invokeArgs[i] = finalInvokeArgs[i];
return (bool)bestMatchMethod.Invoke(null, invokeArgs);
};
}
/// <summary>
/// 辅助方法:拆分参数字符串。
/// 这是一个更健壮的实现,能够正确处理包含逗号的带引号字符串和嵌套括号。
/// 辅助方法:拆分参数字符串。
/// 这是一个更健壮的实现,能够正确处理包含逗号的带引号字符串和嵌套括号。
/// </summary>
/// <param name="argsString">待拆分的参数字符串。</param>
/// <returns>拆分后的参数列表。</returns>
private static IEnumerable<string> SplitArguments(string argsString)
{
if (string.IsNullOrEmpty(argsString))
{
return Enumerable.Empty<string>();
}
if (string.IsNullOrEmpty(argsString)) return Enumerable.Empty<string>();
var arguments = new List<string>();
var currentArgument = new StringBuilder();
var inQuote = false; // 跟踪是否在双引号内部
var parenLevel = 0; // 跟踪括号的嵌套层级
var parenLevel = 0; // 跟踪括号的嵌套层级
for (var i = 0; i < argsString.Length; i++)
{
@@ -211,10 +199,7 @@ namespace Parsing
{
// 发现一个顶级的逗号分隔符:不在引号内,也不在任何括号内
var arg = currentArgument.ToString().Trim();
if (!string.IsNullOrEmpty(arg))
{
arguments.Add(arg);
}
if (!string.IsNullOrEmpty(arg)) arguments.Add(arg);
currentArgument.Clear(); // 重置,开始收集下一个参数
}
else
@@ -226,21 +211,18 @@ namespace Parsing
// 循环结束后,添加最后一个参数(如果有的话)
var lastArg = currentArgument.ToString().Trim();
if (!string.IsNullOrEmpty(lastArg))
{
arguments.Add(lastArg);
}
if (!string.IsNullOrEmpty(lastArg)) arguments.Add(lastArg);
return arguments;
}
/// <summary>
/// 辅助方法:检查一个值是否可以转换为目标类型。
/// 辅助方法:检查一个值是否可以转换为目标类型。
/// </summary>
private static bool CanConvert(object value, Type targetType)
{
// 逻辑修改:新增辅助方法,用于检查类型转换可行性
if (value == null) return !targetType.IsValueType || (Nullable.GetUnderlyingType(targetType) != null);
if (value == null) return !targetType.IsValueType || Nullable.GetUnderlyingType(targetType) != null;
if (targetType.IsInstanceOfType(value)) return true;
try
@@ -256,8 +238,8 @@ namespace Parsing
}
/// <summary>
/// 解析字符串字面量为对应的对象和类型。
/// 支持 int, long, float, double, bool, string。
/// 解析字符串字面量为对应的对象和类型。
/// 支持 int, long, float, double, bool, string。
/// </summary>
/// <param name="literalString">要解析的字面量字符串。</param>
/// <returns>包含解析后的值和类型的元组。</returns>
@@ -267,40 +249,23 @@ namespace Parsing
// 顺序很重要:先尝试更窄的类型,再尝试更宽的类型,以避免不必要的类型提升。
// 尝试解析为 int
if (int.TryParse(literalString, out var intValue))
{
return (intValue, typeof(int));
}
if (int.TryParse(literalString, out var intValue)) return (intValue, typeof(int));
// 尝试解析为 long
if (long.TryParse(literalString, out var longValue))
{
return (longValue, typeof(long));
}
if (long.TryParse(literalString, out var longValue)) return (longValue, typeof(long));
// 尝试解析为 float
if (float.TryParse(literalString, out var floatValue))
{
return (floatValue, typeof(float));
}
if (float.TryParse(literalString, out var floatValue)) return (floatValue, typeof(float));
// 尝试解析为 double
if (double.TryParse(literalString, out var doubleValue))
{
return (doubleValue, typeof(double));
}
if (double.TryParse(literalString, out var doubleValue)) return (doubleValue, typeof(double));
// 尝试解析为 bool
if (bool.TryParse(literalString, out var boolValue))
{
return (boolValue, typeof(bool));
}
if (bool.TryParse(literalString, out var boolValue)) return (boolValue, typeof(bool));
// 尝试解析为 string (如果被双引号包围)
if (literalString.StartsWith("\"") && literalString.EndsWith("\"") && literalString.Length > 1)
{
return (literalString.Substring(1, literalString.Length - 2), typeof(string));
}
// 默认作为字符串处理
return (literalString, typeof(string));