2021-08-11 21:44:26 +00:00
|
|
|
using System;
|
2021-07-28 22:08:57 +00:00
|
|
|
using System.CodeDom;
|
|
|
|
using System.CodeDom.Compiler;
|
2021-08-11 21:44:26 +00:00
|
|
|
using System.Collections.Generic;
|
2021-07-28 22:08:57 +00:00
|
|
|
using System.IO;
|
|
|
|
using System.Linq;
|
2021-08-11 21:44:26 +00:00
|
|
|
using System.Reflection;
|
|
|
|
using Gamecraft.Tweaks;
|
2021-07-28 22:08:57 +00:00
|
|
|
using RobocraftX.Common;
|
2021-07-28 23:04:27 +00:00
|
|
|
using Svelto.ECS;
|
2021-07-28 22:08:57 +00:00
|
|
|
|
|
|
|
namespace CodeGenerator
|
|
|
|
{
|
|
|
|
public class BlockClassGenerator
|
|
|
|
{
|
2021-08-11 21:44:26 +00:00
|
|
|
public void Generate(string name, string group = null, Dictionary<string, string> renames = null, params Type[] types)
|
2021-07-28 22:08:57 +00:00
|
|
|
{
|
|
|
|
if (group is null)
|
|
|
|
{
|
|
|
|
group = GetGroup(name) + "_BLOCK_GROUP";
|
|
|
|
if (typeof(CommonExclusiveGroups).GetFields().All(field => field.Name != group))
|
|
|
|
group = GetGroup(name) + "_BLOCK_BUILD_GROUP";
|
|
|
|
}
|
|
|
|
|
2022-04-11 22:52:24 +00:00
|
|
|
if (!group.Contains('.'))
|
2021-08-11 21:44:26 +00:00
|
|
|
group = "CommonExclusiveGroups." + group;
|
|
|
|
|
2021-07-28 22:08:57 +00:00
|
|
|
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);
|
2021-08-11 21:44:26 +00:00
|
|
|
//cl.BaseTypes.Add(baseClass != null ? new CodeTypeReference(baseClass) : new CodeTypeReference("Block"));
|
|
|
|
cl.BaseTypes.Add(new CodeTypeReference("SignalingBlock"));
|
2021-07-28 22:08:57 +00:00
|
|
|
cl.Members.Add(new CodeConstructor
|
|
|
|
{
|
|
|
|
Parameters = {new CodeParameterDeclarationExpression("EGID", "egid")},
|
2021-08-11 21:44:26 +00:00
|
|
|
Comments =
|
|
|
|
{
|
|
|
|
_start, new CodeCommentStatement($"Constructs a(n) {name} object representing an existing block.", true), _end
|
|
|
|
},
|
|
|
|
BaseConstructorArgs = {new CodeVariableReferenceExpression("egid")},
|
|
|
|
Attributes = MemberAttributes.Public | MemberAttributes.Final
|
2021-07-28 22:08:57 +00:00
|
|
|
});
|
|
|
|
cl.Members.Add(new CodeConstructor
|
|
|
|
{
|
|
|
|
Parameters =
|
|
|
|
{
|
|
|
|
new CodeParameterDeclarationExpression(typeof(uint), "id")
|
|
|
|
},
|
2021-08-11 21:44:26 +00:00
|
|
|
Comments =
|
|
|
|
{
|
|
|
|
_start, new CodeCommentStatement($"Constructs a(n) {name} object representing an existing block.", true), _end
|
|
|
|
},
|
2021-07-28 22:08:57 +00:00
|
|
|
BaseConstructorArgs =
|
|
|
|
{
|
|
|
|
new CodeObjectCreateExpression("EGID", new CodeVariableReferenceExpression("id"),
|
2021-08-11 21:44:26 +00:00
|
|
|
new CodeVariableReferenceExpression(group))
|
|
|
|
},
|
|
|
|
Attributes = MemberAttributes.Public | MemberAttributes.Final
|
2021-07-28 22:08:57 +00:00
|
|
|
});
|
2021-08-11 21:44:26 +00:00
|
|
|
foreach (var type in types)
|
|
|
|
{
|
|
|
|
GenerateProperties(cl, type, name, renames);
|
|
|
|
}
|
2021-07-28 22:08:57 +00:00
|
|
|
ns.Types.Add(cl);
|
|
|
|
codeUnit.Namespaces.Add(ns);
|
|
|
|
|
|
|
|
var provider = CodeDomProvider.CreateProvider("CSharp");
|
2022-06-01 14:54:17 +00:00
|
|
|
var path = $@"../../../../TechbloxModdingAPI/Blocks/{name}.cs";
|
2021-08-11 21:44:26 +00:00
|
|
|
using (var sw = new StreamWriter(path))
|
2021-07-28 22:08:57 +00:00
|
|
|
{
|
|
|
|
provider.GenerateCodeFromCompileUnit(codeUnit, sw, new CodeGeneratorOptions {BracingStyle = "C"});
|
|
|
|
}
|
2021-08-11 21:44:26 +00:00
|
|
|
|
|
|
|
File.WriteAllLines(path,
|
|
|
|
File.ReadAllLines(path).SkipWhile(line => line.StartsWith("//") || line.Length == 0));
|
2021-07-28 22:08:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2021-07-28 23:04:27 +00:00
|
|
|
|
2021-08-11 21:44:26 +00:00
|
|
|
private void GenerateProperties(CodeTypeDeclaration cl, Type type, string baseClass,
|
|
|
|
Dictionary<string, string> renames)
|
2021-07-28 23:04:27 +00:00
|
|
|
{
|
2021-08-11 21:44:26 +00:00
|
|
|
if (!typeof(IEntityComponent).IsAssignableFrom(type))
|
|
|
|
throw new ArgumentException("Type must be an entity component");
|
2022-02-06 02:11:51 +00:00
|
|
|
bool reflection = type.IsNotPublic;
|
|
|
|
var reflectedType = new CodeSnippetExpression($"HarmonyLib.AccessTools.TypeByName(\"{type.FullName}\")");
|
2021-07-28 23:04:27 +00:00
|
|
|
foreach (var field in type.GetFields())
|
|
|
|
{
|
2021-08-11 21:44:26 +00:00
|
|
|
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);
|
2022-02-06 02:11:51 +00:00
|
|
|
var getStruct = new CodeMethodInvokeExpression(
|
|
|
|
new CodeMethodReferenceExpression(new CodeSnippetExpression("BlockEngine"),
|
|
|
|
"GetBlockInfo", new CodeTypeReference(type)),
|
|
|
|
new CodeThisReferenceExpression());
|
|
|
|
CodeExpression structFieldReference = new CodeFieldReferenceExpression(getStruct, field.Name);
|
|
|
|
CodeExpression reflectedGet = new CodeCastExpression(field.FieldType, new CodeMethodInvokeExpression(
|
2021-07-28 23:04:27 +00:00
|
|
|
new CodeMethodReferenceExpression(new CodeSnippetExpression("BlockEngine"),
|
2022-02-06 02:11:51 +00:00
|
|
|
"GetBlockInfo"),
|
|
|
|
new CodeThisReferenceExpression(), reflectedType, new CodePrimitiveExpression(field.Name)));
|
|
|
|
CodeExpression reflectedSet = new CodeMethodInvokeExpression(
|
|
|
|
new CodeMethodReferenceExpression(new CodeSnippetExpression("BlockEngine"),
|
|
|
|
"SetBlockInfo"),
|
|
|
|
new CodeThisReferenceExpression(), reflectedType, new CodePrimitiveExpression(field.Name),
|
|
|
|
new CodePropertySetValueReferenceExpression());
|
2021-07-28 23:04:27 +00:00
|
|
|
cl.Members.Add(new CodeMemberProperty
|
|
|
|
{
|
|
|
|
Name = propName,
|
|
|
|
HasGet = true,
|
|
|
|
HasSet = true,
|
|
|
|
GetStatements =
|
|
|
|
{
|
2022-02-06 02:11:51 +00:00
|
|
|
new CodeMethodReturnStatement(reflection ? reflectedGet : structFieldReference)
|
2021-07-28 23:04:27 +00:00
|
|
|
},
|
|
|
|
SetStatements =
|
|
|
|
{
|
2022-02-06 02:11:51 +00:00
|
|
|
reflection
|
|
|
|
? (CodeStatement)new CodeExpressionStatement(reflectedSet)
|
|
|
|
: new CodeAssignStatement(structFieldReference, new CodePropertySetValueReferenceExpression())
|
2021-07-28 23:04:27 +00:00
|
|
|
},
|
2021-08-11 21:44:26 +00:00
|
|
|
Type = new CodeTypeReference(field.FieldType),
|
|
|
|
Attributes = MemberAttributes.Public | MemberAttributes.Final,
|
|
|
|
Comments =
|
|
|
|
{
|
2022-02-06 02:11:51 +00:00
|
|
|
_start,
|
|
|
|
new CodeCommentStatement($"Gets or sets the {baseClass}'s {propName} property." +
|
|
|
|
$" {(attr != null ? "Tweakable stat." : "May not be saved.")}",
|
|
|
|
true),
|
|
|
|
_end
|
2021-08-11 21:44:26 +00:00
|
|
|
}
|
2021-07-28 23:04:27 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
2021-08-11 21:44:26 +00:00
|
|
|
|
|
|
|
private static readonly CodeCommentStatement _start = new CodeCommentStatement("<summary>", true);
|
|
|
|
private static readonly CodeCommentStatement _end = new CodeCommentStatement("</summary>", true);
|
2021-07-28 22:08:57 +00:00
|
|
|
}
|
|
|
|
}
|