Refactor serialization copying to use source generators (#4286)

This commit is contained in:
DrSmugleaf
2023-08-22 17:37:13 -07:00
committed by GitHub
parent dbb45f1c13
commit 66239d23ea
135 changed files with 1897 additions and 221 deletions

View File

@@ -25,4 +25,7 @@
<!-- analyzer -->
<Import Project="Robust.Analyzers.targets" Condition="'$(SkipRobustAnalyzer)' != 'true'" />
<!-- serialization generator -->
<Import Project="Robust.Serialization.Generator.targets" />
</Project>

View 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>

View 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;
}
}
}

View 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);
}
}

View File

@@ -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.");

View File

@@ -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
{
}
}

View File

@@ -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
{
}
}

View File

@@ -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
{
}
}

View File

@@ -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
{
}
}

View File

@@ -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!;
}
}

View File

@@ -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!;
}
}

View File

@@ -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;

View File

@@ -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!;
}

View File

@@ -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!;
}

View File

@@ -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 ._.

View File

@@ -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.

View File

@@ -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!;

View File

@@ -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!;
}

View File

@@ -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.

View File

@@ -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; }

View File

@@ -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; }

View File

@@ -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!;

View File

@@ -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();

View File

@@ -225,7 +225,7 @@ namespace Robust.Client.Graphics
}
[DataDefinition]
public struct StencilParameters
public partial struct StencilParameters
{
public StencilParameters()
{

View File

@@ -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()
{

View File

@@ -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;

View File

@@ -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
{
}

View File

@@ -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!;
}

View File

@@ -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)
{

View 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);

View 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();
}
}

View 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
}

View 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}});
""");
}
}

View 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
{
}

View File

@@ -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>

View 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;
}
}
}

View File

@@ -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!;

View File

@@ -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;

View File

@@ -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();
}

View File

@@ -4,5 +4,5 @@ namespace Robust.Server.GameObjects
{
[RegisterComponent]
[ComponentReference(typeof(SharedPointLightComponent))]
public sealed class PointLightComponent : SharedPointLightComponent {}
public sealed partial class PointLightComponent : SharedPointLightComponent {}
}

View File

@@ -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
{
}

View File

@@ -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();
}

View File

@@ -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.

View File

@@ -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; }
}

View File

@@ -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
{
}

View File

@@ -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
{
}

View File

@@ -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.

View File

@@ -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();
}

View File

@@ -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() { }

View File

@@ -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]

View File

@@ -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();

View File

@@ -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 ();

View File

@@ -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";

View File

@@ -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

View File

@@ -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.

View File

@@ -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)]

View File

@@ -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.

View File

@@ -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 {}

View File

@@ -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).

View File

@@ -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;

View File

@@ -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 { }
}

View File

@@ -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; }

View File

@@ -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;

View File

@@ -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!;
}

View File

@@ -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!;

View File

@@ -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

View File

@@ -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;

View File

@@ -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.

View File

@@ -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
{
}

View File

@@ -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!;

View File

@@ -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!;

View File

@@ -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.

View File

@@ -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

View File

@@ -1,6 +1,6 @@
namespace Robust.Shared.GameObjects
{
public interface IComponentDebug : IComponent
public partial interface IComponentDebug : IComponent
{
string GetDebugString();
}

View File

@@ -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 = "";

View File

@@ -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();

View File

@@ -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")]

View File

@@ -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; }

View File

@@ -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);

View File

@@ -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();

View File

@@ -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;

View File

@@ -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.

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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.

View File

@@ -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.

View File

@@ -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();

View File

@@ -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.

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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.

View File

@@ -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;

View File

@@ -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.

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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();
}
}

View File

@@ -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