129 lines
5.8 KiB
C#
129 lines
5.8 KiB
C#
|
using System;
|
||
|
using System.CodeDom;
|
||
|
using System.CodeDom.Compiler;
|
||
|
using System.IO;
|
||
|
using System.Linq;
|
||
|
|
||
|
namespace CodeGenerator
|
||
|
{
|
||
|
public static class ECSClassGenerator
|
||
|
{
|
||
|
public static void Generate(Type entityDescriptorType)
|
||
|
{
|
||
|
var info = ECSAnalyzer.AnalyzeEntityDescriptor(entityDescriptorType);
|
||
|
|
||
|
var codeUnit = new CodeCompileUnit();
|
||
|
var ns = new CodeNamespace("TechbloxModdingAPI.Blocks");
|
||
|
ns.Imports.Add(new CodeNamespaceImport("RobocraftX.Common"));
|
||
|
ns.Imports.Add(new CodeNamespaceImport("Svelto.ECS"));
|
||
|
var cl = new CodeTypeDeclaration(info.Name);
|
||
|
cl.BaseTypes.Add(new CodeTypeReference("SignalingBlock"));
|
||
|
cl.Members.Add(new CodeConstructor
|
||
|
{
|
||
|
Parameters = {new CodeParameterDeclarationExpression("EGID", "egid")},
|
||
|
Comments =
|
||
|
{
|
||
|
_start,
|
||
|
new CodeCommentStatement($"Constructs a(n) {info.Name} object representing an existing block.", true),
|
||
|
_end
|
||
|
},
|
||
|
BaseConstructorArgs = {new CodeVariableReferenceExpression("egid")},
|
||
|
Attributes = MemberAttributes.Public | MemberAttributes.Final
|
||
|
});
|
||
|
foreach (var propertyInfo in info.Properties)
|
||
|
{
|
||
|
if (propertyInfo is ECSReflectedPropertyInfo reflectedPropertyInfo)
|
||
|
GenerateReflectedProperty(reflectedPropertyInfo, cl);
|
||
|
else
|
||
|
GenerateProperty(propertyInfo, cl);
|
||
|
}
|
||
|
ns.Types.Add(cl);
|
||
|
codeUnit.Namespaces.Add(ns);
|
||
|
|
||
|
var provider = CodeDomProvider.CreateProvider("CSharp");
|
||
|
var path = $"../../../../TechbloxModdingAPI/Blocks/{info.Name}.cs";
|
||
|
using (var sw = new StreamWriter(path))
|
||
|
{
|
||
|
provider.GenerateCodeFromCompileUnit(codeUnit, sw, new CodeGeneratorOptions {BracingStyle = "C"});
|
||
|
}
|
||
|
|
||
|
File.WriteAllLines(path,
|
||
|
File.ReadAllLines(path).SkipWhile(line => line.StartsWith("//") || line.Length == 0));
|
||
|
}
|
||
|
|
||
|
private static void GenerateProperty(ECSPropertyInfo info, CodeTypeDeclaration cl)
|
||
|
{
|
||
|
var getStruct = new CodeMethodInvokeExpression(
|
||
|
new CodeMethodReferenceExpression(new CodeSnippetExpression("BlockEngine"),
|
||
|
"GetBlockInfo", new CodeTypeReference(info.ComponentType)),
|
||
|
new CodeThisReferenceExpression());
|
||
|
CodeExpression structFieldReference = new CodeFieldReferenceExpression(getStruct, info.Name);
|
||
|
cl.Members.Add(new CodeMemberProperty
|
||
|
{
|
||
|
Name = info.Name,
|
||
|
HasGet = true,
|
||
|
HasSet = true,
|
||
|
GetStatements =
|
||
|
{
|
||
|
new CodeMethodReturnStatement(structFieldReference)
|
||
|
},
|
||
|
SetStatements =
|
||
|
{
|
||
|
new CodeAssignStatement(structFieldReference, new CodePropertySetValueReferenceExpression())
|
||
|
},
|
||
|
Type = new CodeTypeReference(info.Type),
|
||
|
Attributes = MemberAttributes.Public | MemberAttributes.Final,
|
||
|
Comments =
|
||
|
{
|
||
|
_start,
|
||
|
new CodeCommentStatement($"Gets or sets the {info.ComponentType.Name}'s {info.Name} property." +
|
||
|
" May not be saved.", // TODO: Doesn't know if tweakable stat
|
||
|
true),
|
||
|
_end
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
private static void GenerateReflectedProperty(ECSReflectedPropertyInfo info, CodeTypeDeclaration cl)
|
||
|
{
|
||
|
var reflectedType = new CodeSnippetExpression($"HarmonyLib.AccessTools.TypeByName(\"{info.OriginalClassName}\")");
|
||
|
|
||
|
CodeExpression reflectedGet = new CodeCastExpression(info.Type, new CodeMethodInvokeExpression(
|
||
|
new CodeMethodReferenceExpression(new CodeSnippetExpression("BlockEngine"),
|
||
|
"GetBlockInfo"),
|
||
|
new CodeThisReferenceExpression(), reflectedType, new CodePrimitiveExpression(info.Name)));
|
||
|
CodeExpression reflectedSet = new CodeMethodInvokeExpression(
|
||
|
new CodeMethodReferenceExpression(new CodeSnippetExpression("BlockEngine"),
|
||
|
"SetBlockInfo"),
|
||
|
new CodeThisReferenceExpression(), reflectedType, new CodePrimitiveExpression(info.Name),
|
||
|
new CodePropertySetValueReferenceExpression());
|
||
|
cl.Members.Add(new CodeMemberProperty
|
||
|
{
|
||
|
Name = info.Name,
|
||
|
HasGet = true,
|
||
|
HasSet = true,
|
||
|
GetStatements =
|
||
|
{
|
||
|
new CodeMethodReturnStatement(reflectedGet)
|
||
|
},
|
||
|
SetStatements =
|
||
|
{
|
||
|
(CodeStatement)new CodeExpressionStatement(reflectedSet)
|
||
|
},
|
||
|
Type = new CodeTypeReference(info.Type),
|
||
|
Attributes = MemberAttributes.Public | MemberAttributes.Final,
|
||
|
Comments =
|
||
|
{
|
||
|
_start,
|
||
|
new CodeCommentStatement($"Gets or sets the {info.ComponentType.Name}'s {info.Name} property." +
|
||
|
" May not be saved.", // TODO: Doesn't know if tweakable stat
|
||
|
true),
|
||
|
_end
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
private static readonly CodeCommentStatement _start = new("<summary>", true);
|
||
|
private static readonly CodeCommentStatement _end = new("</summary>", true);
|
||
|
}
|
||
|
}
|