243 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
		
		
			
		
	
	
			243 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
|  | using System; | ||
|  | using System.Collections.Generic; | ||
|  | using System.IO; | ||
|  | using System.Linq; | ||
|  | using System.Text.Json; | ||
|  | using EpicGames.UHT.Types; | ||
|  | using UnrealSharpScriptGenerator.Model; | ||
|  | 
 | ||
|  | namespace UnrealSharpScriptGenerator.PropertyTranslators; | ||
|  | 
 | ||
|  | public static class PropertyTranslatorManager | ||
|  | { | ||
|  |     private static readonly Dictionary<Type, List<PropertyTranslator>?> RegisteredTranslators = new(); | ||
|  |     private static readonly HashSet<Type> RegisteredPrimitives = new(); | ||
|  |     private static readonly HashSet<Type> RegisteredNumerics = new(); | ||
|  | 
 | ||
|  |     public static SpecialTypeInfo SpecialTypeInfo { get; } = new(); | ||
|  |      | ||
|  |     static PropertyTranslatorManager() | ||
|  |     { | ||
|  |         var projectDirectory = Program.Factory.Session.ProjectDirectory; | ||
|  |         var configDirectory = Path.Combine(projectDirectory!, "Config"); | ||
|  |          | ||
|  |         var pluginDirectory = Path.Combine(projectDirectory!, "Plugins"); | ||
|  |         var pluginDirInfo = new DirectoryInfo(pluginDirectory); | ||
|  | 
 | ||
|  |         var files = pluginDirInfo.GetFiles("*.uplugin", SearchOption.AllDirectories) | ||
|  |             .Select(x => x.DirectoryName!) | ||
|  |             .Select(x => Path.Combine(x, "Config")) | ||
|  |             .Concat(new List<string> { configDirectory }) | ||
|  |             .Select(x => new DirectoryInfo(x)) | ||
|  |             .Where(x => x.Exists) | ||
|  |             .SelectMany(x => x.GetFiles("*.UnrealSharpTypes.json", SearchOption.AllDirectories)) | ||
|  |             .Select(x => x.FullName); | ||
|  |         foreach (var pluginFile in files) | ||
|  |         { | ||
|  |             using var fileStream = File.OpenRead(pluginFile); | ||
|  |             try | ||
|  |             { | ||
|  |                 var manifest = JsonSerializer.Deserialize<TypeTranslationManifest>(fileStream); | ||
|  |                 AddTranslationManifest(manifest!); | ||
|  |             } | ||
|  |             catch (JsonException e) | ||
|  |             { | ||
|  |                 Console.WriteLine($"Error reading {pluginFile}: {e.Message}"); | ||
|  |             } | ||
|  |         } | ||
|  |          | ||
|  |         EnumPropertyTranslator enumPropertyTranslator = new(); | ||
|  |         AddPropertyTranslator(typeof(UhtEnumProperty), enumPropertyTranslator); | ||
|  |         AddPropertyTranslator(typeof(UhtByteProperty), enumPropertyTranslator); | ||
|  |          | ||
|  |         AddBlittablePropertyTranslator(typeof(UhtInt8Property), "sbyte", PropertyKind.SByte); | ||
|  |         AddBlittablePropertyTranslator(typeof(UhtInt16Property), "short", PropertyKind.Short); | ||
|  |         AddBlittablePropertyTranslator(typeof(UhtInt64Property), "long", PropertyKind.Long); | ||
|  |         AddBlittablePropertyTranslator(typeof(UhtUInt16Property), "ushort", PropertyKind.UShort); | ||
|  |         AddBlittablePropertyTranslator(typeof(UhtUInt32Property), "uint", PropertyKind.UInt); | ||
|  |         AddBlittablePropertyTranslator(typeof(UhtUInt64Property), "ulong", PropertyKind.ULong); | ||
|  |         AddBlittablePropertyTranslator(typeof(UhtDoubleProperty), "double", PropertyKind.Double); | ||
|  |         AddBlittablePropertyTranslator(typeof(UhtByteProperty), "byte", PropertyKind.Byte); | ||
|  |         AddBlittablePropertyTranslator(typeof(UhtLargeWorldCoordinatesRealProperty), "double", PropertyKind.Double); | ||
|  |         AddPropertyTranslator(typeof(UhtFloatProperty), new FloatPropertyTranslator()); | ||
|  |         AddPropertyTranslator(typeof(UhtIntProperty), new IntPropertyTranslator()); | ||
|  | 
 | ||
|  |         MulticastDelegatePropertyTranslator multicastDelegatePropertyTranslator = new(); | ||
|  |         AddPropertyTranslator(typeof(UhtMulticastSparseDelegateProperty), multicastDelegatePropertyTranslator); | ||
|  |         AddPropertyTranslator(typeof(UhtMulticastDelegateProperty), multicastDelegatePropertyTranslator); | ||
|  |         AddPropertyTranslator(typeof(UhtMulticastInlineDelegateProperty), multicastDelegatePropertyTranslator); | ||
|  |         AddPropertyTranslator(typeof(UhtDelegateProperty), new SinglecastDelegatePropertyTranslator()); | ||
|  |          | ||
|  |         AddBlittablePropertyTranslator(typeof(UhtByteProperty), "byte", PropertyKind.Byte); | ||
|  |          | ||
|  |         AddPropertyTranslator(typeof(UhtBoolProperty), new BoolPropertyTranslator()); | ||
|  |         AddPropertyTranslator(typeof(UhtStrProperty), new StringPropertyTranslator()); | ||
|  |         AddPropertyTranslator(typeof(UhtNameProperty), new NamePropertyTranslator()); | ||
|  |         AddPropertyTranslator(typeof(UhtTextProperty), new TextPropertyTranslator()); | ||
|  |          | ||
|  |         AddPropertyTranslator(typeof(UhtWeakObjectPtrProperty), new WeakObjectPropertyTranslator()); | ||
|  |          | ||
|  |         WorldContextObjectPropertyTranslator worldContextObjectPropertyTranslator = new(); | ||
|  |         AddPropertyTranslator(typeof(UhtObjectPropertyBase), worldContextObjectPropertyTranslator); | ||
|  | #if !UE_5_6_OR_LATER | ||
|  |         AddPropertyTranslator(typeof(UhtObjectPtrProperty), worldContextObjectPropertyTranslator); | ||
|  | #endif | ||
|  |         AddPropertyTranslator(typeof(UhtObjectProperty), worldContextObjectPropertyTranslator); | ||
|  |         AddPropertyTranslator(typeof(UhtLazyObjectPtrProperty), worldContextObjectPropertyTranslator); | ||
|  |          | ||
|  |         ObjectPropertyTranslator objectPropertyTranslator = new(); | ||
|  |         AddPropertyTranslator(typeof(UhtObjectPropertyBase), objectPropertyTranslator); | ||
|  | #if !UE_5_6_OR_LATER | ||
|  |         AddPropertyTranslator(typeof(UhtObjectPtrProperty), objectPropertyTranslator); | ||
|  | #endif | ||
|  |         AddPropertyTranslator(typeof(UhtObjectProperty), objectPropertyTranslator); | ||
|  |         AddPropertyTranslator(typeof(UhtLazyObjectPtrProperty), objectPropertyTranslator); | ||
|  |          | ||
|  |         AddPropertyTranslator(typeof(UhtInterfaceProperty), new InterfacePropertyTranslator()); | ||
|  |          | ||
|  |         AddPropertyTranslator(typeof(UhtClassProperty), new ClassPropertyTranslator()); | ||
|  | #if !UE_5_6_OR_LATER | ||
|  |         AddPropertyTranslator(typeof(UhtClassPtrProperty), new ClassPropertyTranslator()); | ||
|  | #endif | ||
|  |         AddPropertyTranslator(typeof(UhtSoftClassProperty), new SoftClassPropertyTranslator()); | ||
|  |         AddPropertyTranslator(typeof(UhtSoftObjectProperty), new SoftObjectPropertyTranslator()); | ||
|  |         AddPropertyTranslator(typeof(UhtFieldPathProperty), new FieldPathPropertyTranslator()); | ||
|  | 
 | ||
|  |         foreach (var (nativeName, managedType) in SpecialTypeInfo.Structs.BlittableTypes.Values) | ||
|  |         { | ||
|  |             if (managedType is null) | ||
|  |             { | ||
|  |                 continue; | ||
|  |             } | ||
|  | 
 | ||
|  |             AddBlittableCustomStructPropertyTranslator(nativeName, managedType); | ||
|  |         } | ||
|  | 
 | ||
|  |         AddPropertyTranslator(typeof(UhtArrayProperty), new ArrayPropertyTranslator()); | ||
|  |         AddPropertyTranslator(typeof(UhtMapProperty), new MapPropertyTranslator()); | ||
|  |         AddPropertyTranslator(typeof(UhtSetProperty), new SetPropertyTranslator()); | ||
|  |          | ||
|  |         AddPropertyTranslator(typeof(UhtStructProperty), new BlittableStructPropertyTranslator()); | ||
|  |         AddPropertyTranslator(typeof(UhtStructProperty), new StructPropertyTranslator()); | ||
|  |          | ||
|  |         AddPropertyTranslator(typeof(UhtOptionalProperty), new OptionalPropertyTranslator()); | ||
|  |          | ||
|  |         // Manually exported properties | ||
|  |         InclusionLists.BanProperty("UWorld", "GameState"); | ||
|  |         InclusionLists.BanProperty("UWorld", "AuthorityGameMode"); | ||
|  | 
 | ||
|  |         // Some reason == equality differs from .Equals | ||
|  |         InclusionLists.BanEquality("FRandomStream"); | ||
|  | 
 | ||
|  |         // Renamed variables X/Y/Z to Pitch/Yaw/Roll | ||
|  |         InclusionLists.BanEquality("FRotator"); | ||
|  | 
 | ||
|  |         // Fields not generating correctly | ||
|  |         InclusionLists.BanEquality("FVector3f"); | ||
|  |         InclusionLists.BanEquality("FVector2f"); | ||
|  |         InclusionLists.BanEquality("FVector4f"); | ||
|  |         InclusionLists.BanEquality("FVector_NetQuantize"); | ||
|  |         InclusionLists.BanEquality("FVector_NetQuantize10"); | ||
|  |         InclusionLists.BanEquality("FVector_NetQuantize100"); | ||
|  |         InclusionLists.BanEquality("FVector_NetQuantizeNormal"); | ||
|  | 
 | ||
|  |         // Doesn't have any fields | ||
|  |         InclusionLists.BanEquality("FSubsystemCollectionBaseRef"); | ||
|  | 
 | ||
|  |         // Custom arithmetic needed | ||
|  |         InclusionLists.BanArithmetic("FQuat"); | ||
|  |     } | ||
|  | 
 | ||
|  |     public static void AddTranslationManifest(TypeTranslationManifest manifest) | ||
|  |     { | ||
|  |         foreach (var skippedStruct in manifest.Structs.CustomTypes) | ||
|  |         { | ||
|  |             SpecialTypeInfo.Structs.SkippedTypes.Add(skippedStruct); | ||
|  |         } | ||
|  |          | ||
|  |         foreach (var structInfo in manifest.Structs.BlittableTypes) | ||
|  |         { | ||
|  |             if (SpecialTypeInfo.Structs.NativelyCopyableTypes.ContainsKey(structInfo.Name)) | ||
|  |             { | ||
|  |                 throw new InvalidOperationException( | ||
|  |                     $"A struct cannot be both blittable and natively copyable: {structInfo.Name}"); | ||
|  |             } | ||
|  |              | ||
|  |             if (SpecialTypeInfo.Structs.BlittableTypes.TryGetValue(structInfo.Name, out var existing)) | ||
|  |             { | ||
|  |                 if (structInfo.ManagedType is not null && existing.ManagedType is not null && | ||
|  |                     structInfo.ManagedType != existing.ManagedType) | ||
|  |                 { | ||
|  |                     throw new InvalidOperationException($"Duplicate struct name specified: {structInfo.Name}"); | ||
|  |                 } | ||
|  |             } | ||
|  |             else | ||
|  |             { | ||
|  |                 SpecialTypeInfo.Structs.BlittableTypes.Add(structInfo.Name, structInfo); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         foreach (var structInfo in manifest.Structs.NativelyTranslatableTypes) | ||
|  |         { | ||
|  |             if (SpecialTypeInfo.Structs.NativelyCopyableTypes.TryGetValue(structInfo.Name, out var existing)) | ||
|  |             { | ||
|  |                 SpecialTypeInfo.Structs.NativelyCopyableTypes[structInfo.Name] = existing with { HasDestructor = existing.HasDestructor || structInfo.HasDestructor }; | ||
|  |                 continue; | ||
|  |             } | ||
|  |              | ||
|  |             if (SpecialTypeInfo.Structs.BlittableTypes.ContainsKey(structInfo.Name)) | ||
|  |             { | ||
|  |                 throw new InvalidOperationException( | ||
|  |                     $"A struct cannot be both blittable and natively copyable: {structInfo.Name}"); | ||
|  |             } | ||
|  | 
 | ||
|  |             SpecialTypeInfo.Structs.NativelyCopyableTypes.Add(structInfo.Name, structInfo); | ||
|  |         } | ||
|  |     } | ||
|  |      | ||
|  |     public static PropertyTranslator? GetTranslator(UhtProperty property) | ||
|  |     { | ||
|  |         if (!RegisteredTranslators.TryGetValue(property.GetType(), out var translator)) | ||
|  |         { | ||
|  |             return null; | ||
|  |         } | ||
|  |          | ||
|  |         foreach (PropertyTranslator propertyTranslator in translator!) | ||
|  |         { | ||
|  |             if (propertyTranslator.CanExport(property)) | ||
|  |             { | ||
|  |                 return propertyTranslator; | ||
|  |             } | ||
|  |         } | ||
|  |          | ||
|  |         return null; | ||
|  |     } | ||
|  |      | ||
|  |     public static void AddBlittablePropertyTranslator(Type propertyType, string managedType, PropertyKind propertyKind = PropertyKind.Unknown) | ||
|  |     { | ||
|  |         if (RegisteredTranslators.TryGetValue(propertyType, out var translators)) | ||
|  |         { | ||
|  |             translators!.Add(new BlittableTypePropertyTranslator(propertyType, managedType, propertyKind)); | ||
|  |             return; | ||
|  |         } | ||
|  |          | ||
|  |         RegisteredTranslators.Add(propertyType, new List<PropertyTranslator> {new BlittableTypePropertyTranslator(propertyType, managedType, propertyKind) }); | ||
|  |     } | ||
|  | 
 | ||
|  |     private static void AddPropertyTranslator(Type propertyClass, PropertyTranslator translator) | ||
|  |     { | ||
|  |         if (RegisteredTranslators.TryGetValue(propertyClass, out var translators)) | ||
|  |         { | ||
|  |             translators!.Add(translator); | ||
|  |             return; | ||
|  |         } | ||
|  |          | ||
|  |         RegisteredTranslators.Add(propertyClass, new List<PropertyTranslator> {translator}); | ||
|  |     } | ||
|  |      | ||
|  |     private static void AddBlittableCustomStructPropertyTranslator(string nativeName, string managedType) | ||
|  |     { | ||
|  |         AddPropertyTranslator(typeof(UhtStructProperty), new BlittableCustomStructTypePropertyTranslator(nativeName, managedType)); | ||
|  |     } | ||
|  | } |