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 targetVariableName; // 要从Quest中读取的变量名(Slate中的变量) [NoTranslate] public SlateRef sourceVariableName; // 如果sourceVariableName为空,使用这个值 public SlateRef value; // 写入模式 public WriteMode writeMode = WriteMode.Set; // 是否检查变量已存在 public SlateRef checkExisting = true; // 如果变量已存在,是否覆盖(仅用于Set模式) public SlateRef overwrite = false; // 操作符(用于Add和Multiply模式) public MathOperator mathOperator = MathOperator.Add; // 是否强制转换类型(当类型不匹配时) public SlateRef forceTypeConversion = false; // 当类型不匹配且无法转换时的行为 public TypeMismatchBehavior onTypeMismatch = TypeMismatchBehavior.ConvertToString; // 写入后是否从Slate中删除源变量 public SlateRef removeFromSlate = false; // 是否记录调试信息 public SlateRef logDebug = false; // 允许操作的数值类型 public List allowedNumericTypes = new List { 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)) { WulaLog.Debug("[QuestNode_WriteToEventVariablesWithAdd] targetVariableName is null or empty!"); return false; } // 获取要操作的值 object sourceValue = GetSourceValue(slate); if (sourceValue == null && writeMode != WriteMode.Increment) { if (logDebug.GetValue(slate)) { WulaLog.Debug($"[QuestNode_WriteToEventVariablesWithAdd] No value to operate for variable '{targetName}'."); } return false; } // 在测试运行时不需要实际写入 if (isTestRun) { return true; } // 获取EventVariableManager var eventVarManager = Find.World.GetComponent(); if (eventVarManager == null) { WulaLog.Debug("[QuestNode_WriteToEventVariablesWithAdd] EventVariableManager not found!"); return false; } bool variableExists = eventVarManager.HasVariable(targetName); object currentValue = variableExists ? eventVarManager.GetVariable(targetName) : null; // 记录操作前的状态 if (logDebug.GetValue(slate)) { WulaLog.Debug($"[QuestNode_WriteToEventVariablesWithAdd] Operation for variable '{targetName}':"); WulaLog.Debug($" - Mode: {writeMode}"); WulaLog.Debug($" - Current value: {currentValue ?? "[null]"} (Type: {currentValue?.GetType().Name ?? "null"})"); WulaLog.Debug($" - Source value: {sourceValue ?? "[null]"} (Type: {sourceValue?.GetType().Name ?? "null"})"); } // 根据写入模式计算新值 object newValue = CalculateNewValue(currentValue, sourceValue, slate); // 如果新值为null(可能是由于类型不匹配被跳过了) if (newValue == null) { if (logDebug.GetValue(slate)) { WulaLog.Debug($" - 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)) { WulaLog.Debug($" - Removed source variable '{sourceVariableName.GetValue(slate)}' from Slate"); } } // 验证写入 if (logDebug.GetValue(slate)) { object readBackValue = eventVarManager.GetVariable(targetName); bool writeVerified = (readBackValue == null && newValue == null) || (readBackValue != null && readBackValue.Equals(newValue)); WulaLog.Debug($" - New value written: {newValue} (Type: {newValue.GetType().Name})"); WulaLog.Debug($" - Write verified: {writeVerified}"); if (!writeVerified) { WulaLog.Debug($" - 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(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)) { WulaLog.Debug($" - 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) { WulaLog.Debug($"[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)) { WulaLog.Debug($"[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(); 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)) { WulaLog.Debug($"[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)) { WulaLog.Debug($"[QuestNode_WriteToEventVariablesWithAdd] Increment operation failed: {ex.Message}"); } return currentValue; } } private object HandleTypeMismatch(object currentValue, object sourceValue, string mismatchReason, Slate slate) { if (logDebug.GetValue(slate)) { WulaLog.Debug($"[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)) { WulaLog.Debug($" - 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; } } } } }