Compare commits

...

5 Commits

Author SHA1 Message Date
DrSmugleaf
3ae65f9e3d Version: 248.0.2-source-gen-debug 2025-03-20 21:13:47 -07:00
DrSmugleaf
af6fc51def Source gen changes 2025-03-20 18:06:10 -07:00
metalgearsloth
139b6f796c Version: 248.0.2 2025-03-12 20:26:50 +11:00
metalgearsloth
2ee7c35fd3 Don't throw on invalid MapUids for overlays (#5740) 2025-03-12 20:16:13 +11:00
metalgearsloth
56eae5ad08 Reduce EntityManager.IsDefault allocations (#5741)
* Reduce EntityManager.IsDefault allocations

We don't actually need the MappingDataNode so we can avoid allocating the entire class per entity.

* Adjust this order
2025-03-12 19:42:08 +11:00
7 changed files with 190 additions and 144 deletions

View File

@@ -1,4 +1,4 @@
<Project>
<!-- This file automatically reset by Tools/version.py -->
<!-- This file automatically reset by Tools/version.py -->

View File

@@ -54,8 +54,27 @@ END TEMPLATE-->
*None yet*
## 248.0.2-source-gen-debug
## 248.0.2
### Bugfixes
* Don't throw in overlay rendering if MapUid not found.
### Internal
* Reduce EntityManager.IsDefault allocations.
## 248.0.1
### Bugfixes
* Bump ImageSharp version.
* Fix instances of NaN gain for audio where a negative-infinity value is being used for volume.
## 248.0.0

View File

@@ -126,7 +126,7 @@ namespace Robust.Client.Graphics.Clyde
DebugTools.Assert(space != OverlaySpace.ScreenSpaceBelowWorld && space != OverlaySpace.ScreenSpace);
var mapId = vp.Eye!.Position.MapId;
var args = new OverlayDrawArgs(space, null, vp, _renderHandle, new UIBox2i((0, 0), vp.Size), _mapManager.GetMapEntityIdOrThrow(mapId), mapId, worldBox, worldBounds);
var args = new OverlayDrawArgs(space, null, vp, _renderHandle, new UIBox2i((0, 0), vp.Size), _mapSystem.GetMapOrInvalid(mapId), mapId, worldBox, worldBounds);
if (!overlay.BeforeDraw(args))
return;
@@ -178,7 +178,7 @@ namespace Robust.Client.Graphics.Clyde
var worldAABB = worldBounds.CalcBoundingBox();
var mapId = vp.Eye!.Position.MapId;
var args = new OverlayDrawArgs(space, vpControl, vp, handle, bounds, _mapManager.GetMapEntityIdOrThrow(mapId), mapId, worldAABB, worldBounds);
var args = new OverlayDrawArgs(space, vpControl, vp, handle, bounds, _mapSystem.GetMapOrInvalid(mapId), mapId, worldAABB, worldBounds);
foreach (var overlay in list)
{

View File

@@ -19,112 +19,117 @@ public class Generator : IIncrementalGenerator
public void Initialize(IncrementalGeneratorInitializationContext initContext)
{
IncrementalValuesProvider<(string name, string code)?> dataDefinitions = initContext.SyntaxProvider
.CreateSyntaxProvider(
static (node, _) => node is TypeDeclarationSyntax,
static (context, _) =>
{
var type = (TypeDeclarationSyntax)context.Node;
var symbol = (ITypeSymbol)context.SemanticModel.GetDeclaredSymbol(type)!;
if (!IsDataDefinition(symbol))
return null;
return GenerateForDataDefinition(type, symbol);
}
)
.Where(static type => type != null);
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(
dataDefinitions,
initContext.CompilationProvider.Combine(dataDefinitions.WithComparer(comparer).Collect()),
static (sourceContext, source) =>
{
// TODO: deduplicate based on name?
var (name, code) = source!.Value;
var (compilation, declarations) = source;
var builder = new StringBuilder();
var containingTypes = new Stack<INamedTypeSymbol>();
var declarationsGenerated = new HashSet<string>();
var deltaType = compilation.GetTypeByMetadataName(ComponentDeltaInterfaceName)!;
sourceContext.AddSource(name, code);
foreach (var declaration in declarations)
{
builder.Clear();
containingTypes.Clear();
var type = compilation.GetSemanticModel(declaration.SyntaxTree).GetDeclaredSymbol(declaration)!;
var symbolName = type
.ToDisplayString()
.Replace('<', '{')
.Replace('>', '}');
if (!declarationsGenerated.Add(symbolName))
continue;
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.Manager.Exceptions;
using Robust.Shared.Serialization.TypeSerializers.Interfaces;
#pragma warning disable CS0618 // Type or member is obsolete
#pragma warning disable CS0612 // Type or member is obsolete
#pragma warning disable CS0108 // Member hides inherited member; missing new keyword
#pragma warning disable RA0002 // Robust access analyzer
{{namespaceString}}
{{containingTypesStart}}
{{GetPartialTypeDefinitionLine(type)}} : ISerializationGenerated<{{definition.GenericTypeName}}>
{
{{GetConstructor(definition)}}
{{GetCopyMethods(definition, deltaType)}}
{{GetInstantiators(definition, deltaType)}}
}
{{containingTypesEnd}}
""");
var sourceText = CSharpSyntaxTree
.ParseText(builder.ToString())
.GetRoot()
.NormalizeWhitespace()
.ToFullString();
sourceContext.AddSource($"{symbolName}.g.cs", sourceText);
}
}
);
}
private static (string, string)? GenerateForDataDefinition(
TypeDeclarationSyntax declaration,
ITypeSymbol type)
{
var builder = new StringBuilder();
var containingTypes = new Stack<INamedTypeSymbol>();
containingTypes.Clear();
var symbolName = type
.ToDisplayString()
.Replace('<', '{')
.Replace('>', '}');
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)
return null;
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.Manager.Exceptions;
using Robust.Shared.Serialization.TypeSerializers.Interfaces;
#pragma warning disable CS0618 // Type or member is obsolete
#pragma warning disable CS0612 // Type or member is obsolete
#pragma warning disable CS0108 // Member hides inherited member; missing new keyword
#pragma warning disable RA0002 // Robust access analyzer
{{namespaceString}}
{{containingTypesStart}}
{{GetPartialTypeDefinitionLine(type)}} : ISerializationGenerated<{{definition.GenericTypeName}}>
{
{{GetConstructor(definition)}}
{{GetCopyMethods(definition)}}
{{GetInstantiators(definition)}}
}
{{containingTypesEnd}}
""");
return ($"{symbolName}.g.cs", builder.ToString());
}
private static DataDefinition GetDataDefinition(ITypeSymbol definition)
{
var fields = new List<DataField>();
@@ -191,7 +196,7 @@ public class Generator : IIncrementalGenerator
return builder.ToString();
}
private static string GetCopyMethods(DataDefinition definition)
private static string GetCopyMethods(DataDefinition definition, ITypeSymbol deltaType)
{
var builder = new StringBuilder();
@@ -262,36 +267,36 @@ public class Generator : IIncrementalGenerator
{{baseCopy}}
""");
foreach (var interfaceName in InternalGetImplicitDataDefinitionInterfaces(definition.Type, true))
foreach (var @interface in InternalGetImplicitDataDefinitionInterfaces(definition.Type, true, deltaType))
{
var interfaceModifiers = baseType != null &&
baseType.AllInterfaces.Any(i => i.ToDisplayString() == interfaceName)
var interfaceModifiers = baseType != null && baseType.AllInterfaces.Contains(@interface, SymbolEqualityComparer.Default)
? "override "
: modifiers;
var interfaceName = @interface.ToDisplayString();
builder.AppendLine($$"""
/// <seealso cref="ISerializationManager.CopyTo"/>
[Obsolete("Use ISerializationManager.CopyTo instead")]
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;
}
/// <seealso cref="ISerializationManager.CopyTo"/>
[Obsolete("Use ISerializationManager.CopyTo instead")]
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;
}
/// <seealso cref="ISerializationManager.CopyTo"/>
[Obsolete("Use ISerializationManager.CopyTo instead")]
public {{interfaceModifiers}} void Copy(ref {{interfaceName}} target, ISerializationManager serialization, SerializationHookContext hookCtx, ISerializationContext? context = null)
{
InternalCopy(ref target, serialization, hookCtx, context);
}
""");
/// <seealso cref="ISerializationManager.CopyTo"/>
[Obsolete("Use ISerializationManager.CopyTo instead")]
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)
private static string GetInstantiators(DataDefinition definition, ITypeSymbol deltaType)
{
var builder = new StringBuilder();
var modifiers = string.Empty;
@@ -325,28 +330,27 @@ public class Generator : IIncrementalGenerator
""");
}
foreach (var interfaceName in InternalGetImplicitDataDefinitionInterfaces(definition.Type, false))
foreach (var @interface in InternalGetImplicitDataDefinitionInterfaces(definition.Type, false, deltaType))
{
var interfaceName = @interface.ToDisplayString();
builder.AppendLine($$"""
{{interfaceName}} {{interfaceName}}.Instantiate()
{
return Instantiate();
}
{{interfaceName}} {{interfaceName}}.Instantiate()
{
return Instantiate();
}
{{interfaceName}} ISerializationGenerated<{{interfaceName}}>.Instantiate()
{
return Instantiate();
}
""");
{{interfaceName}} ISerializationGenerated<{{interfaceName}}>.Instantiate()
{
return Instantiate();
}
""");
}
return builder.ToString();
}
[SuppressMessage("ReSharper", "PossibleMultipleEnumeration")]
private static IEnumerable<string> InternalGetImplicitDataDefinitionInterfaces(
ITypeSymbol type,
bool all)
private static IEnumerable<ITypeSymbol> InternalGetImplicitDataDefinitionInterfaces(ITypeSymbol type, bool all, ITypeSymbol deltaType)
{
var symbols = GetImplicitDataDefinitionInterfaces(type, all);
@@ -364,10 +368,10 @@ public class Generator : IIncrementalGenerator
return symbols;
}
if (symbols.Any(x => x == ComponentDeltaInterfaceName))
if (symbols.Any(x => x.ToDisplayString() == deltaType.ToDisplayString()))
return symbols;
return symbols.Append(ComponentDeltaInterfaceName);
return symbols.Append(deltaType);
}
// TODO serveronly? do we care? who knows!!

View File

@@ -1,5 +1,4 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.CodeAnalysis;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
@@ -94,13 +93,13 @@ internal static class Types
return false;
}
internal static IEnumerable<string> GetImplicitDataDefinitionInterfaces(ITypeSymbol type, bool all)
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.ToDisplayString();
yield return @interface;
}
}

View File

@@ -189,10 +189,12 @@ namespace Robust.Shared.GameObjects
return false;
var compType = component.GetType();
var compName = _componentFactory.GetComponentName(compType);
if (compName == _xformName || compName == _metaReg.Name)
if (compType == typeof(TransformComponent) || compType == typeof(MetaDataComponent))
continue;
var compName = _componentFactory.GetComponentName(compType);
// If the component isn't on the prototype then it's custom.
if (!protoData.TryGetValue(compName, out var protoMapping))
return false;
@@ -208,9 +210,7 @@ namespace Robust.Shared.GameObjects
return false;
}
var diff = compMapping.Except(protoMapping);
if (diff != null && diff.Children.Count != 0)
if (compMapping.AnyExcept(protoMapping))
return false;
}

View File

@@ -2,6 +2,7 @@ using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
@@ -352,6 +353,29 @@ namespace Robust.Shared.Serialization.Markdown.Mapping
return mappingNode._children.Count == 0 ? null : mappingNode;
}
/// <summary>
/// Returns true if there are any nodes on this node that aren't in the other node.
/// </summary>
[Pure]
public bool AnyExcept(MappingDataNode node)
{
foreach (var (key, val) in _list)
{
var other = node._list.FirstOrNull(p => p.Key.Equals(key));
if (other == null)
{
return true;
}
// We only keep the entry if the values are not equal
if (!val.Equals(other.Value.Value))
return true;
}
return false;
}
public override bool Equals(object? obj)
{
if (obj is not MappingDataNode other)