diff --git a/.idea/.idea.BlenderSharp/.idea/statistic.xml b/.idea/.idea.BlenderSharp/.idea/statistic.xml
new file mode 100644
index 0000000..fe71fe1
--- /dev/null
+++ b/.idea/.idea.BlenderSharp/.idea/statistic.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/CodeGenerator/Program.cs b/CodeGenerator/Program.cs
index 2c41cfd..be3660c 100644
--- a/CodeGenerator/Program.cs
+++ b/CodeGenerator/Program.cs
@@ -17,11 +17,16 @@ using BlendFile = Kaitai.BlenderBlend;
// ReSharper disable BitwiseOperatorOnEnumWithoutFlags
namespace CodeGenerator {
+ using CParamDeclExp = CodeParameterDeclarationExpression;
+ using CArgRefExp = CodeArgumentReferenceExpression;
+ using CThisRefExp = CodeThisReferenceExpression;
+ using CFieldRefExp = CodeFieldReferenceExpression;
+
public class Program {
public static BlendFile blendfile;
private static StringBuilder sb = new();
- private const string OutPath = @"Blendfile\DNA";
- private const string Namespace = "BlendFile.DNA";
+ private const string OutPath = @"GeneratedOutput\";
+ private const string Namespace = "BlendFile";
private static readonly string[] AdaptedTypes = new[] { "uchar" };
private static HashSet customTypes;
@@ -37,10 +42,12 @@ namespace CodeGenerator {
Log("Generating C# code...");
Log("Pass 1: Generating types");
- CodeNamespace ns = GenerateTypes();
+ CodeNamespace rootNs;
+ CodeNamespace ns = GenerateTypes(out rootNs);
Log("Pass 2: Writing out code");
OutputCodeFiles(ns);
+ OutputCodeFiles(rootNs, false);
Log("Finished generating C# code!");
File.AppendAllText("Log.txt", sb.ToString());
@@ -54,10 +61,14 @@ namespace CodeGenerator {
$"DataBlocks: {blendfile.Blocks.Count}\n" +
$"DNA1: {blendfile.SdnaStructs.Count} structures\n");
}
-
- private static CodeNamespace GenerateTypes() {
- CodeNamespace ns = new CodeNamespace(Namespace);
-
+
+ private static CodeNamespace GenerateTypes(out CodeNamespace additionalNs) {
+ CodeNamespace rootNs = new CodeNamespace(Namespace);
+ rootNs.Types.Add(GenerateDNAFieldAttributeType());
+ rootNs.Types.Add(GenerateDNAClassAttributeType());
+ CodeNamespace ns = new CodeNamespace(Namespace+".DNA");
+ ns.Imports.Add(new(rootNs.Name));
+
customTypes = new();
foreach (var type in blendfile.SdnaStructs) {
@@ -93,7 +104,8 @@ namespace CodeGenerator {
//Add the fields to the class
Log($"Fields: {type.Fields.Count}");
- foreach (var field in type.Fields) {
+ for (var index = 0; index < type.Fields.Count; index++) {
+ var field = type.Fields[index];
CodeMemberField cmf;
string name = field.Name;
if (name.Contains("()")) continue;
@@ -105,7 +117,7 @@ namespace CodeGenerator {
Log($"Generating field {field.Name}");
cmf = CreateMemberField(field);
}
-
+ cmf.CustomAttributes.Add(GenerateDNAFieldAttribute(index, field, field.M_Parent.M_Parent));
ctd.Members.Add(cmf);
}
@@ -114,9 +126,196 @@ namespace CodeGenerator {
Log("Finished generating struct");
}
+ additionalNs = rootNs;
return ns;
}
+ private static CodeTypeDeclaration GenerateDNAFieldAttributeType() {
+ var ctd = new CodeTypeDeclaration("DNAFieldAttribute") {
+ IsClass = true,
+ Attributes = MemberAttributes.Public
+ };
+ ctd.BaseTypes.Add(new CodeTypeReference(typeof(Attribute)));
+ ctd.CustomAttributes.Add(new("AttributeUsage",
+ new CodeAttributeArgument(new CodeSnippetExpression("AttributeTargets.Field"))));
+
+ var cmf = new CodeMemberField(typeof(int), "_size") {
+ Attributes = MemberAttributes.Private
+ };
+ ctd.Members.Add(cmf);
+
+ var cmp = new CodeMemberProperty() {
+ Name = "Size",
+ Type = new CodeTypeReference(typeof(int)),
+ Attributes = MemberAttributes.Public,
+ HasSet = true,
+ SetStatements = {
+ new CodeAssignStatement(new CFieldRefExp(new CThisRefExp(), "_size"), new CArgRefExp("value"))
+ },
+ HasGet = true,
+ GetStatements = {
+ new CodeMethodReturnStatement(new CFieldRefExp(new CThisRefExp(), "_size"))
+ }
+ };
+ ctd.Members.Add(cmp);
+
+ cmf = new CodeMemberField(typeof(string), "_originalType") {
+ Attributes = MemberAttributes.Private
+ };
+ ctd.Members.Add(cmf);
+
+ cmp = new CodeMemberProperty() {
+ Name = "OriginalType",
+ Type = new CodeTypeReference(typeof(string)),
+ Attributes = MemberAttributes.Public,
+ HasSet = true,
+ SetStatements = {
+ new CodeAssignStatement(new CFieldRefExp(new CThisRefExp(), "_originalType"), new CArgRefExp("value"))
+ },
+ HasGet = true,
+ GetStatements = {
+ new CodeMethodReturnStatement(new CFieldRefExp(new CThisRefExp(), "_originalType"))
+ }
+ };
+ ctd.Members.Add(cmp);
+
+ cmf = new CodeMemberField(typeof(string), "_originalName") {
+ Attributes = MemberAttributes.Private
+ };
+ ctd.Members.Add(cmf);
+
+ cmp = new CodeMemberProperty() {
+ Name = "OriginalName",
+ Type = new CodeTypeReference(typeof(string)),
+ Attributes = MemberAttributes.Public,
+ HasSet = true,
+ SetStatements = {
+ new CodeAssignStatement(
+ new CFieldRefExp(new CThisRefExp(), "_originalName"), new CArgRefExp("value"))
+ },
+ HasGet = true,
+ GetStatements = {
+ new CodeMethodReturnStatement(new CFieldRefExp(new CThisRefExp(), "_originalName"))
+ }
+ };
+ ctd.Members.Add(cmp);
+
+ cmf = new CodeMemberField(typeof(int), "_originalIndex") {
+ Attributes = MemberAttributes.Private
+ };
+ ctd.Members.Add(cmf);
+
+ cmp = new CodeMemberProperty() {
+ Name = "OriginalIndex",
+ Type = new CodeTypeReference(typeof(int)),
+ Attributes = MemberAttributes.Public,
+ HasSet = true,
+ SetStatements = {
+ new CodeAssignStatement(new CFieldRefExp(new CThisRefExp(), "_originalIndex"), new CArgRefExp("value"))
+ },
+ HasGet = true,
+ GetStatements = {
+ new CodeMethodReturnStatement(new CFieldRefExp(new CThisRefExp(), "_originalIndex"))
+ }
+ };
+ ctd.Members.Add(cmp);
+
+ var cc = new CodeConstructor() { Attributes = MemberAttributes.Public };
+
+ cc.Parameters.AddRange(new CParamDeclExp[] {
+ new(typeof(int), "originalIndex"),
+ new(typeof(string), "originalType"),
+ new(typeof(string), "originalName"),
+ new(typeof(int), "size")
+ });
+
+ cc.Statements.AddRange(new CodeAssignStatement[] {
+ new(new CFieldRefExp(new CThisRefExp(), "OriginalIndex"), new CArgRefExp("originalIndex")),
+ new(new CFieldRefExp(new CThisRefExp(), "OriginalType"), new CArgRefExp("originalType")),
+ new(new CFieldRefExp(new CThisRefExp(), "OriginalName"), new CArgRefExp("originalName")),
+ new(new CFieldRefExp(new CThisRefExp(), "Size"), new CArgRefExp("size"))
+ });
+
+ ctd.Members.Add(cc);
+ return ctd;
+ }
+
+ private static CodeTypeDeclaration GenerateDNAClassAttributeType() {
+ var ctd = new CodeTypeDeclaration("DNAClassAttribute") {
+ IsClass = true,
+ Attributes = MemberAttributes.Public
+ };
+ ctd.CustomAttributes.Add(new("AttributeUsage",
+ new CodeAttributeArgument(new CodeSnippetExpression("AttributeTargets.Class"))));
+
+ var cmf = new CodeMemberField(typeof(int), "_originalIndex") {
+ Attributes = MemberAttributes.Private
+ };
+ ctd.Members.Add(cmf);
+
+ var cmp = new CodeMemberProperty() {
+ Name = "OriginalIndex",
+ Type = new CodeTypeReference(typeof(int)),
+ Attributes = MemberAttributes.Public,
+ HasSet = true,
+ SetStatements = {
+ new CodeAssignStatement(new CFieldRefExp(new CThisRefExp(), "_originalIndex"), new CArgRefExp("value"))
+ },
+ HasGet = true,
+ GetStatements = {
+ new CodeMethodReturnStatement(new CFieldRefExp(new CThisRefExp(), "_originalIndex"))
+ }
+ };
+ ctd.Members.Add(cmp);
+
+ cmf = new CodeMemberField(typeof(string), "_originalName") {
+ Attributes = MemberAttributes.Private
+ };
+ ctd.Members.Add(cmf);
+
+ cmp = new CodeMemberProperty() {
+ Name = "OriginalName",
+ Type = new CodeTypeReference(typeof(string)),
+ Attributes = MemberAttributes.Public,
+ HasSet = true,
+ SetStatements = {
+ new CodeAssignStatement(new CFieldRefExp(new CThisRefExp(), "_originalName"), new CArgRefExp("value"))
+ },
+ HasGet = true,
+ GetStatements = {
+ new CodeMethodReturnStatement(new CFieldRefExp(new CThisRefExp(), "_originalName"))
+ }
+ };
+ ctd.Members.Add(cmp);
+
+ var cc = new CodeConstructor() { Attributes = MemberAttributes.Public };
+
+ cc.Parameters.AddRange(new CParamDeclExp[] {
+ new(typeof(int), "originalIndex"),
+ new(typeof(string), "originalName")
+ });
+
+ cc.Statements.AddRange(new CodeAssignStatement[] {
+ new(new CFieldRefExp(new CThisRefExp(), "OriginalIndex"), new CArgRefExp("originalIndex")),
+ new(new CFieldRefExp(new CThisRefExp(), "OriginalName"), new CArgRefExp("originalName"))
+ });
+
+ ctd.Members.Add(cc);
+ return ctd;
+ }
+
+ private static CodeAttributeDeclaration GenerateDNAFieldAttribute(int index, BlendFile.DnaField field,
+ BlendFile.Dna1Body body) {
+ CodeAttributeDeclaration cad = new("DNAFieldAttribute");
+ cad.Arguments.AddRange(new CodeAttributeArgumentCollection() {
+ new(new CodePrimitiveExpression(index)),
+ new(new CodePrimitiveExpression(field.Type)),
+ new(new CodePrimitiveExpression(field.Name)),
+ new(new CodePrimitiveExpression((int)body.Lengths[field.IdxType]))
+ });
+ return cad;
+ }
+
private static CodeMemberField CreateMemberField(BlenderBlend.DnaField field) {
Type t = Type.GetType(field.Type.ParseFType());
CodeMemberField cmf;
@@ -173,7 +372,7 @@ namespace CodeGenerator {
public static CodeExpression GenerateArrayInitExpression(CodeTypeReference type, IEnumerable dimensions) {
var dimValues = dimensions as int[] ?? dimensions.ToArray();
string dims = string.Concat(dimValues.Take(dimValues.Count() - 1).Select(d => $"{d},"));
- dims+= dimValues.Last();
+ dims += dimValues.Last();
return new CodeSnippetExpression($"new {type.BaseType}[{dims}]");
}
@@ -190,7 +389,7 @@ namespace CodeGenerator {
dims.Add(0);
}
return new CodeAssignStatement(
- new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), f.Name),
+ new CFieldRefExp(new CThisRefExp(), f.Name),
GenerateArrayInitExpression(f.Type, dims)
);
}).ToArray());
@@ -210,7 +409,7 @@ namespace CodeGenerator {
.OfType()
.Select(f =>
{
- var cpde = new CodeParameterDeclarationExpression(f.Type, f.Name);
+ var cpde = new CParamDeclExp(f.Type, f.Name);
cpde.Direction = FieldDirection.In;
return cpde;
}).ToArray());
@@ -219,8 +418,8 @@ namespace CodeGenerator {
cc.Statements.AddRange(ctd.Members
.OfType()
.Select(f => new CodeAssignStatement(
- new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), f.Name),
- new CodeArgumentReferenceExpression(f.Name))
+ new CFieldRefExp(new CThisRefExp(), f.Name),
+ new CArgRefExp(f.Name))
).ToArray());
return cc;
@@ -248,18 +447,22 @@ namespace CodeGenerator {
ccu.Namespaces.Add(globalNs);
}
- private static void OutputCodeFiles(CodeNamespace ns) {
- if (!Path.Exists(OutPath)) Directory.CreateDirectory(OutPath);
+ private static void OutputCodeFiles(CodeNamespace ns, bool outputExtraTypes = true) {
+ string rootPath = Path.GetDirectoryName(GetOutputPath(ns, ""));
+ if (!Path.Exists(rootPath)) Directory.CreateDirectory(rootPath!);
SetupCCU(out var codeGeneratorOptions, out var provider, out var ccu);
- CodeNamespace tempNs = new CodeNamespace(Namespace);
+ CodeNamespace tempNs = new CodeNamespace(ns.Name);
+ tempNs.Imports.AddRange(ns.Imports.Cast().ToArray());
ccu.Namespaces.Add(tempNs);
foreach (var type in ns.Types.OfType()) {
tempNs.Types.Add(type);
Log($"Writing out {(type.IsStruct ? "struct" : "class")} {type.Name}");
- using var sw = new StreamWriter($"{OutPath}\\{type.Name}.cs");
+ using var sw = new StreamWriter(GetOutputPath(ns, type.Name));
provider.GenerateCodeFromCompileUnit(ccu, sw, codeGeneratorOptions);
tempNs.Types.Remove(type);
}
+
+ if (!outputExtraTypes) return;
customTypes.ExceptWith(ns.Types.OfType().Select(t => t.Name));
foreach (var type in customTypes) {
Log($"Creating empty struct for missing {type}");
@@ -269,8 +472,12 @@ namespace CodeGenerator {
};
tempNs.Types.Add(ctd);
}
- using var finalsw = new StreamWriter($"{OutPath}\\_ExtraTypes.cs");
+ using var finalsw = new StreamWriter(GetOutputPath(ns, "_ExtraTypes"));
provider.GenerateCodeFromCompileUnit(ccu, finalsw, codeGeneratorOptions);
}
+
+ private static string GetOutputPath(CodeNamespace ns, string typeName) {
+ return $"{OutPath}\\{string.Concat(ns.Name.Split('.').Skip(1))}\\{typeName}.cs";
+ }
}
}
\ No newline at end of file