Unity won't recognize the class from source generator

Hi! I’m new to source generator. I want to make a generator that read the item from a enum and create a struct public struct Tag_ ItemName : IComponentData {} and create a static class with a method that return the responding ComponentType of the the struct when entering a item of the enum.

the generator code is

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CavePeople_TagSourceGenerator
{
    [Generator]
    public class TagSourceGenerator : IIncrementalGenerator
    {
        public void Initialize(IncrementalGeneratorInitializationContext context)
        {
            var enumDeclarations = context.SyntaxProvider
                .CreateSyntaxProvider(
                    predicate: (s, _) => s is EnumDeclarationSyntax enumDecl && enumDecl.AttributeLists.Any(),
                    transform: (ctx, _) => (EnumDeclarationSyntax)ctx.Node)
                .Where(enumDecl => enumDecl != null && HasGenerateTagAttribute(enumDecl));

            context.RegisterSourceOutput(enumDeclarations, (spc, enumDeclaration) =>
            {
                var sourceBuilder = new StringBuilder();
                sourceBuilder.AppendLine("using Unity.Entities;");

                var B_nameSpace = new SyntaxBlock("namespace CavePeople", enumDeclaration.Members.Count + 5);

                GenStructs(B_nameSpace, enumDeclaration);
                GenBuildingUtil(B_nameSpace, enumDeclaration);

                SyntaxBlock.BuildBlockAndClear(ref sourceBuilder, B_nameSpace);

                spc.AddSource("GeneratedBuildingTypeTags", SourceText.From(sourceBuilder.ToString(), Encoding.UTF8));
            });
        }

        static bool HasGenerateTagAttribute(EnumDeclarationSyntax enumDecl)
        {
            return enumDecl.AttributeLists
                .SelectMany(al => al.Attributes)
                .Any(attr => attr.Name.ToString() == "GenerateTag");
        }

        void GenStructs(SyntaxBlock B_nameSpace, EnumDeclarationSyntax enumDeclaration)
        {
            foreach (var member in enumDeclaration.Members)
            {
                var enumName = member.Identifier.Text;
                if (enumName == "None" || enumName == "Count") continue;
                B_nameSpace.AddSubBlock(new SyntaxBlock($"public struct Tag_{enumName} : IComponentData"));
            }
        }

        void GenBuildingUtil(SyntaxBlock B_nameSpace, EnumDeclarationSyntax enumDeclaration)
        {
            var B_buildingUtil = new SyntaxBlock("public static class TypeTagUtil", 5, parent: B_nameSpace);

            var B_getBuildingTag = new SyntaxBlock("public static ComponentType GetBuildingTag(BuildingType buildingType)", 5, parent: B_buildingUtil);

            var B_switch = new SyntaxBlock("return buildingType switch", enumDeclaration.Members.Count, parent: B_getBuildingTag);

            foreach (var member in enumDeclaration.Members)
            {
                var enumName = member.Identifier.Text;
                if (enumName == "None" || enumName == "Count") continue;
                B_switch.AddSubBlock(new SyntaxBlock($"BuildingType.{enumName} => typeof(Tag_{enumName}),", addBracket: false));
            }

            B_switch.AddSubBlock(new SyntaxBlock("_ => throw new System.Exception(\"Invalid BuildingType\")", addBracket: false));
        }
    }

    public class SyntaxBlock
    {
        public string head;
        public bool addBracket;
        public List<SyntaxBlock> subBlock;

        public SyntaxBlock(string head, int capacity = 0, bool addBracket = true, SyntaxBlock parent = null)
        {
            this.head = head;
            if (capacity != 0)
            {
                subBlock = new List<SyntaxBlock>(capacity);
            }

            parent?.AddSubBlock(this);
            this.addBracket = addBracket;
        }

        public void AddSubBlock(SyntaxBlock block)
        {
            if (subBlock == null)
            {
                subBlock = new List<SyntaxBlock>();
            }
            subBlock.Add(block);
        }

        public static void BuildBlockAndClear(ref StringBuilder builder, SyntaxBlock block)
        {
            if (block == null) return;

            builder.AppendLine(block.head);
            if (block.addBracket) builder.AppendLine("{");
            if (block.subBlock != null)
            {
                for (int i = 0; i < block.subBlock.Count; i++)
                {
                    BuildBlockAndClear(ref builder, block.subBlock[i]);
                }

                block.subBlock.Clear();
                block.subBlock = null;
            }
            if (block.addBracket) builder.AppendLine("}");

        }
    }
}

In unity, the BuildingType enum is decorated with the attribute [GenerateTag] to trigger.

    [GenerateTag]
    public enum BuildingType : byte
    {
        None,
        House, Floor, Stair, StructuralFrame, LifeSource,
        WaterPool, Warehouse, Bullpen, WoodFarm, RobberyStartPoint,
        ShipPoint,
        ArcherTower,
        Kitchen, Temple,
        Count
    }

    [AttributeUsage(AttributeTargets.Enum, Inherited = false, AllowMultiple = false)]
    sealed class GenerateTagAttribute : Attribute
    {
        public GenerateTagAttribute() { }
    }

And the generated code looks ok

using Unity.Entities;
namespace CavePeople
{
public struct Tag_House : IComponentData
{
}
public struct Tag_Floor : IComponentData
{
}
public struct Tag_Stair : IComponentData
{
}
public struct Tag_StructuralFrame : IComponentData
{
}
public struct Tag_LifeSource : IComponentData
{
}
public struct Tag_WaterPool : IComponentData
{
}
public struct Tag_Warehouse : IComponentData
{
}
public struct Tag_Bullpen : IComponentData
{
}
public struct Tag_WoodFarm : IComponentData
{
}
public struct Tag_RobberyStartPoint : IComponentData
{
}
public struct Tag_ShipPoint : IComponentData
{
}
public struct Tag_ArcherTower : IComponentData
{
}
public struct Tag_Kitchen : IComponentData
{
}
public struct Tag_Temple : IComponentData
{
}
public static class TypeTagUtil
{
public static ComponentType GetBuildingTag(BuildingType buildingType)
{
return buildingType switch
{
BuildingType.House => typeof(Tag_House),
BuildingType.Floor => typeof(Tag_Floor),
BuildingType.Stair => typeof(Tag_Stair),
BuildingType.StructuralFrame => typeof(Tag_StructuralFrame),
BuildingType.LifeSource => typeof(Tag_LifeSource),
BuildingType.WaterPool => typeof(Tag_WaterPool),
BuildingType.Warehouse => typeof(Tag_Warehouse),
BuildingType.Bullpen => typeof(Tag_Bullpen),
BuildingType.WoodFarm => typeof(Tag_WoodFarm),
BuildingType.RobberyStartPoint => typeof(Tag_RobberyStartPoint),
BuildingType.ShipPoint => typeof(Tag_ShipPoint),
BuildingType.ArcherTower => typeof(Tag_ArcherTower),
BuildingType.Kitchen => typeof(Tag_Kitchen),
BuildingType.Temple => typeof(Tag_Temple),
_ => throw new System.Exception("Invalid BuildingType")
}
}
}
}

But when I use the TypeTagUtil.GetBuildingTag(BuildingType buildingType), it logs the error

 The name 'TypeTagUtil' does not exist in the current context
1 Like

The issue is caused by wrong Microsoft.CodeAnalysis.CSharp version ( I installed 4.13). Unity said we must use 4.3

1 Like