ノートの端の書き残し

UnityやらC#やら。設計が得意かもしれない。

【Unity】エディタ上でだけ編集可能なパラメータ

エディタ上でだけ編集可能にする

「エディタ上で編集不可能にする」ではなく、その逆です。
↓こういうこと

ReadonlyInScript属性が付いたフィールドはインスペクタでは普通に編集できますが、スクリプトで代入しようとするとエラーで怒られます。

ネタバラし

RoslynAnalyzerで書き込みを禁止しているだけです。 以下のような感じで、すごく愚直に。

public override void Initialize(AnalysisContext context)
        {
            // お約束。
            context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
            context.EnableConcurrentExecution();

            // binary assignment expression全部
            var kinds = new SyntaxKind[]
            {
                SyntaxKind.SimpleAssignmentExpression,
                SyntaxKind.AddAssignmentExpression,
                SyntaxKind.SubtractAssignmentExpression,
                SyntaxKind.MultiplyAssignmentExpression,
                SyntaxKind.DivideAssignmentExpression,
                SyntaxKind.ModuloAssignmentExpression,
                SyntaxKind.AndAssignmentExpression,
                SyntaxKind.ExclusiveOrAssignmentExpression,
                SyntaxKind.OrAssignmentExpression,
                SyntaxKind.LeftShiftAssignmentExpression,
                SyntaxKind.RightShiftAssignmentExpression,
                SyntaxKind.CoalesceAssignmentExpression,
                SyntaxKind.PreIncrementExpression,
                SyntaxKind.PreDecrementExpression,
                SyntaxKind.PostIncrementExpression,
                SyntaxKind.PostDecrementExpression
            };
            
            context.RegisterSyntaxNodeAction(AnalyzeSyntax, kinds);
        }

        private static void AnalyzeSyntax(SyntaxNodeAnalysisContext context)
        {
            var syntax = context.Node switch
            {
                AssignmentExpressionSyntax assignExpression => assignExpression.Left,
                PostfixUnaryExpressionSyntax postUnary => postUnary.Operand,
                PrefixUnaryExpressionSyntax preUnary => preUnary.Operand,
                _ => default
            };

            if (syntax == default) return;

            var symbol = context.SemanticModel
                .GetSymbolInfo(syntax, context.CancellationToken)
                .Symbol;

            var result = symbol switch
            {
                IFieldSymbol fieldSymbol
                    => fieldSymbol.GetAttributes()
                        .Any(x => x.AttributeClass.Name.Contains("ReadonlyInScriptAttribute")),
                IPropertySymbol propertySymbol 
                    => IsAutoProperty(propertySymbol) && HasReadonlyAttribute(propertySymbol),
                _ => false,
            };

            if (result)
            {
                // Diagnosticを作ってReportDiagnosticに詰める。
                var diagnostic = Diagnostic.Create(Rule, context.Node.GetLocation());
                context.ReportDiagnostic(diagnostic);
            }

            bool IsAutoProperty(IPropertySymbol propertySymbol)
            {
                var node = propertySymbol.DeclaringSyntaxReferences.First().GetSyntax();
                if (node is not PropertyDeclarationSyntax propertyDeclarationSyntax) return false;
                return propertyDeclarationSyntax.AccessorList.Accessors.All(a => a.Body == null);
            }

            bool HasReadonlyAttribute(IPropertySymbol propertySymbol)
            {
                var node = propertySymbol.DeclaringSyntaxReferences.First().GetSyntax();
                if (node is not PropertyDeclarationSyntax propertyDeclarationSyntax) return false;
                return propertyDeclarationSyntax.DescendantNodes()
                    .OfType<AttributeSyntax>()
                    .Any(a => a.Name.ToString().Contains("ReadonlyInScript"));
            }
        }

飽くまでもコードを分析しているだけなので、エディタからの編集は何も問題無いというわけです。

これの何が嬉しいの?って言われたらわからないですが、 アナライザのコードとdllは以下のリポジトリに公開しています。 github.com

以下のページなどを参考に、dllをポイっとUnityにインポートして、ReadonlyInScriptAtributeって名前の属性を作ればOKです。

docs.unity3d.com