This commit is contained in:
2025-12-12 22:42:10 +08:00
8 changed files with 903 additions and 10 deletions

View File

@@ -0,0 +1,536 @@
using System;
using RimWorld.QuestGen;
using Verse;
using System.Collections.Generic;
using System.Linq;
namespace WulaFallenEmpire
{
public class QuestNode_WriteToEventVariablesWithAdd : QuestNode
{
// 要写入的变量名在EventVariableManager中的名字
[NoTranslate]
public SlateRef<string> targetVariableName;
// 要从Quest中读取的变量名Slate中的变量
[NoTranslate]
public SlateRef<string> sourceVariableName;
// 如果sourceVariableName为空使用这个值
public SlateRef<object> value;
// 写入模式
public WriteMode writeMode = WriteMode.Set;
// 是否检查变量已存在
public SlateRef<bool> checkExisting = true;
// 如果变量已存在是否覆盖仅用于Set模式
public SlateRef<bool> overwrite = false;
// 操作符用于Add和Multiply模式
public MathOperator mathOperator = MathOperator.Add;
// 是否强制转换类型(当类型不匹配时)
public SlateRef<bool> forceTypeConversion = false;
// 当类型不匹配且无法转换时的行为
public TypeMismatchBehavior onTypeMismatch = TypeMismatchBehavior.ConvertToString;
// 写入后是否从Slate中删除源变量
public SlateRef<bool> removeFromSlate = false;
// 是否记录调试信息
public SlateRef<bool> logDebug = false;
// 允许操作的数值类型
public List<Type> allowedNumericTypes = new List<Type>
{
typeof(int),
typeof(float),
typeof(double),
typeof(long),
typeof(short),
typeof(decimal)
};
public enum WriteMode
{
Set, // 直接设置值(覆盖)
Add, // 相加(仅对数值类型)
Multiply, // 相乘(仅对数值类型)
Append, // 追加(字符串、列表等)
Min, // 取最小值(仅对数值类型)
Max, // 取最大值(仅对数值类型)
Increment // 自增1仅对数值类型忽略源值
}
public enum MathOperator
{
Add, // 加法
Subtract, // 减法
Multiply, // 乘法
Divide // 除法
}
public enum TypeMismatchBehavior
{
ThrowError, // 抛出错误
Skip, // 跳过操作
ConvertToString,// 转换为字符串
UseDefault // 使用默认值
}
protected override bool TestRunInt(Slate slate)
{
return RunInternal(slate, isTestRun: true);
}
protected override void RunInt()
{
RunInternal(QuestGen.slate, isTestRun: false);
}
private bool RunInternal(Slate slate, bool isTestRun)
{
// 获取目标变量名
string targetName = targetVariableName.GetValue(slate);
if (string.IsNullOrEmpty(targetName))
{
Log.Error("[QuestNode_WriteToEventVariablesWithAdd] targetVariableName is null or empty!");
return false;
}
// 获取要操作的值
object sourceValue = GetSourceValue(slate);
if (sourceValue == null && writeMode != WriteMode.Increment)
{
if (logDebug.GetValue(slate))
{
Log.Warning($"[QuestNode_WriteToEventVariablesWithAdd] No value to operate for variable '{targetName}'.");
}
return false;
}
// 在测试运行时不需要实际写入
if (isTestRun)
{
return true;
}
// 获取EventVariableManager
var eventVarManager = Find.World.GetComponent<EventVariableManager>();
if (eventVarManager == null)
{
Log.Error("[QuestNode_WriteToEventVariablesWithAdd] EventVariableManager not found!");
return false;
}
bool variableExists = eventVarManager.HasVariable(targetName);
object currentValue = variableExists ? eventVarManager.GetVariable<object>(targetName) : null;
// 记录操作前的状态
if (logDebug.GetValue(slate))
{
Log.Message($"[QuestNode_WriteToEventVariablesWithAdd] Operation for variable '{targetName}':");
Log.Message($" - Mode: {writeMode}");
Log.Message($" - Current value: {currentValue ?? "[null]"} (Type: {currentValue?.GetType().Name ?? "null"})");
Log.Message($" - Source value: {sourceValue ?? "[null]"} (Type: {sourceValue?.GetType().Name ?? "null"})");
}
// 根据写入模式计算新值
object newValue = CalculateNewValue(currentValue, sourceValue, slate);
// 如果新值为null可能是由于类型不匹配被跳过了
if (newValue == null)
{
if (logDebug.GetValue(slate))
{
Log.Message($" - Operation skipped (new value is null)");
}
return false;
}
// 写入变量
eventVarManager.SetVariable(targetName, newValue);
// 写入后从Slate中删除源变量
if (removeFromSlate.GetValue(slate) && !string.IsNullOrEmpty(sourceVariableName.GetValue(slate)))
{
slate.Remove(sourceVariableName.GetValue(slate));
if (logDebug.GetValue(slate))
{
Log.Message($" - Removed source variable '{sourceVariableName.GetValue(slate)}' from Slate");
}
}
// 验证写入
if (logDebug.GetValue(slate))
{
object readBackValue = eventVarManager.GetVariable<object>(targetName);
bool writeVerified = (readBackValue == null && newValue == null) ||
(readBackValue != null && readBackValue.Equals(newValue));
Log.Message($" - New value written: {newValue} (Type: {newValue.GetType().Name})");
Log.Message($" - Write verified: {writeVerified}");
if (!writeVerified)
{
Log.Warning($" - Verification failed! Expected: {newValue}, Got: {readBackValue}");
}
}
return true;
}
private object GetSourceValue(Slate slate)
{
string sourceName = sourceVariableName.GetValue(slate);
if (!string.IsNullOrEmpty(sourceName))
{
if (slate.TryGet<object>(sourceName, out var slateValue))
{
return slateValue;
}
}
return value.GetValue(slate);
}
private object CalculateNewValue(object currentValue, object sourceValue, Slate slate)
{
switch (writeMode)
{
case WriteMode.Set:
return HandleSetMode(currentValue, sourceValue, slate);
case WriteMode.Add:
case WriteMode.Multiply:
return HandleMathOperation(currentValue, sourceValue, writeMode == WriteMode.Add, slate);
case WriteMode.Append:
return HandleAppendMode(currentValue, sourceValue, slate);
case WriteMode.Min:
return HandleMinMaxMode(currentValue, sourceValue, isMin: true, slate);
case WriteMode.Max:
return HandleMinMaxMode(currentValue, sourceValue, isMin: false, slate);
case WriteMode.Increment:
return HandleIncrementMode(currentValue, slate);
default:
return sourceValue;
}
}
private object HandleSetMode(object currentValue, object sourceValue, Slate slate)
{
bool variableExists = currentValue != null;
if (checkExisting.GetValue(slate) && variableExists)
{
if (!overwrite.GetValue(slate))
{
if (logDebug.GetValue(slate))
{
Log.Message($" - Variable exists and overwrite is false, keeping current value");
}
return currentValue; // 不覆盖,返回原值
}
}
return sourceValue;
}
private object HandleMathOperation(object currentValue, object sourceValue, bool isAddition, Slate slate)
{
// 如果当前值不存在,直接使用源值
if (currentValue == null)
{
return sourceValue;
}
// 尝试进行数学运算
try
{
// 检查类型是否支持数学运算
if (!IsNumericType(currentValue.GetType()) || !IsNumericType(sourceValue.GetType()))
{
return HandleTypeMismatch(currentValue, sourceValue, "non-numeric", slate);
}
// 转换为动态类型以进行数学运算
dynamic current = ConvertToBestNumericType(currentValue);
dynamic source = ConvertToBestNumericType(sourceValue);
dynamic result;
switch (mathOperator)
{
case MathOperator.Add:
result = current + source;
break;
case MathOperator.Subtract:
result = current - source;
break;
case MathOperator.Multiply:
result = current * source;
break;
case MathOperator.Divide:
if (source == 0)
{
Log.Error($"[QuestNode_WriteToEventVariablesWithAdd] Division by zero for variable operation");
return currentValue;
}
result = current / source;
break;
default:
result = current + source;
break;
}
// 根据配置决定返回类型
if (forceTypeConversion.GetValue(slate))
{
// 转换为与当前值相同的类型
return Convert.ChangeType(result, currentValue.GetType());
}
else
{
// 返回最佳类型通常是double或decimal
return result;
}
}
catch (Exception ex)
{
if (logDebug.GetValue(slate))
{
Log.Error($"[QuestNode_WriteToEventVariablesWithAdd] Math operation failed: {ex.Message}");
}
return currentValue;
}
}
private object HandleAppendMode(object currentValue, object sourceValue, Slate slate)
{
// 如果当前值不存在,直接使用源值
if (currentValue == null)
{
return sourceValue;
}
// 处理字符串追加
if (currentValue is string currentStr && sourceValue is string sourceStr)
{
return currentStr + sourceStr;
}
// 处理列表追加
if (currentValue is System.Collections.IEnumerable currentEnumerable &&
sourceValue is System.Collections.IEnumerable sourceEnumerable)
{
try
{
// 尝试创建新列表并添加所有元素
var resultList = new List<object>();
foreach (var item in currentEnumerable)
resultList.Add(item);
foreach (var item in sourceEnumerable)
resultList.Add(item);
return resultList;
}
catch
{
// 如果列表操作失败,回退到字符串追加
return currentValue.ToString() + sourceValue.ToString();
}
}
// 其他类型:转换为字符串并追加
return currentValue.ToString() + sourceValue.ToString();
}
private object HandleMinMaxMode(object currentValue, object sourceValue, bool isMin, Slate slate)
{
// 如果当前值不存在,直接使用源值
if (currentValue == null)
{
return sourceValue;
}
// 检查类型是否支持比较
if (!(currentValue is IComparable currentComparable) || !(sourceValue is IComparable sourceComparable))
{
return HandleTypeMismatch(currentValue, sourceValue, "non-comparable", slate);
}
try
{
int comparison = currentComparable.CompareTo(sourceComparable);
if (isMin)
{
// 取最小值
return comparison <= 0 ? currentValue : sourceValue;
}
else
{
// 取最大值
return comparison >= 0 ? currentValue : sourceValue;
}
}
catch (ArgumentException)
{
// 类型不匹配,无法比较
return HandleTypeMismatch(currentValue, sourceValue, "type mismatch for comparison", slate);
}
}
private object HandleIncrementMode(object currentValue, Slate slate)
{
// 如果当前值不存在从1开始
if (currentValue == null)
{
return 1;
}
// 检查是否是数值类型
if (!IsNumericType(currentValue.GetType()))
{
if (logDebug.GetValue(slate))
{
Log.Warning($"[QuestNode_WriteToEventVariablesWithAdd] Cannot increment non-numeric type: {currentValue.GetType().Name}");
}
return currentValue;
}
try
{
dynamic current = ConvertToBestNumericType(currentValue);
dynamic result = current + 1;
if (forceTypeConversion.GetValue(slate))
{
return Convert.ChangeType(result, currentValue.GetType());
}
else
{
return result;
}
}
catch (Exception ex)
{
if (logDebug.GetValue(slate))
{
Log.Error($"[QuestNode_WriteToEventVariablesWithAdd] Increment operation failed: {ex.Message}");
}
return currentValue;
}
}
private object HandleTypeMismatch(object currentValue, object sourceValue, string mismatchReason, Slate slate)
{
if (logDebug.GetValue(slate))
{
Log.Warning($"[QuestNode_WriteToEventVariablesWithAdd] Type mismatch for operation: {mismatchReason}");
}
switch (onTypeMismatch)
{
case TypeMismatchBehavior.ThrowError:
throw new InvalidOperationException($"Type mismatch for operation: {mismatchReason}");
case TypeMismatchBehavior.Skip:
if (logDebug.GetValue(slate))
{
Log.Message($" - Skipping operation due to type mismatch");
}
return currentValue; // 保持原值
case TypeMismatchBehavior.ConvertToString:
// 都转换为字符串
return currentValue.ToString() + " | " + sourceValue.ToString();
case TypeMismatchBehavior.UseDefault:
// 使用源值作为默认
return sourceValue;
default:
return currentValue;
}
}
private bool IsNumericType(Type type)
{
if (type == null) return false;
TypeCode typeCode = Type.GetTypeCode(type);
switch (typeCode)
{
case TypeCode.Byte:
case TypeCode.SByte:
case TypeCode.UInt16:
case TypeCode.UInt32:
case TypeCode.UInt64:
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.Int64:
case TypeCode.Decimal:
case TypeCode.Double:
case TypeCode.Single:
return true;
default:
return false;
}
}
private dynamic ConvertToBestNumericType(object value)
{
if (value == null) return 0;
Type type = value.GetType();
TypeCode typeCode = Type.GetTypeCode(type);
switch (typeCode)
{
case TypeCode.Decimal:
return (decimal)value;
case TypeCode.Double:
return (double)value;
case TypeCode.Single:
return (float)value;
case TypeCode.Int64:
return (long)value;
case TypeCode.Int32:
return (int)value;
case TypeCode.Int16:
return (short)value;
case TypeCode.UInt64:
return (ulong)value;
case TypeCode.UInt32:
return (uint)value;
case TypeCode.UInt16:
return (ushort)value;
case TypeCode.Byte:
return (byte)value;
case TypeCode.SByte:
return (sbyte)value;
default:
// 尝试转换
try
{
return Convert.ToDouble(value);
}
catch
{
return 0;
}
}
}
}
}