mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-14 19:29:36 +01:00
Refactor serialization copying to use source generators (#4286)
This commit is contained in:
@@ -25,4 +25,7 @@
|
||||
|
||||
<!-- analyzer -->
|
||||
<Import Project="Robust.Analyzers.targets" Condition="'$(SkipRobustAnalyzer)' != 'true'" />
|
||||
|
||||
<!-- serialization generator -->
|
||||
<Import Project="Robust.Serialization.Generator.targets" />
|
||||
</Project>
|
||||
|
||||
5
MSBuild/Robust.Serialization.Generator.targets
Normal file
5
MSBuild/Robust.Serialization.Generator.targets
Normal file
@@ -0,0 +1,5 @@
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="12.0">
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="$(MSBuildThisFileDirectory)\..\Robust.Serialization.Generator\Robust.Serialization.Generator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false"/>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
293
Robust.Analyzers/DataDefinitionAnalyzer.cs
Normal file
293
Robust.Analyzers/DataDefinitionAnalyzer.cs
Normal file
@@ -0,0 +1,293 @@
|
||||
#nullable enable
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Microsoft.CodeAnalysis.Diagnostics;
|
||||
|
||||
namespace Robust.Analyzers;
|
||||
|
||||
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
||||
public sealed class DataDefinitionAnalyzer : DiagnosticAnalyzer
|
||||
{
|
||||
private const string DataDefinitionNamespace = "Robust.Shared.Serialization.Manager.Attributes.DataDefinitionAttribute";
|
||||
private const string ImplicitDataDefinitionNamespace = "Robust.Shared.Serialization.Manager.Attributes.ImplicitDataDefinitionForInheritorsAttribute";
|
||||
private const string DataFieldBaseNamespace = "Robust.Shared.Serialization.Manager.Attributes.DataFieldBaseAttribute";
|
||||
|
||||
private static readonly DiagnosticDescriptor DataDefinitionPartialRule = new(
|
||||
Diagnostics.IdDataDefinitionPartial,
|
||||
"Type must be partial",
|
||||
"Type {0} is a DataDefinition but is not partial.",
|
||||
"Usage",
|
||||
DiagnosticSeverity.Error,
|
||||
true,
|
||||
"Make sure to mark any type that is a data definition as partial."
|
||||
);
|
||||
|
||||
private static readonly DiagnosticDescriptor NestedDataDefinitionPartialRule = new(
|
||||
Diagnostics.IdNestedDataDefinitionPartial,
|
||||
"Type must be partial",
|
||||
"Type {0} contains nested data definition {1} but is not partial.",
|
||||
"Usage",
|
||||
DiagnosticSeverity.Error,
|
||||
true,
|
||||
"Make sure to mark any type containing a nested data definition as partial."
|
||||
);
|
||||
|
||||
private static readonly DiagnosticDescriptor DataFieldWritableRule = new(
|
||||
Diagnostics.IdDataFieldWritable,
|
||||
"Data field must not be readonly",
|
||||
"Data field {0} in data definition {1} is readonly.",
|
||||
"Usage",
|
||||
DiagnosticSeverity.Error,
|
||||
true,
|
||||
"Make sure to remove the readonly modifier."
|
||||
);
|
||||
|
||||
private static readonly DiagnosticDescriptor DataFieldPropertyWritableRule = new(
|
||||
Diagnostics.IdDataFieldPropertyWritable,
|
||||
"Data field property must have a setter",
|
||||
"Data field property {0} in data definition {1} does not have a setter.",
|
||||
"Usage",
|
||||
DiagnosticSeverity.Error,
|
||||
true,
|
||||
"Make sure to add a setter."
|
||||
);
|
||||
|
||||
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(
|
||||
DataDefinitionPartialRule, NestedDataDefinitionPartialRule, DataFieldWritableRule, DataFieldPropertyWritableRule
|
||||
);
|
||||
|
||||
public override void Initialize(AnalysisContext context)
|
||||
{
|
||||
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.None);
|
||||
context.EnableConcurrentExecution();
|
||||
|
||||
context.RegisterSyntaxNodeAction(AnalyzeDataDefinition, SyntaxKind.ClassDeclaration);
|
||||
context.RegisterSyntaxNodeAction(AnalyzeDataDefinition, SyntaxKind.StructDeclaration);
|
||||
context.RegisterSyntaxNodeAction(AnalyzeDataDefinition, SyntaxKind.RecordDeclaration);
|
||||
context.RegisterSyntaxNodeAction(AnalyzeDataDefinition, SyntaxKind.RecordStructDeclaration);
|
||||
context.RegisterSyntaxNodeAction(AnalyzeDataDefinition, SyntaxKind.InterfaceDeclaration);
|
||||
|
||||
context.RegisterSyntaxNodeAction(AnalyzeDataField, SyntaxKind.FieldDeclaration);
|
||||
context.RegisterSyntaxNodeAction(AnalyzeDataFieldProperty, SyntaxKind.PropertyDeclaration);
|
||||
}
|
||||
|
||||
private void AnalyzeDataDefinition(SyntaxNodeAnalysisContext context)
|
||||
{
|
||||
if (context.Node is not TypeDeclarationSyntax declaration)
|
||||
return;
|
||||
|
||||
var type = context.SemanticModel.GetDeclaredSymbol(declaration)!;
|
||||
if (!IsDataDefinition(type))
|
||||
return;
|
||||
|
||||
if (!IsPartial(declaration))
|
||||
{
|
||||
context.ReportDiagnostic(Diagnostic.Create(DataDefinitionPartialRule, declaration.Keyword.GetLocation(), type.Name));
|
||||
}
|
||||
|
||||
var containingType = type.ContainingType;
|
||||
while (containingType != null)
|
||||
{
|
||||
var containingTypeDeclaration = (TypeDeclarationSyntax) containingType.DeclaringSyntaxReferences[0].GetSyntax();
|
||||
if (!IsPartial(containingTypeDeclaration))
|
||||
{
|
||||
context.ReportDiagnostic(Diagnostic.Create(NestedDataDefinitionPartialRule, containingTypeDeclaration.Keyword.GetLocation(), containingType.Name, type.Name));
|
||||
}
|
||||
|
||||
containingType = containingType.ContainingType;
|
||||
}
|
||||
}
|
||||
|
||||
private void AnalyzeDataField(SyntaxNodeAnalysisContext context)
|
||||
{
|
||||
if (context.Node is not FieldDeclarationSyntax field)
|
||||
return;
|
||||
|
||||
var typeDeclaration = field.FirstAncestorOrSelf<TypeDeclarationSyntax>();
|
||||
if (typeDeclaration == null)
|
||||
return;
|
||||
|
||||
var type = context.SemanticModel.GetDeclaredSymbol(typeDeclaration)!;
|
||||
if (!IsDataDefinition(type))
|
||||
return;
|
||||
|
||||
foreach (var variable in field.Declaration.Variables)
|
||||
{
|
||||
var fieldSymbol = context.SemanticModel.GetDeclaredSymbol(variable);
|
||||
if (fieldSymbol == null)
|
||||
continue;
|
||||
|
||||
if (IsReadOnlyDataField(type, fieldSymbol))
|
||||
{
|
||||
context.ReportDiagnostic(Diagnostic.Create(DataFieldWritableRule, context.Node.GetLocation(), fieldSymbol.Name, type.Name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void AnalyzeDataFieldProperty(SyntaxNodeAnalysisContext context)
|
||||
{
|
||||
if (context.Node is not PropertyDeclarationSyntax property)
|
||||
return;
|
||||
|
||||
var typeDeclaration = property.FirstAncestorOrSelf<TypeDeclarationSyntax>();
|
||||
if (typeDeclaration == null)
|
||||
return;
|
||||
|
||||
var type = context.SemanticModel.GetDeclaredSymbol(typeDeclaration)!;
|
||||
if (!IsDataDefinition(type) || type.IsRecord || type.IsValueType)
|
||||
return;
|
||||
|
||||
var propertySymbol = context.SemanticModel.GetDeclaredSymbol(property);
|
||||
if (propertySymbol == null)
|
||||
return;
|
||||
|
||||
if (IsReadOnlyDataField(type, propertySymbol))
|
||||
{
|
||||
context.ReportDiagnostic(Diagnostic.Create(DataFieldPropertyWritableRule, context.Node.GetLocation(), propertySymbol.Name, type.Name));
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsReadOnlyDataField(ITypeSymbol type, ISymbol field)
|
||||
{
|
||||
if (!IsDataField(field, out _, out _))
|
||||
return false;
|
||||
|
||||
return IsReadOnlyMember(type, field);
|
||||
}
|
||||
|
||||
private static bool IsPartial(TypeDeclarationSyntax type)
|
||||
{
|
||||
return type.Modifiers.IndexOf(SyntaxKind.PartialKeyword) != -1;
|
||||
}
|
||||
|
||||
private static bool IsDataDefinition(ITypeSymbol? type)
|
||||
{
|
||||
if (type == null)
|
||||
return false;
|
||||
|
||||
return HasAttribute(type, DataDefinitionNamespace) ||
|
||||
IsImplicitDataDefinition(type);
|
||||
}
|
||||
|
||||
private static bool IsDataField(ISymbol member, out ITypeSymbol type, out AttributeData attribute)
|
||||
{
|
||||
// TODO data records and other attributes
|
||||
if (member is IFieldSymbol field)
|
||||
{
|
||||
foreach (var attr in field.GetAttributes())
|
||||
{
|
||||
if (attr.AttributeClass != null && Inherits(attr.AttributeClass, DataFieldBaseNamespace))
|
||||
{
|
||||
type = field.Type;
|
||||
attribute = attr;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (member is IPropertySymbol property)
|
||||
{
|
||||
foreach (var attr in property.GetAttributes())
|
||||
{
|
||||
if (attr.AttributeClass != null && Inherits(attr.AttributeClass, DataFieldBaseNamespace))
|
||||
{
|
||||
type = property.Type;
|
||||
attribute = attr;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type = null!;
|
||||
attribute = null!;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool Inherits(ITypeSymbol type, string parent)
|
||||
{
|
||||
foreach (var baseType in GetBaseTypes(type))
|
||||
{
|
||||
if (baseType.ToDisplayString() == parent)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool IsReadOnlyMember(ITypeSymbol type, ISymbol member)
|
||||
{
|
||||
if (member is IFieldSymbol field)
|
||||
{
|
||||
return field.IsReadOnly;
|
||||
}
|
||||
else if (member is IPropertySymbol property)
|
||||
{
|
||||
if (property.SetMethod == null)
|
||||
return true;
|
||||
|
||||
if (property.SetMethod.IsInitOnly)
|
||||
return type.IsReferenceType;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool HasAttribute(ITypeSymbol type, string attributeName)
|
||||
{
|
||||
foreach (var attribute in type.GetAttributes())
|
||||
{
|
||||
if (attribute.AttributeClass?.ToDisplayString() == attributeName)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool IsImplicitDataDefinition(ITypeSymbol type)
|
||||
{
|
||||
if (HasAttribute(type, ImplicitDataDefinitionNamespace))
|
||||
return true;
|
||||
|
||||
foreach (var baseType in GetBaseTypes(type))
|
||||
{
|
||||
if (HasAttribute(baseType, ImplicitDataDefinitionNamespace))
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach (var @interface in type.AllInterfaces)
|
||||
{
|
||||
if (IsImplicitDataDefinitionInterface(@interface))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool IsImplicitDataDefinitionInterface(ITypeSymbol @interface)
|
||||
{
|
||||
if (HasAttribute(@interface, ImplicitDataDefinitionNamespace))
|
||||
return true;
|
||||
|
||||
foreach (var subInterface in @interface.AllInterfaces)
|
||||
{
|
||||
if (HasAttribute(subInterface, ImplicitDataDefinitionNamespace))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static IEnumerable<ITypeSymbol> GetBaseTypes(ITypeSymbol type)
|
||||
{
|
||||
var baseType = type.BaseType;
|
||||
while (baseType != null)
|
||||
{
|
||||
yield return baseType;
|
||||
baseType = baseType.BaseType;
|
||||
}
|
||||
}
|
||||
}
|
||||
168
Robust.Analyzers/DataDefinitionFixer.cs
Normal file
168
Robust.Analyzers/DataDefinitionFixer.cs
Normal file
@@ -0,0 +1,168 @@
|
||||
#nullable enable
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CodeActions;
|
||||
using Microsoft.CodeAnalysis.CodeFixes;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using static Microsoft.CodeAnalysis.CSharp.SyntaxKind;
|
||||
using static Robust.Analyzers.Diagnostics;
|
||||
|
||||
namespace Robust.Analyzers;
|
||||
|
||||
[ExportCodeFixProvider(LanguageNames.CSharp)]
|
||||
public sealed class DefinitionFixer : CodeFixProvider
|
||||
{
|
||||
public override ImmutableArray<string> FixableDiagnosticIds => ImmutableArray.Create(
|
||||
IdDataDefinitionPartial, IdNestedDataDefinitionPartial, IdDataFieldWritable, IdDataFieldPropertyWritable
|
||||
);
|
||||
|
||||
public override Task RegisterCodeFixesAsync(CodeFixContext context)
|
||||
{
|
||||
foreach (var diagnostic in context.Diagnostics)
|
||||
{
|
||||
switch (diagnostic.Id)
|
||||
{
|
||||
case IdDataDefinitionPartial:
|
||||
return RegisterPartialTypeFix(context, diagnostic);
|
||||
case IdNestedDataDefinitionPartial:
|
||||
return RegisterPartialTypeFix(context, diagnostic);
|
||||
case IdDataFieldWritable:
|
||||
return RegisterDataFieldFix(context, diagnostic);
|
||||
case IdDataFieldPropertyWritable:
|
||||
return RegisterDataFieldPropertyFix(context, diagnostic);
|
||||
}
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public override FixAllProvider GetFixAllProvider()
|
||||
{
|
||||
return WellKnownFixAllProviders.BatchFixer;
|
||||
}
|
||||
|
||||
private static async Task RegisterPartialTypeFix(CodeFixContext context, Diagnostic diagnostic)
|
||||
{
|
||||
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken);
|
||||
var span = diagnostic.Location.SourceSpan;
|
||||
var token = root?.FindToken(span.Start).Parent?.AncestorsAndSelf().OfType<TypeDeclarationSyntax>().First();
|
||||
|
||||
if (token == null)
|
||||
return;
|
||||
|
||||
context.RegisterCodeFix(CodeAction.Create(
|
||||
"Make type partial",
|
||||
c => MakeDataDefinitionPartial(context.Document, token, c),
|
||||
"Make type partial"
|
||||
), diagnostic);
|
||||
}
|
||||
|
||||
private static async Task<Document> MakeDataDefinitionPartial(Document document, TypeDeclarationSyntax declaration, CancellationToken cancellation)
|
||||
{
|
||||
var root = (CompilationUnitSyntax?) await document.GetSyntaxRootAsync(cancellation);
|
||||
var token = SyntaxFactory.Token(PartialKeyword);
|
||||
var newDeclaration = declaration.AddModifiers(token);
|
||||
|
||||
root = root!.ReplaceNode(declaration, newDeclaration);
|
||||
|
||||
return document.WithSyntaxRoot(root);
|
||||
}
|
||||
|
||||
private static async Task RegisterDataFieldFix(CodeFixContext context, Diagnostic diagnostic)
|
||||
{
|
||||
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken);
|
||||
var span = diagnostic.Location.SourceSpan;
|
||||
var field = root?.FindToken(span.Start).Parent?.AncestorsAndSelf().OfType<FieldDeclarationSyntax>().FirstOrDefault();
|
||||
|
||||
if (field == null)
|
||||
return;
|
||||
|
||||
context.RegisterCodeFix(CodeAction.Create(
|
||||
"Make data field writable",
|
||||
c => MakeFieldWritable(context.Document, field, c),
|
||||
"Make data field writable"
|
||||
), diagnostic);
|
||||
}
|
||||
|
||||
private static async Task RegisterDataFieldPropertyFix(CodeFixContext context, Diagnostic diagnostic)
|
||||
{
|
||||
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken);
|
||||
var span = diagnostic.Location.SourceSpan;
|
||||
var property = root?.FindToken(span.Start).Parent?.AncestorsAndSelf().OfType<PropertyDeclarationSyntax>().FirstOrDefault();
|
||||
|
||||
if (property == null)
|
||||
return;
|
||||
|
||||
context.RegisterCodeFix(CodeAction.Create(
|
||||
"Make data field writable",
|
||||
c => MakePropertyWritable(context.Document, property, c),
|
||||
"Make data field writable"
|
||||
), diagnostic);
|
||||
}
|
||||
|
||||
private static async Task<Document> MakeFieldWritable(Document document, FieldDeclarationSyntax declaration, CancellationToken cancellation)
|
||||
{
|
||||
var root = (CompilationUnitSyntax?) await document.GetSyntaxRootAsync(cancellation);
|
||||
var token = declaration.Modifiers.First(t => t.IsKind(ReadOnlyKeyword));
|
||||
var newDeclaration = declaration.WithModifiers(declaration.Modifiers.Remove(token));
|
||||
|
||||
root = root!.ReplaceNode(declaration, newDeclaration);
|
||||
|
||||
return document.WithSyntaxRoot(root);
|
||||
}
|
||||
|
||||
private static async Task<Document> MakePropertyWritable(Document document, PropertyDeclarationSyntax declaration, CancellationToken cancellation)
|
||||
{
|
||||
var root = (CompilationUnitSyntax?) await document.GetSyntaxRootAsync(cancellation);
|
||||
var newDeclaration = declaration;
|
||||
var privateSet = newDeclaration
|
||||
.AccessorList?
|
||||
.Accessors
|
||||
.FirstOrDefault(s => s.IsKind(SetAccessorDeclaration) || s.IsKind(InitAccessorDeclaration));
|
||||
|
||||
if (newDeclaration.AccessorList != null && privateSet != null)
|
||||
{
|
||||
newDeclaration = newDeclaration.WithAccessorList(
|
||||
newDeclaration.AccessorList.WithAccessors(
|
||||
newDeclaration.AccessorList.Accessors.Remove(privateSet)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
AccessorDeclarationSyntax setter;
|
||||
if (declaration.Modifiers.Any(m => m.IsKind(PrivateKeyword)))
|
||||
{
|
||||
setter = SyntaxFactory.AccessorDeclaration(
|
||||
SetAccessorDeclaration,
|
||||
default,
|
||||
default,
|
||||
SyntaxFactory.Token(SetKeyword),
|
||||
default,
|
||||
default,
|
||||
SyntaxFactory.Token(SemicolonToken)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
setter = SyntaxFactory.AccessorDeclaration(
|
||||
SetAccessorDeclaration,
|
||||
default,
|
||||
SyntaxFactory.TokenList(SyntaxFactory.Token(PrivateKeyword)),
|
||||
SyntaxFactory.Token(SetKeyword),
|
||||
default,
|
||||
default,
|
||||
SyntaxFactory.Token(SemicolonToken)
|
||||
);
|
||||
}
|
||||
|
||||
newDeclaration = newDeclaration.AddAccessorListAccessors(setter);
|
||||
|
||||
root = root!.ReplaceNode(declaration, newDeclaration);
|
||||
|
||||
return document.WithSyntaxRoot(root);
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,10 @@ public static class Diagnostics
|
||||
public const string IdValueEventSubscribedByRef = "RA0014";
|
||||
public const string IdByRefEventRaisedByValue = "RA0015";
|
||||
public const string IdValueEventRaisedByRef = "RA0016";
|
||||
public const string IdDataDefinitionPartial = "RA0017";
|
||||
public const string IdNestedDataDefinitionPartial = "RA0018";
|
||||
public const string IdDataFieldWritable = "RA0019";
|
||||
public const string IdDataFieldPropertyWritable = "RA0020";
|
||||
|
||||
public static SuppressionDescriptor MeansImplicitAssignment =>
|
||||
new SuppressionDescriptor("RADC1000", "CS0649", "Marked as implicitly assigned.");
|
||||
|
||||
@@ -8,7 +8,7 @@ using Robust.UnitTesting.Server;
|
||||
namespace Robust.Benchmarks.EntityManager;
|
||||
|
||||
[Virtual]
|
||||
public class AddRemoveComponentBenchmark
|
||||
public partial class AddRemoveComponentBenchmark
|
||||
{
|
||||
private ISimulation _simulation = default!;
|
||||
private IEntityManager _entityManager = default!;
|
||||
@@ -48,7 +48,7 @@ public class AddRemoveComponentBenchmark
|
||||
}
|
||||
|
||||
[ComponentProtoName("A")]
|
||||
public sealed class A : Component
|
||||
public sealed partial class A : Component
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ using Robust.UnitTesting.Server;
|
||||
|
||||
namespace Robust.Benchmarks.EntityManager;
|
||||
|
||||
public class ComponentIteratorBenchmark
|
||||
public partial class ComponentIteratorBenchmark
|
||||
{
|
||||
private ISimulation _simulation = default!;
|
||||
private IEntityManager _entityManager = default!;
|
||||
@@ -69,7 +69,7 @@ public class ComponentIteratorBenchmark
|
||||
}
|
||||
|
||||
[ComponentProtoName("A")]
|
||||
public sealed class A : Component
|
||||
public sealed partial class A : Component
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using System;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Analyzers;
|
||||
@@ -9,7 +8,7 @@ using Robust.UnitTesting.Server;
|
||||
namespace Robust.Benchmarks.EntityManager;
|
||||
|
||||
[Virtual]
|
||||
public class GetComponentBenchmark
|
||||
public partial class GetComponentBenchmark
|
||||
{
|
||||
private ISimulation _simulation = default!;
|
||||
private IEntityManager _entityManager = default!;
|
||||
@@ -55,7 +54,7 @@ public class GetComponentBenchmark
|
||||
}
|
||||
|
||||
[ComponentProtoName("A")]
|
||||
public sealed class A : Component
|
||||
public sealed partial class A : Component
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ using Robust.UnitTesting.Server;
|
||||
namespace Robust.Benchmarks.EntityManager;
|
||||
|
||||
[Virtual]
|
||||
public class SpawnDeleteEntityBenchmark
|
||||
public partial class SpawnDeleteEntityBenchmark
|
||||
{
|
||||
private ISimulation _simulation = default!;
|
||||
private IEntityManager _entityManager = default!;
|
||||
@@ -56,7 +56,7 @@ public class SpawnDeleteEntityBenchmark
|
||||
}
|
||||
|
||||
[ComponentProtoName("A")]
|
||||
public sealed class A : Component
|
||||
public sealed partial class A : Component
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,9 +5,9 @@ namespace Robust.Benchmarks.Serialization.Definitions
|
||||
{
|
||||
[DataDefinition]
|
||||
[Virtual]
|
||||
public class DataDefinitionWithString
|
||||
public partial class DataDefinitionWithString
|
||||
{
|
||||
[DataField("string")]
|
||||
public string StringField { get; init; } = default!;
|
||||
public string StringField { get; set; } = default!;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
namespace Robust.Benchmarks.Serialization.Definitions
|
||||
{
|
||||
[DataDefinition]
|
||||
public sealed class SealedDataDefinitionWithString
|
||||
public sealed partial class SealedDataDefinitionWithString
|
||||
{
|
||||
[DataField("string")]
|
||||
public string StringField { get; init; } = default!;
|
||||
public string StringField { get; private set; } = default!;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
@@ -10,8 +11,7 @@ namespace Robust.Benchmarks.Serialization.Definitions
|
||||
/// Arbitrarily large data definition for benchmarks.
|
||||
/// Taken from content.
|
||||
/// </summary>
|
||||
[Prototype("seed")]
|
||||
public sealed class SeedDataDefinition : IPrototype
|
||||
public sealed partial class SeedDataDefinition : Component
|
||||
{
|
||||
public const string Prototype = @"
|
||||
- type: seed
|
||||
@@ -106,7 +106,7 @@ namespace Robust.Benchmarks.Serialization.Definitions
|
||||
}
|
||||
|
||||
[DataDefinition]
|
||||
public struct SeedChemQuantity
|
||||
public partial struct SeedChemQuantity
|
||||
{
|
||||
[DataField("Min")]
|
||||
public int Min;
|
||||
|
||||
@@ -6,7 +6,7 @@ using Robust.Shared.Physics;
|
||||
namespace Robust.Client.ComponentTrees;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed class LightTreeComponent: Component, IComponentTreeComponent<PointLightComponent>
|
||||
public sealed partial class LightTreeComponent: Component, IComponentTreeComponent<PointLightComponent>
|
||||
{
|
||||
public DynamicTree<ComponentTreeEntry<PointLightComponent>> Tree { get; set; } = default!;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ using Robust.Shared.Physics;
|
||||
namespace Robust.Client.ComponentTrees;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed class SpriteTreeComponent: Component, IComponentTreeComponent<SpriteComponent>
|
||||
public sealed partial class SpriteTreeComponent: Component, IComponentTreeComponent<SpriteComponent>
|
||||
{
|
||||
public DynamicTree<ComponentTreeEntry<SpriteComponent>> Tree { get; set; } = default!;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Robust.Client.GameObjects
|
||||
/// Plays back <see cref="Animation"/>s on entities.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed class AnimationPlayerComponent : Component
|
||||
public sealed partial class AnimationPlayerComponent : Component
|
||||
{
|
||||
// TODO: Give this component a friend someday. Way too much content shit to change atm ._.
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Robust.Client.GameObjects;
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
[Access(typeof(GenericVisualizerSystem))]
|
||||
public sealed class GenericVisualizerComponent : Component
|
||||
public sealed partial class GenericVisualizerComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// This is a nested dictionary that maps appearance data keys -> sprite layer keys -> appearance data values -> layer data.
|
||||
|
||||
@@ -10,7 +10,7 @@ using Robust.Shared.ViewVariables;
|
||||
namespace Robust.Client.GameObjects
|
||||
{
|
||||
[RegisterComponent, ComponentReference(typeof(SharedEyeComponent))]
|
||||
public sealed class EyeComponent : SharedEyeComponent
|
||||
public sealed partial class EyeComponent : SharedEyeComponent
|
||||
{
|
||||
[Dependency] private readonly IEyeManager _eyeManager = default!;
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
|
||||
@@ -16,8 +16,8 @@ namespace Robust.Client.GameObjects;
|
||||
/// updated.
|
||||
/// </remarks>
|
||||
[RegisterComponent]
|
||||
public sealed class IconComponent : Component
|
||||
public sealed partial class IconComponent : Component
|
||||
{
|
||||
[IncludeDataField]
|
||||
public readonly SpriteSpecifier.Rsi Icon = default!;
|
||||
public SpriteSpecifier.Rsi Icon = default!;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Robust.Client.GameObjects
|
||||
/// Defines data fields used in the <see cref="InputSystem"/>.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed class InputComponent : Component
|
||||
public sealed partial class InputComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// The context that will be made active for a client that attaches to this entity.
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Robust.Client.GameObjects
|
||||
{
|
||||
[RegisterComponent]
|
||||
[ComponentReference(typeof(SharedPointLightComponent))]
|
||||
public sealed class PointLightComponent : SharedPointLightComponent, IComponentTreeEntry<PointLightComponent>
|
||||
public sealed partial class PointLightComponent : SharedPointLightComponent, IComponentTreeEntry<PointLightComponent>
|
||||
{
|
||||
public EntityUid? TreeUid { get; set; }
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ using Robust.Shared.Maths;
|
||||
|
||||
namespace Robust.Client.GameObjects
|
||||
{
|
||||
public interface IRenderableComponent : IComponent
|
||||
public partial interface IRenderableComponent : IComponent
|
||||
{
|
||||
int DrawDepth { get; set; }
|
||||
float Bottom { get; }
|
||||
|
||||
@@ -32,7 +32,7 @@ using static Robust.Shared.Serialization.TypeSerializers.Implementations.SpriteS
|
||||
namespace Robust.Client.GameObjects
|
||||
{
|
||||
[RegisterComponent]
|
||||
public sealed class SpriteComponent : Component, IComponentDebug, ISerializationHooks, IComponentTreeEntry<SpriteComponent>, IAnimationProperties
|
||||
public sealed partial class SpriteComponent : Component, IComponentDebug, ISerializationHooks, IComponentTreeEntry<SpriteComponent>, IAnimationProperties
|
||||
{
|
||||
[Dependency] private readonly IResourceCache resourceCache = default!;
|
||||
[Dependency] private readonly IPrototypeManager prototypes = default!;
|
||||
|
||||
@@ -7,7 +7,7 @@ using Robust.Shared.ViewVariables;
|
||||
namespace Robust.Client.GameObjects
|
||||
{
|
||||
[RegisterComponent, ComponentReference(typeof(SharedUserInterfaceComponent))]
|
||||
public sealed class ClientUserInterfaceComponent : SharedUserInterfaceComponent
|
||||
public sealed partial class ClientUserInterfaceComponent : SharedUserInterfaceComponent
|
||||
{
|
||||
[ViewVariables]
|
||||
internal readonly Dictionary<Enum, PrototypeData> _interfaces = new();
|
||||
|
||||
@@ -225,7 +225,7 @@ namespace Robust.Client.Graphics
|
||||
}
|
||||
|
||||
[DataDefinition]
|
||||
public struct StencilParameters
|
||||
public partial struct StencilParameters
|
||||
{
|
||||
public StencilParameters()
|
||||
{
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace Robust.Client.Graphics
|
||||
{
|
||||
[ViewVariables]
|
||||
[IdDataField]
|
||||
public string ID { get; } = default!;
|
||||
public string ID { get; private set; } = default!;
|
||||
|
||||
[ViewVariables] private ShaderKind Kind;
|
||||
[ViewVariables] private Dictionary<string, object>? _params;
|
||||
@@ -95,19 +95,19 @@ namespace Robust.Client.Graphics
|
||||
}
|
||||
|
||||
[DataField("kind", required: true)]
|
||||
private readonly string _rawKind = default!;
|
||||
private string _rawKind = default!;
|
||||
|
||||
[DataField("path")]
|
||||
private readonly ResPath? _path;
|
||||
private ResPath? _path;
|
||||
|
||||
[DataField("params")]
|
||||
private readonly Dictionary<string, string>? _paramMapping;
|
||||
private Dictionary<string, string>? _paramMapping;
|
||||
|
||||
[DataField("light_mode")]
|
||||
private readonly string? _rawMode;
|
||||
private string? _rawMode;
|
||||
|
||||
[DataField("blend_mode")]
|
||||
private readonly string? _rawBlendMode;
|
||||
private string? _rawBlendMode;
|
||||
|
||||
void ISerializationHooks.AfterDeserialization()
|
||||
{
|
||||
|
||||
@@ -4,7 +4,7 @@ using Robust.Shared.Serialization.Manager.Attributes;
|
||||
namespace Robust.Client.Input
|
||||
{
|
||||
[DataDefinition]
|
||||
public sealed class KeyBindingRegistration
|
||||
public sealed partial class KeyBindingRegistration
|
||||
{
|
||||
[DataField("function")]
|
||||
public BoundKeyFunction Function;
|
||||
|
||||
@@ -6,6 +6,6 @@ namespace Robust.Client.Physics;
|
||||
/// Simple component used to tag entities that have physics prediction enabled.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed class PredictedPhysicsComponent : Component
|
||||
public sealed partial class PredictedPhysicsComponent : Component
|
||||
{
|
||||
}
|
||||
|
||||
@@ -8,8 +8,8 @@ namespace Robust.Client.UserInterface.RichText;
|
||||
public sealed class FontPrototype : IPrototype
|
||||
{
|
||||
[IdDataField]
|
||||
public string ID { get; } = default!;
|
||||
public string ID { get; private set; } = default!;
|
||||
|
||||
[DataField("path", required: true)]
|
||||
public ResPath Path { get; } = default!;
|
||||
public ResPath Path { get; private set; } = default!;
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ public sealed class UITheme : IPrototype
|
||||
|
||||
[ViewVariables]
|
||||
[IdDataField]
|
||||
public string ID { get; } = default!;
|
||||
public string ID { get; private set; } = default!;
|
||||
|
||||
[DataField("path")]
|
||||
private ResPath _path;
|
||||
@@ -70,7 +70,7 @@ public sealed class UITheme : IPrototype
|
||||
|
||||
if (!texturePath.EndsWith(".png"))
|
||||
texturePath = $"{texturePath}.png";
|
||||
|
||||
|
||||
var resPath = new ResPath(texturePath);
|
||||
if (resPath.IsRelative)
|
||||
{
|
||||
|
||||
6
Robust.Serialization.Generator/DataDefinition.cs
Normal file
6
Robust.Serialization.Generator/DataDefinition.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace Robust.Serialization.Generator;
|
||||
|
||||
public sealed record DataDefinition(ITypeSymbol Type, string GenericTypeName, List<DataField> Fields, bool HasHooks, bool InvalidFields);
|
||||
17
Robust.Serialization.Generator/DataDefinitionComparer.cs
Normal file
17
Robust.Serialization.Generator/DataDefinitionComparer.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
|
||||
namespace Robust.Serialization.Generator;
|
||||
|
||||
public sealed class DataDefinitionComparer : IEqualityComparer<TypeDeclarationSyntax>
|
||||
{
|
||||
public bool Equals(TypeDeclarationSyntax x, TypeDeclarationSyntax y)
|
||||
{
|
||||
return x.Equals(y);
|
||||
}
|
||||
|
||||
public int GetHashCode(TypeDeclarationSyntax type)
|
||||
{
|
||||
return type.GetHashCode();
|
||||
}
|
||||
}
|
||||
14
Robust.Serialization.Generator/DataField.cs
Normal file
14
Robust.Serialization.Generator/DataField.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace Robust.Serialization.Generator;
|
||||
|
||||
public sealed record DataField(
|
||||
ISymbol Symbol,
|
||||
ITypeSymbol Type,
|
||||
(INamedTypeSymbol Serializer, CustomSerializerType Type)? CustomSerializer);
|
||||
|
||||
public enum CustomSerializerType
|
||||
{
|
||||
Copier,
|
||||
CopyCreator
|
||||
}
|
||||
534
Robust.Serialization.Generator/Generator.cs
Normal file
534
Robust.Serialization.Generator/Generator.cs
Normal file
@@ -0,0 +1,534 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using static Robust.Serialization.Generator.CustomSerializerType;
|
||||
using static Robust.Serialization.Generator.Types;
|
||||
|
||||
namespace Robust.Serialization.Generator;
|
||||
|
||||
[Generator]
|
||||
public class Generator : IIncrementalGenerator
|
||||
{
|
||||
private const string TypeCopierInterfaceNamespace = "Robust.Shared.Serialization.TypeSerializers.Interfaces.ITypeCopier";
|
||||
private const string TypeCopyCreatorInterfaceNamespace = "Robust.Shared.Serialization.TypeSerializers.Interfaces.ITypeCopyCreator";
|
||||
private const string SerializationHooksNamespace = "Robust.Shared.Serialization.ISerializationHooks";
|
||||
|
||||
public void Initialize(IncrementalGeneratorInitializationContext initContext)
|
||||
{
|
||||
IncrementalValuesProvider<TypeDeclarationSyntax> dataDefinitions = initContext.SyntaxProvider.CreateSyntaxProvider(
|
||||
static (node, _) => node is TypeDeclarationSyntax,
|
||||
static (context, _) =>
|
||||
{
|
||||
var type = (TypeDeclarationSyntax) context.Node;
|
||||
var symbol = (ITypeSymbol) context.SemanticModel.GetDeclaredSymbol(type)!;
|
||||
return IsDataDefinition(symbol) ? type : null;
|
||||
}
|
||||
).Where(static type => type != null)!;
|
||||
|
||||
var comparer = new DataDefinitionComparer();
|
||||
initContext.RegisterSourceOutput(
|
||||
initContext.CompilationProvider.Combine(dataDefinitions.WithComparer(comparer).Collect()),
|
||||
static (sourceContext, source) =>
|
||||
{
|
||||
var (compilation, declarations) = source;
|
||||
var builder = new StringBuilder();
|
||||
var containingTypes = new Stack<INamedTypeSymbol>();
|
||||
|
||||
foreach (var declaration in declarations)
|
||||
{
|
||||
builder.Clear();
|
||||
containingTypes.Clear();
|
||||
|
||||
var type = compilation.GetSemanticModel(declaration.SyntaxTree).GetDeclaredSymbol(declaration)!;
|
||||
|
||||
var nonPartial = !IsPartial(declaration);
|
||||
|
||||
var namespaceString = type.ContainingNamespace.IsGlobalNamespace
|
||||
? string.Empty
|
||||
: $"namespace {type.ContainingNamespace.ToDisplayString()};";
|
||||
|
||||
var containingType = type.ContainingType;
|
||||
while (containingType != null)
|
||||
{
|
||||
containingTypes.Push(containingType);
|
||||
containingType = containingType.ContainingType;
|
||||
}
|
||||
|
||||
var containingTypesStart = new StringBuilder();
|
||||
var containingTypesEnd = new StringBuilder();
|
||||
foreach (var parent in containingTypes)
|
||||
{
|
||||
var syntax = (ClassDeclarationSyntax) parent.DeclaringSyntaxReferences[0].GetSyntax();
|
||||
if (!IsPartial(syntax))
|
||||
{
|
||||
nonPartial = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
containingTypesStart.AppendLine($"{GetPartialTypeDefinitionLine(parent)}\n{{");
|
||||
containingTypesEnd.AppendLine("}");
|
||||
}
|
||||
|
||||
var definition = GetDataDefinition(type);
|
||||
if (nonPartial || definition.InvalidFields)
|
||||
continue;
|
||||
|
||||
builder.AppendLine($$"""
|
||||
#nullable enable
|
||||
using System;
|
||||
using Robust.Shared.Analyzers;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Serialization.Manager;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Interfaces;
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
|
||||
{{namespaceString}}
|
||||
|
||||
{{containingTypesStart}}
|
||||
|
||||
[RobustAutoGenerated]
|
||||
{{GetPartialTypeDefinitionLine(type)}} : ISerializationGenerated<{{definition.GenericTypeName}}>
|
||||
{
|
||||
{{GetConstructor(definition)}}
|
||||
|
||||
{{GetCopyMethods(definition)}}
|
||||
|
||||
{{GetInstantiators(definition)}}
|
||||
}
|
||||
|
||||
{{containingTypesEnd}}
|
||||
""");
|
||||
|
||||
var symbolName = type
|
||||
.ToDisplayString()
|
||||
.Replace('<', '{')
|
||||
.Replace('>', '}');
|
||||
|
||||
var sourceText = CSharpSyntaxTree
|
||||
.ParseText(builder.ToString())
|
||||
.GetRoot()
|
||||
.NormalizeWhitespace()
|
||||
.ToFullString();
|
||||
|
||||
sourceContext.AddSource($"{symbolName}.g.cs", sourceText);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private static DataDefinition GetDataDefinition(ITypeSymbol definition)
|
||||
{
|
||||
var fields = new List<DataField>();
|
||||
var invalidFields = false;
|
||||
|
||||
foreach (var member in definition.GetMembers())
|
||||
{
|
||||
if (member is not IFieldSymbol && member is not IPropertySymbol)
|
||||
continue;
|
||||
|
||||
if (member.IsStatic)
|
||||
continue;
|
||||
|
||||
if (IsDataField(member, out var type, out var attribute))
|
||||
{
|
||||
if (attribute.ConstructorArguments.FirstOrDefault(arg => arg.Kind == TypedConstantKind.Type).Value is INamedTypeSymbol customSerializer)
|
||||
{
|
||||
if (ImplementsInterface(customSerializer, TypeCopierInterfaceNamespace))
|
||||
{
|
||||
fields.Add(new DataField(member, type, (customSerializer, Copier)));
|
||||
continue;
|
||||
}
|
||||
else if (ImplementsInterface(customSerializer, TypeCopyCreatorInterfaceNamespace))
|
||||
{
|
||||
fields.Add(new DataField(member, type, (customSerializer, CopyCreator)));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
fields.Add(new DataField(member, type, null));
|
||||
|
||||
if (IsReadOnlyMember(definition, type))
|
||||
{
|
||||
invalidFields = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var typeName = GetGenericTypeName(definition);
|
||||
var hasHooks = ImplementsInterface(definition, SerializationHooksNamespace);
|
||||
|
||||
return new DataDefinition(definition, typeName, fields, hasHooks, invalidFields);
|
||||
}
|
||||
|
||||
private static string GetConstructor(DataDefinition definition)
|
||||
{
|
||||
if (definition.Type.TypeKind == TypeKind.Interface)
|
||||
return string.Empty;
|
||||
|
||||
var builder = new StringBuilder();
|
||||
|
||||
if (NeedsEmptyConstructor(definition.Type))
|
||||
{
|
||||
builder.AppendLine($$"""
|
||||
// Implicit constructor
|
||||
#pragma warning disable CS8618
|
||||
public {{definition.Type.Name}}()
|
||||
#pragma warning enable CS8618
|
||||
{
|
||||
}
|
||||
""");
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
private static string GetCopyMethods(DataDefinition definition)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
|
||||
var modifiers = IsVirtualClass(definition.Type) ? "virtual " : string.Empty;
|
||||
var baseCall = string.Empty;
|
||||
string baseCopy;
|
||||
var baseType = definition.Type.BaseType;
|
||||
|
||||
if (baseType != null && IsDataDefinition(definition.Type.BaseType))
|
||||
{
|
||||
var baseName = baseType.ToDisplayString();
|
||||
baseCall = $"""
|
||||
var definitionCast = ({baseName}) target;
|
||||
base.InternalCopy(ref definitionCast, serialization, hookCtx, context);
|
||||
target = ({definition.GenericTypeName}) definitionCast;
|
||||
""";
|
||||
|
||||
baseCopy = $$"""
|
||||
public override void Copy(ref {{baseName}} target, ISerializationManager serialization, SerializationHookContext hookCtx, ISerializationContext? context = null)
|
||||
{
|
||||
var cast = ({{definition.GenericTypeName}}) target;
|
||||
Copy(ref cast, serialization, hookCtx, context);
|
||||
target = cast!;
|
||||
}
|
||||
|
||||
public override void Copy(ref object target, ISerializationManager serialization, SerializationHookContext hookCtx, ISerializationContext? context = null)
|
||||
{
|
||||
var cast = ({{definition.GenericTypeName}}) target;
|
||||
Copy(ref cast, serialization, hookCtx, context);
|
||||
target = cast!;
|
||||
}
|
||||
""";
|
||||
}
|
||||
else
|
||||
{
|
||||
baseCopy = $$"""
|
||||
public {{modifiers}} void Copy(ref object target, ISerializationManager serialization, SerializationHookContext hookCtx, ISerializationContext? context = null)
|
||||
{
|
||||
var cast = ({{definition.GenericTypeName}}) target;
|
||||
Copy(ref cast, serialization, hookCtx, context);
|
||||
target = cast!;
|
||||
}
|
||||
""";
|
||||
}
|
||||
|
||||
builder.AppendLine($$"""
|
||||
public {{modifiers}} void InternalCopy(ref {{definition.GenericTypeName}} target, ISerializationManager serialization, SerializationHookContext hookCtx, ISerializationContext? context = null)
|
||||
{
|
||||
{{baseCall}}
|
||||
{{CopyDataFields(definition)}}
|
||||
}
|
||||
|
||||
public {{modifiers}} void Copy(ref {{definition.GenericTypeName}} target, ISerializationManager serialization, SerializationHookContext hookCtx, ISerializationContext? context = null)
|
||||
{
|
||||
InternalCopy(ref target, serialization, hookCtx, context);
|
||||
}
|
||||
|
||||
{{baseCopy}}
|
||||
""");
|
||||
|
||||
foreach (var @interface in GetImplicitDataDefinitionInterfaces(definition.Type, true))
|
||||
{
|
||||
var interfaceModifiers = baseType != null && baseType.AllInterfaces.Contains(@interface, SymbolEqualityComparer.Default)
|
||||
? "override "
|
||||
: modifiers;
|
||||
var interfaceName = @interface.ToDisplayString();
|
||||
|
||||
builder.AppendLine($$"""
|
||||
public {{interfaceModifiers}} void InternalCopy(ref {{interfaceName}} target, ISerializationManager serialization, SerializationHookContext hookCtx, ISerializationContext? context = null)
|
||||
{
|
||||
var def = ({{definition.GenericTypeName}}) target;
|
||||
Copy(ref def, serialization, hookCtx, context);
|
||||
target = def;
|
||||
}
|
||||
|
||||
public {{interfaceModifiers}} void Copy(ref {{interfaceName}} target, ISerializationManager serialization, SerializationHookContext hookCtx, ISerializationContext? context = null)
|
||||
{
|
||||
InternalCopy(ref target, serialization, hookCtx, context);
|
||||
}
|
||||
""");
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
private static string GetInstantiators(DataDefinition definition)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
var modifiers = string.Empty;
|
||||
|
||||
if (definition.Type.BaseType is { } baseType && IsDataDefinition(baseType))
|
||||
modifiers = "override ";
|
||||
else if (IsVirtualClass(definition.Type))
|
||||
modifiers = "virtual ";
|
||||
|
||||
if (definition.Type.IsAbstract)
|
||||
{
|
||||
// TODO make abstract once data definitions are forced to be partial
|
||||
builder.AppendLine($$"""
|
||||
public {{modifiers}} {{definition.GenericTypeName}} Instantiate()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
""");
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.AppendLine($$"""
|
||||
public {{modifiers}} {{definition.GenericTypeName}} Instantiate()
|
||||
{
|
||||
return new {{definition.GenericTypeName}}();
|
||||
}
|
||||
""");
|
||||
}
|
||||
|
||||
foreach (var @interface in GetImplicitDataDefinitionInterfaces(definition.Type, false))
|
||||
{
|
||||
var interfaceName = @interface.ToDisplayString();
|
||||
builder.AppendLine($$"""
|
||||
{{interfaceName}} {{interfaceName}}.Instantiate()
|
||||
{
|
||||
return Instantiate();
|
||||
}
|
||||
|
||||
{{interfaceName}} ISerializationGenerated<{{interfaceName}}>.Instantiate()
|
||||
{
|
||||
return Instantiate();
|
||||
}
|
||||
""");
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
// TODO serveronly? do we care? who knows!!
|
||||
private static StringBuilder CopyDataFields(DataDefinition definition)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
|
||||
builder.AppendLine($"""
|
||||
if (serialization.TryCustomCopy(this, ref target, hookCtx, {definition.HasHooks.ToString().ToLower()}, context))
|
||||
return;
|
||||
""");
|
||||
|
||||
var structCopier = new StringBuilder();
|
||||
foreach (var field in definition.Fields)
|
||||
{
|
||||
var type = field.Type;
|
||||
var typeName = type.ToDisplayString();
|
||||
if (IsMultidimensionalArray(type))
|
||||
{
|
||||
typeName = typeName.Replace("*", "");
|
||||
}
|
||||
|
||||
var isNullableValueType = IsNullableValueType(type);
|
||||
var nonNullableTypeName = type.WithNullableAnnotation(NullableAnnotation.None).ToDisplayString();
|
||||
if (isNullableValueType)
|
||||
{
|
||||
nonNullableTypeName = typeName.Substring(0, typeName.Length - 1);
|
||||
}
|
||||
|
||||
var isClass = type.IsReferenceType || type.SpecialType == SpecialType.System_String;
|
||||
var isNullable = type.NullableAnnotation == NullableAnnotation.Annotated;
|
||||
var nullableOverride = isClass && !isNullable ? ", true" : string.Empty;
|
||||
var name = field.Symbol.Name;
|
||||
var tempVarName = $"{name}Temp";
|
||||
var nullableValue = isNullableValueType ? ".Value" : string.Empty;
|
||||
|
||||
if (field.CustomSerializer is { Serializer: var serializer, Type: var serializerType })
|
||||
{
|
||||
if (isClass || isNullableValueType)
|
||||
{
|
||||
builder.AppendLine($$"""
|
||||
if ({{name}} != null)
|
||||
{
|
||||
""");
|
||||
}
|
||||
|
||||
var serializerName = serializer.ToDisplayString();
|
||||
switch (serializerType)
|
||||
{
|
||||
case Copier:
|
||||
CopyToCustom(
|
||||
builder,
|
||||
nonNullableTypeName,
|
||||
serializerName,
|
||||
tempVarName,
|
||||
name,
|
||||
isNullable,
|
||||
isClass,
|
||||
isNullableValueType
|
||||
);
|
||||
break;
|
||||
case CopyCreator:
|
||||
CreateCopyCustom(
|
||||
builder,
|
||||
name,
|
||||
nonNullableTypeName,
|
||||
serializerName,
|
||||
nullableValue,
|
||||
nullableOverride
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
if (isClass || isNullableValueType)
|
||||
{
|
||||
builder.AppendLine("}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.AppendLine($$"""
|
||||
{{typeName}} {{tempVarName}} = default!;
|
||||
""");
|
||||
|
||||
if (isClass)
|
||||
{
|
||||
builder.AppendLine($$"""
|
||||
if ({{name}} != null)
|
||||
{
|
||||
""");
|
||||
}
|
||||
|
||||
var instantiator = string.Empty;
|
||||
if (!type.IsAbstract &&
|
||||
HasEmptyPublicConstructor(type) &&
|
||||
(type.IsReferenceType || IsNullableType(type)))
|
||||
{
|
||||
instantiator = $"{tempVarName} = new();";
|
||||
}
|
||||
|
||||
var hasHooks = ImplementsInterface(type, SerializationHooksNamespace) || !type.IsSealed;
|
||||
builder.AppendLine($$"""
|
||||
{{instantiator}}
|
||||
if (!serialization.TryCustomCopy(this.{{name}}, ref {{tempVarName}}, hookCtx, {{hasHooks.ToString().ToLower()}}, context))
|
||||
{
|
||||
""");
|
||||
|
||||
if (CanBeCopiedByValue(field.Symbol, field.Type))
|
||||
{
|
||||
builder.AppendLine($"{tempVarName} = {name};");
|
||||
}
|
||||
else if (IsDataDefinition(type) && !type.IsAbstract &&
|
||||
type is not INamedTypeSymbol { TypeKind: TypeKind.Interface })
|
||||
{
|
||||
var nullability = type.IsValueType ? string.Empty : "?";
|
||||
var orNew = type.IsReferenceType
|
||||
? $" ?? {name}{nullability}.Instantiate()"
|
||||
: string.Empty;
|
||||
var nullable = !type.IsValueType || IsNullableType(type);
|
||||
|
||||
|
||||
builder.AppendLine($"var temp = {name}{orNew};");
|
||||
|
||||
if (nullable)
|
||||
{
|
||||
builder.AppendLine("""
|
||||
if (temp != null)
|
||||
{
|
||||
""");
|
||||
}
|
||||
|
||||
builder.AppendLine($$"""
|
||||
{{name}}{{nullability}}.Copy(ref temp, serialization, hookCtx, context);
|
||||
{{tempVarName}} = temp;
|
||||
""");
|
||||
|
||||
if (nullable)
|
||||
{
|
||||
builder.AppendLine("}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.AppendLine($"{tempVarName} = serialization.CreateCopy({name}, hookCtx, context);");
|
||||
}
|
||||
|
||||
builder.AppendLine("}");
|
||||
|
||||
if (isClass)
|
||||
{
|
||||
builder.AppendLine("}");
|
||||
}
|
||||
|
||||
if (definition.Type.IsValueType)
|
||||
{
|
||||
structCopier.AppendLine($"{name} = {tempVarName},");
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.AppendLine($"target.{name} = {tempVarName};");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (definition.Type.IsValueType)
|
||||
{
|
||||
builder.AppendLine($$"""
|
||||
target = target with
|
||||
{
|
||||
{{structCopier}}
|
||||
};
|
||||
""");
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
private static void CopyToCustom(
|
||||
StringBuilder builder,
|
||||
string typeName,
|
||||
string serializerName,
|
||||
string tempVarName,
|
||||
string varName,
|
||||
bool isNullable,
|
||||
bool isClass,
|
||||
bool isNullableValueType)
|
||||
{
|
||||
var newTemp = isNullable && isClass ? $"{tempVarName} ??= new();" : string.Empty;
|
||||
var nullableOverride = isClass ? ", true" : string.Empty;
|
||||
var nullableValue = isNullableValueType ? ".Value" : string.Empty;
|
||||
|
||||
builder.AppendLine($$"""
|
||||
{{typeName}} {{tempVarName}} = default!;
|
||||
{{newTemp}}
|
||||
serialization.CopyTo<{{typeName}}, {{serializerName}}>(this.{{varName}}{{nullableValue}}, ref {{tempVarName}}, hookCtx, context{{nullableOverride}});
|
||||
target.{{varName}} = {{tempVarName}};
|
||||
""");
|
||||
}
|
||||
|
||||
private static void CreateCopyCustom(
|
||||
StringBuilder builder,
|
||||
string varName,
|
||||
string nonNullableTypeName,
|
||||
string serializerName,
|
||||
string nullableValue,
|
||||
string nullableOverride)
|
||||
{
|
||||
builder.AppendLine($$"""
|
||||
target.{{varName}} = serialization.CreateCopy<{{nonNullableTypeName}}, {{serializerName}}>(this.{{varName}}{{nullableValue}}, hookCtx, context{{nullableOverride}});
|
||||
""");
|
||||
}
|
||||
}
|
||||
8
Robust.Serialization.Generator/IsExternalInit.cs
Normal file
8
Robust.Serialization.Generator/IsExternalInit.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace System.Runtime.CompilerServices;
|
||||
|
||||
// Need this to be able to define records in the project
|
||||
internal static class IsExternalInit
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<LangVersion>11</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.Common" Version="4.4.0" PrivateAssets="all" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.4.0" PrivateAssets="all" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.Workspaces.Common" Version="4.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
331
Robust.Serialization.Generator/Types.cs
Normal file
331
Robust.Serialization.Generator/Types.cs
Normal file
@@ -0,0 +1,331 @@
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
|
||||
namespace Robust.Serialization.Generator;
|
||||
|
||||
internal static class Types
|
||||
{
|
||||
private const string DataDefinitionNamespace = "Robust.Shared.Serialization.Manager.Attributes.DataDefinitionAttribute";
|
||||
private const string ImplicitDataDefinitionNamespace = "Robust.Shared.Serialization.Manager.Attributes.ImplicitDataDefinitionForInheritorsAttribute";
|
||||
private const string DataFieldBaseNamespace = "Robust.Shared.Serialization.Manager.Attributes.DataFieldBaseAttribute";
|
||||
private const string CopyByRefNamespace = "Robust.Shared.Serialization.Manager.Attributes.CopyByRefAttribute";
|
||||
|
||||
internal static bool IsPartial(TypeDeclarationSyntax type)
|
||||
{
|
||||
return type.Modifiers.IndexOf(SyntaxKind.PartialKeyword) != -1;
|
||||
}
|
||||
|
||||
internal static bool IsDataDefinition(ITypeSymbol? type)
|
||||
{
|
||||
if (type == null)
|
||||
return false;
|
||||
|
||||
return HasAttribute(type, DataDefinitionNamespace) ||
|
||||
IsImplicitDataDefinition(type);
|
||||
}
|
||||
|
||||
internal static bool IsDataField(ISymbol member, out ITypeSymbol type, out AttributeData attribute)
|
||||
{
|
||||
// TODO data records and other attributes
|
||||
if (member is IFieldSymbol field)
|
||||
{
|
||||
foreach (var attr in field.GetAttributes())
|
||||
{
|
||||
if (attr.AttributeClass != null && Inherits(attr.AttributeClass, DataFieldBaseNamespace))
|
||||
{
|
||||
type = field.Type;
|
||||
attribute = attr;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (member is IPropertySymbol property)
|
||||
{
|
||||
foreach (var attr in property.GetAttributes())
|
||||
{
|
||||
if (attr.AttributeClass != null && Inherits(attr.AttributeClass, DataFieldBaseNamespace))
|
||||
{
|
||||
type = property.Type;
|
||||
attribute = attr;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type = null!;
|
||||
attribute = null!;
|
||||
return false;
|
||||
}
|
||||
|
||||
internal static bool IsImplicitDataDefinition(ITypeSymbol type)
|
||||
{
|
||||
if (HasAttribute(type, ImplicitDataDefinitionNamespace))
|
||||
return true;
|
||||
|
||||
foreach (var baseType in GetBaseTypes(type))
|
||||
{
|
||||
if (HasAttribute(baseType, ImplicitDataDefinitionNamespace))
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach (var @interface in type.AllInterfaces)
|
||||
{
|
||||
if (IsImplicitDataDefinitionInterface(@interface))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal static bool IsImplicitDataDefinitionInterface(ITypeSymbol @interface)
|
||||
{
|
||||
if (HasAttribute(@interface, ImplicitDataDefinitionNamespace))
|
||||
return true;
|
||||
|
||||
foreach (var subInterface in @interface.AllInterfaces)
|
||||
{
|
||||
if (HasAttribute(subInterface, ImplicitDataDefinitionNamespace))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal static IEnumerable<ITypeSymbol> GetImplicitDataDefinitionInterfaces(ITypeSymbol type, bool all)
|
||||
{
|
||||
var interfaces = all ? type.AllInterfaces : type.Interfaces;
|
||||
foreach (var @interface in interfaces)
|
||||
{
|
||||
if (IsImplicitDataDefinitionInterface(@interface))
|
||||
yield return @interface;
|
||||
}
|
||||
}
|
||||
|
||||
internal static bool IsNullableType(ITypeSymbol type)
|
||||
{
|
||||
if (type.NullableAnnotation == NullableAnnotation.Annotated)
|
||||
return true;
|
||||
|
||||
if (type.OriginalDefinition.ToDisplayString() == "System.Nullable<T>")
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal static bool IsNullableValueType(ITypeSymbol type)
|
||||
{
|
||||
return type.IsValueType && IsNullableType(type);
|
||||
}
|
||||
|
||||
internal static bool IsMultidimensionalArray(ITypeSymbol type)
|
||||
{
|
||||
return type is IArrayTypeSymbol { Rank: > 1 };
|
||||
}
|
||||
|
||||
internal static bool CanBeCopiedByValue(ISymbol member, ITypeSymbol type)
|
||||
{
|
||||
if (type.OriginalDefinition.ToDisplayString() == "System.Nullable<T>")
|
||||
return CanBeCopiedByValue(member, ((INamedTypeSymbol) type).TypeArguments[0]);
|
||||
|
||||
if (type.TypeKind == TypeKind.Enum)
|
||||
return true;
|
||||
|
||||
switch (type.SpecialType)
|
||||
{
|
||||
case SpecialType.System_Enum:
|
||||
case SpecialType.System_Boolean:
|
||||
case SpecialType.System_Char:
|
||||
case SpecialType.System_SByte:
|
||||
case SpecialType.System_Byte:
|
||||
case SpecialType.System_Int16:
|
||||
case SpecialType.System_UInt16:
|
||||
case SpecialType.System_Int32:
|
||||
case SpecialType.System_UInt32:
|
||||
case SpecialType.System_Int64:
|
||||
case SpecialType.System_UInt64:
|
||||
case SpecialType.System_Decimal:
|
||||
case SpecialType.System_Single:
|
||||
case SpecialType.System_Double:
|
||||
case SpecialType.System_String:
|
||||
case SpecialType.System_DateTime:
|
||||
return true;
|
||||
}
|
||||
|
||||
if (HasAttribute(member, CopyByRefNamespace))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal static string GetGenericTypeName(ITypeSymbol symbol)
|
||||
{
|
||||
var name = symbol.Name;
|
||||
|
||||
if (symbol is INamedTypeSymbol { TypeParameters: { Length: > 0 } parameters })
|
||||
{
|
||||
name += "<";
|
||||
|
||||
for (var i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
var parameter = parameters[i];
|
||||
name += parameter.Name;
|
||||
|
||||
if (i < parameters.Length - 1)
|
||||
{
|
||||
name += ", ";
|
||||
}
|
||||
}
|
||||
|
||||
name += ">";
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
internal static string GetPartialTypeDefinitionLine(ITypeSymbol symbol)
|
||||
{
|
||||
var access = symbol.DeclaredAccessibility switch
|
||||
{
|
||||
Accessibility.Private => "private",
|
||||
Accessibility.ProtectedAndInternal => "protected internal",
|
||||
Accessibility.Protected => "protected",
|
||||
Accessibility.Internal => "internal",
|
||||
Accessibility.Public => "public",
|
||||
_ => "public"
|
||||
};
|
||||
|
||||
var typeKeyword = "partial ";
|
||||
if (symbol.TypeKind == TypeKind.Interface)
|
||||
{
|
||||
typeKeyword += "interface";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (symbol.IsRecord)
|
||||
{
|
||||
typeKeyword += symbol.IsValueType ? "record struct" : "record";
|
||||
}
|
||||
else
|
||||
{
|
||||
typeKeyword += symbol.IsValueType ? "struct" : "class";
|
||||
}
|
||||
|
||||
if (symbol.IsAbstract)
|
||||
{
|
||||
typeKeyword = $"abstract {typeKeyword}";
|
||||
}
|
||||
}
|
||||
|
||||
var typeName = GetGenericTypeName(symbol);
|
||||
return $"{access} {typeKeyword} {typeName}";
|
||||
}
|
||||
|
||||
internal static bool Inherits(ITypeSymbol type, string parent)
|
||||
{
|
||||
foreach (var baseType in GetBaseTypes(type))
|
||||
{
|
||||
if (baseType.ToDisplayString() == parent)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal static bool ImplementsInterface(ITypeSymbol type, string interfaceName)
|
||||
{
|
||||
foreach (var interfaceType in type.AllInterfaces)
|
||||
{
|
||||
if (interfaceType.ToDisplayString().Contains(interfaceName))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal static bool IsReadOnlyMember(ITypeSymbol type, ISymbol member)
|
||||
{
|
||||
if (member is IFieldSymbol field)
|
||||
{
|
||||
return field.IsReadOnly;
|
||||
}
|
||||
else if (member is IPropertySymbol property)
|
||||
{
|
||||
if (property.SetMethod == null)
|
||||
return true;
|
||||
|
||||
if (property.SetMethod.IsInitOnly)
|
||||
return type.IsReferenceType;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal static bool NeedsEmptyConstructor(ITypeSymbol type)
|
||||
{
|
||||
if (type is not INamedTypeSymbol named)
|
||||
return false;
|
||||
|
||||
if (named.InstanceConstructors.Length == 0)
|
||||
return true;
|
||||
|
||||
foreach (var constructor in named.InstanceConstructors)
|
||||
{
|
||||
if (constructor.Parameters.Length == 0 &&
|
||||
!constructor.IsImplicitlyDeclared)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
internal static bool HasEmptyPublicConstructor(ITypeSymbol type)
|
||||
{
|
||||
if (type is not INamedTypeSymbol named)
|
||||
return false;
|
||||
|
||||
foreach (var constructor in named.InstanceConstructors)
|
||||
{
|
||||
if (constructor.DeclaredAccessibility == Accessibility.Public &&
|
||||
constructor.Parameters.Length == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal static bool IsVirtualClass(ITypeSymbol type)
|
||||
{
|
||||
return type.IsReferenceType && !type.IsSealed && type.TypeKind != TypeKind.Interface;
|
||||
}
|
||||
|
||||
internal static bool HasAttribute(ISymbol symbol, string attributeName)
|
||||
{
|
||||
foreach (var attribute in symbol.GetAttributes())
|
||||
{
|
||||
if (attribute.AttributeClass?.ToDisplayString() == attributeName)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal static IEnumerable<ITypeSymbol> GetBaseTypes(ITypeSymbol type)
|
||||
{
|
||||
var baseType = type.BaseType;
|
||||
while (baseType != null)
|
||||
{
|
||||
yield return baseType;
|
||||
baseType = baseType.BaseType;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ using Robust.Shared.ViewVariables;
|
||||
namespace Robust.Server.GameObjects
|
||||
{
|
||||
[RegisterComponent]
|
||||
public sealed class ActorComponent : Component
|
||||
public sealed partial class ActorComponent : Component
|
||||
{
|
||||
[ViewVariables]
|
||||
public IPlayerSession PlayerSession { get; internal set; } = default!;
|
||||
|
||||
@@ -11,7 +11,7 @@ using Robust.Shared.ViewVariables;
|
||||
namespace Robust.Server.GameObjects
|
||||
{
|
||||
[RegisterComponent, ComponentReference(typeof(SharedEyeComponent))]
|
||||
public sealed class EyeComponent : SharedEyeComponent
|
||||
public sealed partial class EyeComponent : SharedEyeComponent
|
||||
{
|
||||
public const int DefaultVisibilityMask = 1;
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ using Robust.Shared.GameObjects;
|
||||
namespace Robust.Server.GameObjects
|
||||
{
|
||||
[RegisterComponent]
|
||||
internal sealed class ViewSubscriberComponent : Component
|
||||
internal sealed partial class ViewSubscriberComponent : Component
|
||||
{
|
||||
internal readonly HashSet<IPlayerSession> SubscribedSessions = new();
|
||||
}
|
||||
|
||||
@@ -4,5 +4,5 @@ namespace Robust.Server.GameObjects
|
||||
{
|
||||
[RegisterComponent]
|
||||
[ComponentReference(typeof(SharedPointLightComponent))]
|
||||
public sealed class PointLightComponent : SharedPointLightComponent {}
|
||||
public sealed partial class PointLightComponent : SharedPointLightComponent {}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,6 @@ namespace Robust.Server.GameObjects;
|
||||
/// close the UI automatically.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed class IgnoreUIRangeComponent : Component
|
||||
public sealed partial class IgnoreUIRangeComponent : Component
|
||||
{
|
||||
}
|
||||
|
||||
@@ -15,14 +15,14 @@ namespace Robust.Server.GameObjects
|
||||
/// <seealso cref="BoundUserInterface"/>
|
||||
[PublicAPI]
|
||||
[RegisterComponent, ComponentReference(typeof(SharedUserInterfaceComponent))]
|
||||
public sealed class ServerUserInterfaceComponent : SharedUserInterfaceComponent
|
||||
public sealed partial class ServerUserInterfaceComponent : SharedUserInterfaceComponent
|
||||
{
|
||||
[ViewVariables]
|
||||
public readonly Dictionary<Enum, BoundUserInterface> Interfaces = new();
|
||||
}
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed class ActiveUserInterfaceComponent : Component
|
||||
public sealed partial class ActiveUserInterfaceComponent : Component
|
||||
{
|
||||
public HashSet<BoundUserInterface> Interfaces = new();
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace Robust.Server.GameObjects
|
||||
{
|
||||
[RegisterComponent]
|
||||
[Access(typeof(VisibilitySystem))]
|
||||
public sealed class VisibilityComponent : Component
|
||||
public sealed partial class VisibilityComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// The visibility layer for the entity.
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace Robust.Server.GameObjects
|
||||
/// This can then be used to re-serialize the entity with the same UID for the merge driver to recognize.
|
||||
/// </remarks>
|
||||
[RegisterComponent]
|
||||
public sealed class MapSaveIdComponent : Component
|
||||
public sealed partial class MapSaveIdComponent : Component
|
||||
{
|
||||
public int Uid { get; set; }
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Robust.Server.Maps;
|
||||
/// Added to Maps that were loaded by MapLoaderSystem. If not present then this map was created externally.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed class LoadedMapComponent : Component
|
||||
public sealed partial class LoadedMapComponent : Component
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Robust.Shared.Analyzers;
|
||||
/// Placed on auto-generated classes to mark to certain robust analyzers that they are auto-generated
|
||||
/// and may need to be ignored (e.g. the access analyzer)
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface)]
|
||||
public sealed class RobustAutoGeneratedAttribute : Attribute
|
||||
{
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace Robust.Shared.Audio
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
[DataDefinition]
|
||||
public struct AudioParams
|
||||
public partial struct AudioParams
|
||||
{
|
||||
/// <summary>
|
||||
/// The DistanceModel to use for this specific source.
|
||||
|
||||
@@ -11,8 +11,8 @@ public sealed class SoundCollectionPrototype : IPrototype
|
||||
{
|
||||
[ViewVariables]
|
||||
[IdDataField]
|
||||
public string ID { get; } = default!;
|
||||
public string ID { get; private set; } = default!;
|
||||
|
||||
[DataField("files")]
|
||||
public List<ResPath> PickFiles { get; } = new();
|
||||
public List<ResPath> PickFiles { get; private set; } = new();
|
||||
}
|
||||
|
||||
@@ -13,22 +13,22 @@ using System;
|
||||
namespace Robust.Shared.Audio;
|
||||
|
||||
[ImplicitDataDefinitionForInheritors, Serializable, NetSerializable]
|
||||
public abstract class SoundSpecifier
|
||||
public abstract partial class SoundSpecifier
|
||||
{
|
||||
[DataField("params")]
|
||||
public AudioParams Params { get; init; } = AudioParams.Default;
|
||||
public AudioParams Params { get; set; } = AudioParams.Default;
|
||||
|
||||
[Obsolete("Use SharedAudioSystem.GetSound(), or just pass sound specifier directly into SharedAudioSystem.")]
|
||||
public abstract string GetSound(IRobustRandom? rand = null, IPrototypeManager? proto = null);
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class SoundPathSpecifier : SoundSpecifier
|
||||
public sealed partial class SoundPathSpecifier : SoundSpecifier
|
||||
{
|
||||
public const string Node = "path";
|
||||
|
||||
[DataField(Node, customTypeSerializer: typeof(ResPathSerializer), required: true)]
|
||||
public ResPath Path { get; }
|
||||
public ResPath Path { get; private set; }
|
||||
|
||||
[UsedImplicitly]
|
||||
private SoundPathSpecifier()
|
||||
@@ -54,12 +54,12 @@ public sealed class SoundPathSpecifier : SoundSpecifier
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class SoundCollectionSpecifier : SoundSpecifier
|
||||
public sealed partial class SoundCollectionSpecifier : SoundSpecifier
|
||||
{
|
||||
public const string Node = "collection";
|
||||
|
||||
[DataField(Node, customTypeSerializer: typeof(PrototypeIdSerializer<SoundCollectionPrototype>), required: true)]
|
||||
public string? Collection { get; }
|
||||
public string? Collection { get; private set; }
|
||||
|
||||
[UsedImplicitly]
|
||||
public SoundCollectionSpecifier() { }
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Robust.Shared.Containers
|
||||
/// <summary>
|
||||
/// Base container class that all container inherit from.
|
||||
/// </summary>
|
||||
public abstract class BaseContainer : IContainer
|
||||
public abstract partial class BaseContainer : IContainer
|
||||
{
|
||||
/// <inheritdoc />
|
||||
[ViewVariables]
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace Robust.Shared.Containers
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
[SerializedType(ClassName)]
|
||||
public sealed class Container : BaseContainer
|
||||
public sealed partial class Container : BaseContainer
|
||||
{
|
||||
private const string ClassName = "Container";
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace Robust.Shared.Containers
|
||||
/// The generic container class uses a list of entities
|
||||
/// </summary>
|
||||
[DataField("ents")]
|
||||
private readonly List<EntityUid> _containerList = new();
|
||||
private List<EntityUid> _containerList = new();
|
||||
|
||||
private readonly List<EntityUid> _expectedEntities = new();
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Robust.Shared.Containers
|
||||
[ComponentReference(typeof(IContainerManager))]
|
||||
[NetworkedComponent]
|
||||
[RegisterComponent, ComponentProtoName("ContainerContainer")]
|
||||
public sealed class ContainerManagerComponent : Component, IContainerManager, ISerializationHooks
|
||||
public sealed partial class ContainerManagerComponent : Component, IContainerManager, ISerializationHooks
|
||||
{
|
||||
[Dependency] private readonly IDynamicTypeFactoryInternal _dynFactory = default!;
|
||||
[Dependency] private readonly IEntityManager _entMan = default!;
|
||||
@@ -184,7 +184,7 @@ namespace Robust.Shared.Containers
|
||||
}
|
||||
|
||||
[DataDefinition]
|
||||
private struct ContainerPrototypeData
|
||||
private partial struct ContainerPrototypeData
|
||||
{
|
||||
[DataField("entities")] public List<EntityUid> Entities = new ();
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Robust.Shared.Containers
|
||||
{
|
||||
[UsedImplicitly]
|
||||
[SerializedType(ClassName)]
|
||||
public sealed class ContainerSlot : BaseContainer
|
||||
public sealed partial class ContainerSlot : BaseContainer
|
||||
{
|
||||
private const string ClassName = "ContainerSlot";
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace Robust.Shared.Containers
|
||||
/// <seealso cref="IContainerManager" />
|
||||
[PublicAPI]
|
||||
[ImplicitDataDefinitionForInheritors]
|
||||
public interface IContainer
|
||||
public partial interface IContainer
|
||||
{
|
||||
/// <summary>
|
||||
/// Readonly collection of all the entities contained within this specific container
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Robust.Shared.Containers
|
||||
/// Manages containers on an entity.
|
||||
/// </summary>
|
||||
/// <seealso cref="IContainer" />
|
||||
public interface IContainerManager : IComponent
|
||||
public partial interface IContainerManager : IComponent
|
||||
{
|
||||
/// <summary>
|
||||
/// Makes a new container of the specified type.
|
||||
|
||||
@@ -2,6 +2,8 @@ using System;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Reflection;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Serialization.Manager;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
@@ -11,8 +13,7 @@ namespace Robust.Shared.GameObjects
|
||||
{
|
||||
/// <inheritdoc />
|
||||
[Reflect(false)]
|
||||
[ImplicitDataDefinitionForInheritors]
|
||||
public abstract class Component : IComponent
|
||||
public abstract partial class Component : IComponent
|
||||
{
|
||||
[DataField("netsync")]
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace Robust.Shared.GameObjects;
|
||||
/// Visualization works client side with derivatives of the <see cref="Robust.Client.GameObjects.VisualizerSystem">VisualizerSystem</see> class and corresponding components.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed class AppearanceComponent : Component
|
||||
public sealed partial class AppearanceComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether or not the appearance needs to be updated.
|
||||
|
||||
@@ -3,4 +3,4 @@ using Robust.Shared.GameStates;
|
||||
namespace Robust.Shared.GameObjects;
|
||||
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed class ScaleVisualsComponent : Component {}
|
||||
public sealed partial class ScaleVisualsComponent : Component {}
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace Robust.Shared.GameObjects
|
||||
/// A component that toggles collision on an entity being toggled.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed class CollideOnAnchorComponent : Component
|
||||
public sealed partial class CollideOnAnchorComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether we toggle collision on or off when anchoring (and vice versa when unanchoring).
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Robust.Shared.GameObjects
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent()]
|
||||
[Access(typeof(CollisionWakeSystem))]
|
||||
public sealed class CollisionWakeComponent : Component
|
||||
public sealed partial class CollisionWakeComponent : Component
|
||||
{
|
||||
[DataField("enabled")]
|
||||
public bool Enabled = true;
|
||||
|
||||
@@ -10,17 +10,17 @@ namespace Robust.Shared.GameObjects
|
||||
/// Throws an exception in <see cref="OnAdd" />.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed class DebugExceptionOnAddComponent : Component { }
|
||||
public sealed partial class DebugExceptionOnAddComponent : Component { }
|
||||
|
||||
/// <summary>
|
||||
/// Throws an exception in <see cref="Initialize" />.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed class DebugExceptionInitializeComponent : Component { }
|
||||
public sealed partial class DebugExceptionInitializeComponent : Component { }
|
||||
|
||||
/// <summary>
|
||||
/// Throws an exception in <see cref="Startup" />.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed class DebugExceptionStartupComponent : Component { }
|
||||
public sealed partial class DebugExceptionStartupComponent : Component { }
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ using Robust.Shared.ViewVariables;
|
||||
namespace Robust.Shared.GameObjects
|
||||
{
|
||||
[NetworkedComponent()]
|
||||
public abstract class SharedEyeComponent : Component
|
||||
public abstract partial class SharedEyeComponent : Component
|
||||
{
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public virtual bool DrawFov { get; set; }
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Robust.Shared.GameObjects;
|
||||
[RegisterComponent]
|
||||
[NetworkedComponent()]
|
||||
[Access(typeof(OccluderSystem))]
|
||||
public sealed class OccluderComponent : Component, IComponentTreeEntry<OccluderComponent>
|
||||
public sealed partial class OccluderComponent : Component, IComponentTreeEntry<OccluderComponent>
|
||||
{
|
||||
[DataField("enabled")]
|
||||
public bool Enabled = true;
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace Robust.Shared.GameObjects;
|
||||
/// Stores the relevant occluder children of this entity.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed class OccluderTreeComponent : Component, IComponentTreeComponent<OccluderComponent>
|
||||
public sealed partial class OccluderTreeComponent : Component, IComponentTreeComponent<OccluderComponent>
|
||||
{
|
||||
public DynamicTree<ComponentTreeEntry<OccluderComponent>> Tree { get; set; } = default!;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ using System.Numerics;
|
||||
namespace Robust.Shared.GameObjects
|
||||
{
|
||||
[NetworkedComponent]
|
||||
public abstract class SharedPointLightComponent : Component
|
||||
public abstract partial class SharedPointLightComponent : Component
|
||||
{
|
||||
[Dependency] private readonly IEntitySystemManager _sysMan = default!;
|
||||
|
||||
|
||||
@@ -12,10 +12,10 @@ namespace Robust.Shared.GameObjects.Components.Localization
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
[NetworkedComponent()]
|
||||
public sealed class GrammarComponent : Component
|
||||
public sealed partial class GrammarComponent : Component
|
||||
{
|
||||
[DataField("attributes")]
|
||||
public Dictionary<string, string> Attributes { get; } = new();
|
||||
public Dictionary<string, string> Attributes { get; private set; } = new();
|
||||
|
||||
[ViewVariables]
|
||||
public Gender? Gender
|
||||
|
||||
@@ -57,7 +57,7 @@ namespace Robust.Shared.GameObjects
|
||||
/// Contains meta data about this entity that isn't component specific.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed class MetaDataComponent : Component
|
||||
public sealed partial class MetaDataComponent : Component
|
||||
{
|
||||
[DataField("name")] internal string? _entityName;
|
||||
[DataField("desc")] internal string? _entityDescription;
|
||||
|
||||
@@ -8,7 +8,7 @@ using Robust.Shared.Serialization.Manager.Attributes;
|
||||
namespace Robust.Shared.GameObjects;
|
||||
|
||||
[Serializable, NetSerializable, DataDefinition]
|
||||
public sealed class PrototypeLayerData
|
||||
public sealed partial class PrototypeLayerData
|
||||
{
|
||||
/// <summary>
|
||||
/// The shader prototype to use for this layer.
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace Robust.Shared.GameObjects;
|
||||
/// this is useful if you require multiple entities to have synchronised animations.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed class SyncSpriteComponent : Component
|
||||
public sealed partial class SyncSpriteComponent : Component
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ using Timer = Robust.Shared.Timing.Timer;
|
||||
namespace Robust.Shared.GameObjects
|
||||
{
|
||||
[RegisterComponent, Obsolete("Use a system update loop instead")]
|
||||
public sealed class TimerComponent : Component
|
||||
public sealed partial class TimerComponent : Component
|
||||
{
|
||||
[Dependency] private readonly IRuntimeLog _runtimeLog = default!;
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace Robust.Shared.GameObjects
|
||||
/// Stores the position and orientation of the entity.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed class TransformComponent : Component, IComponentDebug
|
||||
public sealed partial class TransformComponent : Component, IComponentDebug
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entMan = default!;
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
|
||||
@@ -8,19 +8,19 @@ using Robust.Shared.Serialization.Manager.Attributes;
|
||||
namespace Robust.Shared.GameObjects
|
||||
{
|
||||
[NetworkedComponent]
|
||||
public abstract class SharedUserInterfaceComponent : Component
|
||||
public abstract partial class SharedUserInterfaceComponent : Component
|
||||
{
|
||||
[DataField("interfaces")]
|
||||
internal List<PrototypeData> _interfaceData = new();
|
||||
|
||||
[DataDefinition]
|
||||
public sealed class PrototypeData
|
||||
public sealed partial class PrototypeData
|
||||
{
|
||||
[DataField("key", required: true)]
|
||||
public Enum UiKey { get; } = default!;
|
||||
public Enum UiKey { get; private set; } = default!;
|
||||
|
||||
[DataField("type", required: true)]
|
||||
public string ClientType { get; } = default!;
|
||||
public string ClientType { get; private set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum range before a BUI auto-closes. A non-positive number means there is no limit.
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Robust.Shared.GameObjects
|
||||
@@ -8,7 +10,8 @@ namespace Robust.Shared.GameObjects
|
||||
/// All discoverable implementations of IComponent must override the <see cref="Name" />.
|
||||
/// Instances are dynamically instantiated by a <c>ComponentFactory</c>, and will have their IoC Dependencies resolved.
|
||||
/// </remarks>
|
||||
public interface IComponent
|
||||
[ImplicitDataDefinitionForInheritors]
|
||||
public partial interface IComponent : ISerializationGenerated<IComponent>
|
||||
{
|
||||
/// <summary>
|
||||
/// The current lifetime stage of this component. You can use this to check
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace Robust.Shared.GameObjects
|
||||
{
|
||||
public interface IComponentDebug : IComponent
|
||||
public partial interface IComponentDebug : IComponent
|
||||
{
|
||||
string GetDebugString();
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace Robust.Shared.GameObjects;
|
||||
/// If an entity with this component is placed on top of another anchored entity with this component and the same key it will replace it.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed class PlacementReplacementComponent : Component
|
||||
public sealed partial class PlacementReplacementComponent : Component
|
||||
{
|
||||
[DataField("key")]
|
||||
public string Key = "";
|
||||
|
||||
@@ -6,7 +6,7 @@ using Robust.Shared.ViewVariables;
|
||||
namespace Robust.Shared.Map.Components;
|
||||
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed class GridTreeComponent : Component
|
||||
public sealed partial class GridTreeComponent : Component
|
||||
{
|
||||
[ViewVariables]
|
||||
public readonly B2DynamicTree<(EntityUid Uid, MapGridComponent Grid)> Tree = new();
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Robust.Shared.Map.Components
|
||||
{
|
||||
[RegisterComponent]
|
||||
[NetworkedComponent]
|
||||
public sealed class MapComponent : Component
|
||||
public sealed partial class MapComponent : Component
|
||||
{
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("lightingEnabled")]
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace Robust.Shared.Map.Components
|
||||
{
|
||||
[RegisterComponent]
|
||||
[NetworkedComponent]
|
||||
public sealed class MapGridComponent : Component
|
||||
public sealed partial class MapGridComponent : Component
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entManager = default!;
|
||||
private SharedMapSystem MapSystem => _entManager.System<SharedMapSystem>();
|
||||
@@ -61,7 +61,7 @@ namespace Robust.Shared.Map.Components
|
||||
/// Grid chunks than make up this grid.
|
||||
/// </summary>
|
||||
[DataField("chunks")]
|
||||
internal readonly Dictionary<Vector2i, MapChunk> Chunks = new();
|
||||
internal Dictionary<Vector2i, MapChunk> Chunks = new();
|
||||
|
||||
[ViewVariables]
|
||||
public Box2 LocalAABB { get; internal set; }
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace Robust.Shared.Map.Components;
|
||||
/// Controls per-map lighting values.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed class MapLightComponent : Component
|
||||
public sealed partial class MapLightComponent : Component
|
||||
{
|
||||
public static readonly Color DefaultColor = Color.FromSrgb(Color.Black);
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Robust.Shared.Map.Components;
|
||||
/// Stores what grids moved in a tick.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed class MovedGridsComponent : Component
|
||||
public sealed partial class MovedGridsComponent : Component
|
||||
{
|
||||
[ViewVariables]
|
||||
public HashSet<EntityUid> MovedGrids = new();
|
||||
|
||||
@@ -37,7 +37,7 @@ using FNLfloat = System.Single;
|
||||
//using FNLfloat = System.Double;
|
||||
|
||||
[DataDefinition, Serializable, NetSerializable]
|
||||
public sealed class FastNoiseLite
|
||||
public sealed partial class FastNoiseLite
|
||||
{
|
||||
private const short INLINE = 256; // MethodImplOptions.AggressiveInlining;
|
||||
private const short OPTIMISE = 512; // MethodImplOptions.AggressiveOptimization;
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Robust.Shared.Physics
|
||||
/// Stores the broadphase structure for the relevant grid / map.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed class BroadphaseComponent : Component
|
||||
public sealed partial class BroadphaseComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Stores all non-static bodies.
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace Robust.Shared.Physics.Collision.Shapes
|
||||
{
|
||||
[Serializable, NetSerializable]
|
||||
[DataDefinition]
|
||||
public sealed class EdgeShape : IPhysShape, IEquatable<EdgeShape>
|
||||
public sealed partial class EdgeShape : IPhysShape, IEquatable<EdgeShape>
|
||||
{
|
||||
// Note that the normal is from Vertex 2 to Vertex 1 CCW
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace Robust.Shared.Physics.Collision.Shapes
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
[DataDefinition]
|
||||
public sealed class PhysShapeAabb : IPhysShape, IEquatable<PhysShapeAabb>
|
||||
public sealed partial class PhysShapeAabb : IPhysShape, IEquatable<PhysShapeAabb>
|
||||
{
|
||||
public int ChildCount => 1;
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Robust.Shared.Physics.Collision.Shapes
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
[DataDefinition]
|
||||
public sealed class PhysShapeCircle : IPhysShape, IEquatable<PhysShapeCircle>
|
||||
public sealed partial class PhysShapeCircle : IPhysShape, IEquatable<PhysShapeCircle>
|
||||
{
|
||||
public int ChildCount => 1;
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace Robust.Shared.Physics.Collision.Shapes
|
||||
{
|
||||
[Serializable, NetSerializable]
|
||||
[DataDefinition]
|
||||
public sealed class PolygonShape : IPhysShape, ISerializationHooks, IEquatable<PolygonShape>, IApproxEquatable<PolygonShape>
|
||||
public sealed partial class PolygonShape : IPhysShape, ISerializationHooks, IEquatable<PolygonShape>, IApproxEquatable<PolygonShape>
|
||||
{
|
||||
// TODO: Serialize this someday. This probably needs a dedicated shapeserializer that derives vertexcount
|
||||
// from the yml nodes just for convenience.
|
||||
|
||||
@@ -8,7 +8,7 @@ using Robust.Shared.ViewVariables;
|
||||
namespace Robust.Shared.Physics.Components;
|
||||
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed class Gravity2DComponent : Component
|
||||
public sealed partial class Gravity2DComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Applies side-view gravity to the map.
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Robust.Shared.Physics.Components;
|
||||
/// Does this entity have joint data relayed from elsewhere.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed class JointRelayTargetComponent : Component
|
||||
public sealed partial class JointRelayTargetComponent : Component
|
||||
{
|
||||
[DataField("relayTarget")]
|
||||
public HashSet<EntityUid> Relayed = new();
|
||||
|
||||
@@ -35,7 +35,7 @@ using Robust.Shared.ViewVariables;
|
||||
namespace Robust.Shared.Physics.Components;
|
||||
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed class PhysicsComponent : Component
|
||||
public sealed partial class PhysicsComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Has this body been added to an island previously in this tick.
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace Robust.Shared.Physics.Dynamics
|
||||
{
|
||||
[Serializable, NetSerializable]
|
||||
[DataDefinition]
|
||||
public sealed class Fixture : IEquatable<Fixture>, ISerializationHooks
|
||||
public sealed partial class Fixture : IEquatable<Fixture>, ISerializationHooks
|
||||
{
|
||||
/// <summary>
|
||||
/// Allows us to reference a specific fixture when we contain multiple
|
||||
|
||||
@@ -73,7 +73,7 @@ internal sealed class DistanceJointState : JointState
|
||||
/// to remain at a fixed distance from each other. You can view
|
||||
/// this as a massless, rigid rod.
|
||||
/// </summary>
|
||||
public sealed class DistanceJoint : Joint, IEquatable<DistanceJoint>
|
||||
public sealed partial class DistanceJoint : Joint, IEquatable<DistanceJoint>
|
||||
{
|
||||
// Sloth note:
|
||||
// Box2D is replacing rope with distance hence this is also a partial port of Box2D
|
||||
|
||||
@@ -61,7 +61,7 @@ public sealed class FrictionJointState : JointState
|
||||
/// Friction joint. This is used for top-down friction.
|
||||
/// It provides 2D translational friction and angular friction.
|
||||
/// </summary>
|
||||
public sealed class FrictionJoint : Joint, IEquatable<FrictionJoint>
|
||||
public sealed partial class FrictionJoint : Joint, IEquatable<FrictionJoint>
|
||||
{
|
||||
// Solver shared
|
||||
private Vector2 _linearImpulse;
|
||||
|
||||
@@ -76,7 +76,7 @@ public abstract class JointState
|
||||
}
|
||||
|
||||
[ImplicitDataDefinitionForInheritors]
|
||||
public abstract class Joint : IEquatable<Joint>
|
||||
public abstract partial class Joint : IEquatable<Joint>
|
||||
{
|
||||
/// <summary>
|
||||
/// Network identifier of this joint.
|
||||
|
||||
@@ -47,7 +47,7 @@ internal sealed class MouseJointState : JointState
|
||||
}
|
||||
|
||||
|
||||
public sealed class MouseJoint : Joint, IEquatable<MouseJoint>
|
||||
public sealed partial class MouseJoint : Joint, IEquatable<MouseJoint>
|
||||
{
|
||||
public override JointType JointType => JointType.Mouse;
|
||||
|
||||
|
||||
@@ -119,7 +119,7 @@ internal sealed class PrismaticJointState : JointState
|
||||
/// can violate the constraint slightly. The joint translation is zero
|
||||
/// when the local anchor points coincide in world space.
|
||||
/// </summary>
|
||||
public sealed class PrismaticJoint : Joint, IEquatable<PrismaticJoint>
|
||||
public sealed partial class PrismaticJoint : Joint, IEquatable<PrismaticJoint>
|
||||
{
|
||||
/// <summary>
|
||||
/// The local translation unit axis in bodyA.
|
||||
|
||||
@@ -49,7 +49,7 @@ internal sealed class RevoluteJointState : JointState
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class RevoluteJoint : Joint, IEquatable<RevoluteJoint>
|
||||
public sealed partial class RevoluteJoint : Joint, IEquatable<RevoluteJoint>
|
||||
{
|
||||
// Temporary
|
||||
private Vector2 _impulse;
|
||||
|
||||
@@ -23,7 +23,7 @@ internal sealed class WeldJointState : JointState
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class WeldJoint : Joint, IEquatable<WeldJoint>
|
||||
public sealed partial class WeldJoint : Joint, IEquatable<WeldJoint>
|
||||
{
|
||||
// Shared
|
||||
private float _gamma;
|
||||
|
||||
@@ -31,7 +31,7 @@ using PhysicsComponent = Robust.Shared.Physics.Components.PhysicsComponent;
|
||||
namespace Robust.Shared.Physics.Dynamics;
|
||||
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed class PhysicsMapComponent : Component
|
||||
public sealed partial class PhysicsMapComponent : Component
|
||||
{
|
||||
public bool AutoClearForces;
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Robust.Shared.Physics
|
||||
/// In its own component to decrease physics comp state size significantly.
|
||||
/// </remarks>
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed class FixturesComponent : Component
|
||||
public sealed partial class FixturesComponent : Component
|
||||
{
|
||||
// This is a snowflake component whose main job is making physics states smaller for massive bodies
|
||||
// (e.g. grids)
|
||||
@@ -29,6 +29,6 @@ namespace Robust.Shared.Physics
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("fixtures", customTypeSerializer:typeof(FixtureSerializer))]
|
||||
[NeverPushInheritance]
|
||||
[Access(typeof(FixtureSystem), Other = AccessPermissions.ReadExecute)] // FIXME Friends
|
||||
public readonly Dictionary<string, Fixture> Fixtures = new();
|
||||
public Dictionary<string, Fixture> Fixtures = new();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Robust.Shared.Physics;
|
||||
|
||||
[RegisterComponent]
|
||||
[NetworkedComponent]
|
||||
public sealed class JointComponent : Component
|
||||
public sealed partial class JointComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Are we relaying our joints to a parent entity.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user