NorbiPeti
c0eae77421
Made the generated members public and final Removed the comment from the start of the files Generating the files directly into the project folder Added comments describing the generated constructors and properties Using SignalingBlock as a base class Added support for renaming properties Added support for getting the name from the tweakable stat name Added/updated functional block classes
142 lines
No EOL
5.9 KiB
C#
142 lines
No EOL
5.9 KiB
C#
using System;
|
|
using System.CodeDom;
|
|
using System.CodeDom.Compiler;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using Gamecraft.Tweaks;
|
|
using RobocraftX.Common;
|
|
using Svelto.ECS;
|
|
using Techblox.EngineBlock;
|
|
|
|
namespace CodeGenerator
|
|
{
|
|
public class BlockClassGenerator
|
|
{
|
|
public void Generate(string name, string group = null, Dictionary<string, string> renames = null, params Type[] types)
|
|
{
|
|
if (group is null)
|
|
{
|
|
group = GetGroup(name) + "_BLOCK_GROUP";
|
|
if (typeof(CommonExclusiveGroups).GetFields().All(field => field.Name != group))
|
|
group = GetGroup(name) + "_BLOCK_BUILD_GROUP";
|
|
}
|
|
|
|
if (!group.Contains("."))
|
|
group = "CommonExclusiveGroups." + group;
|
|
|
|
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(name);
|
|
//cl.BaseTypes.Add(baseClass != null ? new CodeTypeReference(baseClass) : new CodeTypeReference("Block"));
|
|
cl.BaseTypes.Add(new CodeTypeReference("SignalingBlock"));
|
|
cl.Members.Add(new CodeConstructor
|
|
{
|
|
Parameters = {new CodeParameterDeclarationExpression("EGID", "egid")},
|
|
Comments =
|
|
{
|
|
_start, new CodeCommentStatement($"Constructs a(n) {name} object representing an existing block.", true), _end
|
|
},
|
|
BaseConstructorArgs = {new CodeVariableReferenceExpression("egid")},
|
|
Attributes = MemberAttributes.Public | MemberAttributes.Final
|
|
});
|
|
cl.Members.Add(new CodeConstructor
|
|
{
|
|
Parameters =
|
|
{
|
|
new CodeParameterDeclarationExpression(typeof(uint), "id")
|
|
},
|
|
Comments =
|
|
{
|
|
_start, new CodeCommentStatement($"Constructs a(n) {name} object representing an existing block.", true), _end
|
|
},
|
|
BaseConstructorArgs =
|
|
{
|
|
new CodeObjectCreateExpression("EGID", new CodeVariableReferenceExpression("id"),
|
|
new CodeVariableReferenceExpression(group))
|
|
},
|
|
Attributes = MemberAttributes.Public | MemberAttributes.Final
|
|
});
|
|
foreach (var type in types)
|
|
{
|
|
GenerateProperties(cl, type, name, renames);
|
|
}
|
|
ns.Types.Add(cl);
|
|
codeUnit.Namespaces.Add(ns);
|
|
|
|
var provider = CodeDomProvider.CreateProvider("CSharp");
|
|
var path = $@"..\..\..\TechbloxModdingAPI\Blocks\{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 string GetGroup(string name)
|
|
{
|
|
var ret = "";
|
|
foreach (var ch in name)
|
|
{
|
|
if (char.IsUpper(ch) && ret.Length > 0)
|
|
ret += "_" + ch;
|
|
else
|
|
ret += char.ToUpper(ch);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
private void GenerateProperties(CodeTypeDeclaration cl, Type type, string baseClass,
|
|
Dictionary<string, string> renames)
|
|
{
|
|
if (!typeof(IEntityComponent).IsAssignableFrom(type))
|
|
throw new ArgumentException("Type must be an entity component");
|
|
foreach (var field in type.GetFields())
|
|
{
|
|
var attr = field.GetCustomAttribute<TweakableStatAttribute>();
|
|
if (renames == null || !renames.TryGetValue(field.Name, out var propName))
|
|
{
|
|
propName = field.Name;
|
|
if (attr != null)
|
|
propName = attr.propertyName;
|
|
}
|
|
|
|
propName = char.ToUpper(propName[0]) + propName.Substring(1);
|
|
var structFieldReference = new CodeFieldReferenceExpression(new CodeMethodInvokeExpression(
|
|
new CodeMethodReferenceExpression(new CodeSnippetExpression("BlockEngine"),
|
|
"GetBlockInfo", new CodeTypeReference(type)),
|
|
new CodeThisReferenceExpression()), field.Name);
|
|
cl.Members.Add(new CodeMemberProperty
|
|
{
|
|
Name = propName,
|
|
HasGet = true,
|
|
HasSet = true,
|
|
GetStatements =
|
|
{
|
|
new CodeMethodReturnStatement(structFieldReference)
|
|
},
|
|
SetStatements =
|
|
{
|
|
new CodeAssignStatement(structFieldReference, new CodePropertySetValueReferenceExpression())
|
|
},
|
|
Type = new CodeTypeReference(field.FieldType),
|
|
Attributes = MemberAttributes.Public | MemberAttributes.Final,
|
|
Comments =
|
|
{
|
|
_start, new CodeCommentStatement($"Gets or sets the {baseClass}'s {propName} property." +
|
|
$" {(attr != null ? "Tweakable stat." : "May not be saved.")}", true), _end
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
private static readonly CodeCommentStatement _start = new CodeCommentStatement("<summary>", true);
|
|
private static readonly CodeCommentStatement _end = new CodeCommentStatement("</summary>", true);
|
|
}
|
|
} |