238 lines
9.1 KiB
C#
238 lines
9.1 KiB
C#
using RimWorld;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Xml;
|
|
using Verse;
|
|
|
|
namespace ArachnaeSwarm
|
|
{
|
|
[StaticConstructorOnStartup]
|
|
public static class FaceAnimationFileGenerator
|
|
{
|
|
private static readonly string OutputDirectory = "1.6/1.6/GeneratedDefs/FacialAnimation/";
|
|
|
|
static FaceAnimationFileGenerator()
|
|
{
|
|
GenerateAllFaceAnimationFiles();
|
|
}
|
|
|
|
private static void GenerateAllFaceAnimationFiles()
|
|
{
|
|
try
|
|
{
|
|
// 获取模组根目录
|
|
string modRootDir = GetModRootDirectory();
|
|
if (string.IsNullOrEmpty(modRootDir))
|
|
{
|
|
Log.Error("Cannot find mod root directory");
|
|
return;
|
|
}
|
|
|
|
// 确保输出目录存在
|
|
string fullOutputDir = Path.Combine(modRootDir, OutputDirectory);
|
|
Directory.CreateDirectory(fullOutputDir);
|
|
|
|
// 配置:种族和对应的抽象动画路径
|
|
var raceConfigs = new Dictionary<string, List<string>>
|
|
{
|
|
{
|
|
"ArachnaeNode_Race_Myrmecocystus",
|
|
new List<string> { "1.6/1.6/Defs/AnimationDefs/FacialAnimation/ARA_JobAnim.xml" }
|
|
},
|
|
{
|
|
"ArachnaeNode_Race_ShieldHead",
|
|
new List<string> { "1.6/1.6/Defs/AnimationDefs/FacialAnimation/ARA_JobAnim.xml" }
|
|
},
|
|
{
|
|
"ArachnaeNode_Race_WeaponSmith",
|
|
new List<string> { "1.6/1.6/Defs/AnimationDefs/FacialAnimation/ARA_JobAnim.xml" }
|
|
},
|
|
{
|
|
"ArachnaeNode_Race_Fighter",
|
|
new List<string> { "1.6/1.6/Defs/AnimationDefs/FacialAnimation/ARA_JobAnim.xml" }
|
|
},
|
|
{
|
|
"ArachnaeNode_Race_Facehugger",
|
|
new List<string> { "1.6/1.6/Defs/AnimationDefs/FacialAnimation/ARA_JobAnim.xml" }
|
|
},
|
|
{
|
|
"ArachnaeNode_Race_Smokepop",
|
|
new List<string> { "1.6/1.6/Defs/AnimationDefs/FacialAnimation/ARA_JobAnim.xml" }
|
|
},
|
|
{
|
|
"ArachnaeNode_Race_NeuroSwarm",
|
|
new List<string> { "1.6/1.6/Defs/AnimationDefs/FacialAnimation/ARA_JobAnim.xml" }
|
|
},
|
|
{
|
|
"ArachnaeNode_Race_Praetorian",
|
|
new List<string> { "1.6/1.6/Defs/AnimationDefs/FacialAnimation/ARA_JobAnim.xml" }
|
|
},
|
|
{
|
|
"ArachnaeNode_Race_Skyraider",
|
|
new List<string> { "1.6/1.6/Defs/AnimationDefs/FacialAnimation/ARA_JobAnim.xml" }
|
|
}
|
|
};
|
|
|
|
int totalFilesGenerated = 0;
|
|
|
|
foreach (var config in raceConfigs)
|
|
{
|
|
string raceDefName = config.Key;
|
|
List<string> paths = config.Value;
|
|
|
|
// 检查种族是否存在
|
|
if (DefDatabase<ThingDef>.GetNamedSilentFail(raceDefName) == null)
|
|
{
|
|
Log.Warning($"Race {raceDefName} not found, skipping face animation generation");
|
|
continue;
|
|
}
|
|
|
|
foreach (string relativePath in paths)
|
|
{
|
|
string fullSourcePath = Path.Combine(modRootDir, relativePath);
|
|
totalFilesGenerated += GenerateAnimationFilesForRace(fullSourcePath, raceDefName, fullOutputDir);
|
|
}
|
|
}
|
|
|
|
Log.Message($"Generated {totalFilesGenerated} face animation files in {fullOutputDir}");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.Error($"Error in FaceAnimationFileGenerator: {ex}");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取模组根目录
|
|
/// </summary>
|
|
private static string GetModRootDirectory()
|
|
{
|
|
try
|
|
{
|
|
// 通过查找当前程序集所在的模组来获取根目录
|
|
var currentMod = LoadedModManager.RunningMods.FirstOrDefault(mod =>
|
|
mod.assemblies.loadedAssemblies.Contains(typeof(FaceAnimationFileGenerator).Assembly));
|
|
|
|
if (currentMod != null)
|
|
{
|
|
return currentMod.RootDir;
|
|
}
|
|
|
|
// 备选方法:通过反射获取
|
|
var assembly = typeof(FaceAnimationFileGenerator).Assembly;
|
|
string assemblyLocation = assembly.Location;
|
|
if (!string.IsNullOrEmpty(assemblyLocation))
|
|
{
|
|
// 向上查找直到找到模组根目录
|
|
DirectoryInfo dir = new FileInfo(assemblyLocation).Directory;
|
|
while (dir != null)
|
|
{
|
|
if (File.Exists(Path.Combine(dir.FullName, "About.xml")) ||
|
|
File.Exists(Path.Combine(dir.FullName, "LoadFolders.xml")))
|
|
{
|
|
return dir.FullName;
|
|
}
|
|
dir = dir.Parent;
|
|
}
|
|
}
|
|
|
|
Log.Error("Cannot determine mod root directory");
|
|
return null;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.Error($"Error getting mod root directory: {ex}");
|
|
return null;
|
|
}
|
|
}
|
|
|
|
private static int GenerateAnimationFilesForRace(string sourcePath, string raceDefName, string outputDir)
|
|
{
|
|
int filesGenerated = 0;
|
|
|
|
try
|
|
{
|
|
// 检查源文件是否存在
|
|
if (!File.Exists(sourcePath))
|
|
{
|
|
Log.Warning($"Source animation file not found: {sourcePath}");
|
|
return 0;
|
|
}
|
|
|
|
XmlDocument xmlDoc = new XmlDocument();
|
|
xmlDoc.Load(sourcePath);
|
|
|
|
XmlNodeList abstractDefNodes = xmlDoc.SelectNodes("//FacialAnimation.FaceAnimationDef[@Abstract='True']");
|
|
|
|
if (abstractDefNodes == null || abstractDefNodes.Count == 0)
|
|
{
|
|
Log.Message($"No abstract FaceAnimationDef found in: {sourcePath}");
|
|
return 0;
|
|
}
|
|
|
|
// 为每个种族创建单独的文件
|
|
string outputFile = Path.Combine(outputDir, $"ARA_{raceDefName}_JobAnim.xml");
|
|
|
|
using (StreamWriter writer = new StreamWriter(outputFile, false, Encoding.UTF8))
|
|
{
|
|
writer.WriteLine("<?xml version=\"1.0\" encoding=\"utf-8\" ?>");
|
|
writer.WriteLine("<Defs>");
|
|
|
|
foreach (XmlNode abstractNode in abstractDefNodes)
|
|
{
|
|
string concreteXml = GenerateConcreteAnimationXml(abstractNode, raceDefName);
|
|
if (!string.IsNullOrEmpty(concreteXml))
|
|
{
|
|
writer.WriteLine(concreteXml);
|
|
filesGenerated++;
|
|
}
|
|
}
|
|
|
|
writer.WriteLine("</Defs>");
|
|
}
|
|
|
|
Log.Message($"Generated {filesGenerated} animations for {raceDefName} in {outputFile}");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.Error($"Error generating animation files for race {raceDefName}: {ex}");
|
|
}
|
|
|
|
return filesGenerated;
|
|
}
|
|
|
|
private static string GenerateConcreteAnimationXml(XmlNode abstractNode, string raceDefName)
|
|
{
|
|
try
|
|
{
|
|
string abstractName = abstractNode.Attributes?["Name"]?.Value;
|
|
if (string.IsNullOrEmpty(abstractName))
|
|
{
|
|
Log.Warning("Abstract FaceAnimationDef has no Name attribute");
|
|
return null;
|
|
}
|
|
|
|
string concreteDefName = $"{raceDefName}_{abstractName.Replace("ARA_", "")}";
|
|
|
|
// 创建XML字符串
|
|
StringBuilder xmlBuilder = new StringBuilder();
|
|
xmlBuilder.AppendLine($" <FacialAnimation.FaceAnimationDef ParentName=\"{abstractName}\" MayRequire=\"Nals.FacialAnimation\">");
|
|
xmlBuilder.AppendLine($" <defName>{concreteDefName}</defName>");
|
|
xmlBuilder.AppendLine($" <raceName>{raceDefName}</raceName>");
|
|
|
|
xmlBuilder.Append(" </FacialAnimation.FaceAnimationDef>");
|
|
|
|
return xmlBuilder.ToString();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.Error($"Error generating XML for {raceDefName}: {ex}");
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
}
|