private void GenerateCodeForModule(UnrealModuleInfo module, UStruct[] structs, UEnum[] enums, UFunction[] globalFunctions) { if (structs.Length == 0 && enums.Length == 0 && globalFunctions.Length == 0) { return; } if (slowTaskModuleCount > 1) { System.Diagnostics.Debug.Assert(subSlowTask == null); subSlowTask = new FScopedSlowTask(currentSlowTaskTarget, "SubTask"); subSlowTask.Visibility = ESlowTaskVisibility.ForceVisible;// Required otherwise the UI is very delayed subSlowTask.MakeDialog(); } BeginGenerateModule(module); GenerateCodeForGlobalFunctions(module, globalFunctions); foreach (UStruct unrealStruct in structs) { SlowTaskStep(unrealStruct); GenerateCodeForStruct(module, unrealStruct); } GenerateCodeForEnums(module, enums, Settings.MergeEnumFiles); EndGenerateModule(module); if (subSlowTask != null) { subSlowTask.Dispose(); subSlowTask = null; } }
private void GenerateCodeForEnum(UnrealModuleInfo module, UEnum unrealEnum) { UnrealModuleType moduleAssetType; string currentNamespace = GetModuleNamespace(unrealEnum, out moduleAssetType); List <string> namespaces = GetDefaultNamespaces(); CSharpTextBuilder builder = new CSharpTextBuilder(Settings.IndentType); if (!string.IsNullOrEmpty(currentNamespace)) { builder.AppendLine("namespace " + currentNamespace); builder.OpenBrace(); } GenerateCodeForEnum(module, builder, unrealEnum); if (!string.IsNullOrEmpty(currentNamespace)) { builder.CloseBrace(); } builder.InsertNamespaces(currentNamespace, namespaces, Settings.SortNamespaces); OnCodeGenerated(module, moduleAssetType, GetTypeName(unrealEnum), unrealEnum.GetPathName(), builder); }
private void OnCodeGenerated(UnrealModuleInfo module, UnrealModuleType moduleAssetType, string typeName, string path, CSharpTextBuilder code) { if (codeManager != null) { codeManager.OnCodeGenerated(module, moduleAssetType, typeName, path, code.ToString()); } }
private void AppendAttribute(CSharpTextBuilder builder, UField field, UnrealModuleInfo module, StructInfo structInfo) { AppendAttribute(builder, field, module); //if (field.IsA<UScriptStruct>() && structInfo.StructAsClass) //{ // builder.AppendLine("[" + Names.UStructAsClassAttributeShort + "]"); //} }
private void GenerateCodeForEnums(UnrealModuleInfo module, UEnum[] enums, bool combine) { if (enums.Length == 0) { return; } if (combine) { // Put all enums into a single file prefixed with the module name string enumsName = module.Name + "Enums"; UnrealModuleType moduleAssetType; string currentNamespace = GetModuleNamespace(enums[0], out moduleAssetType, false); List <string> namespaces = GetDefaultNamespaces(); CSharpTextBuilder builder = new CSharpTextBuilder(Settings.IndentType); if (!string.IsNullOrEmpty(currentNamespace)) { builder.AppendLine("namespace " + currentNamespace); builder.OpenBrace(); } UEnum lastEnum = enums.Last(); foreach (UEnum unrealEnum in enums) { SlowTaskStep(unrealEnum); GenerateCodeForEnum(module, builder, unrealEnum); if (unrealEnum != lastEnum) { builder.AppendLine(); } } if (!string.IsNullOrEmpty(currentNamespace)) { builder.CloseBrace(); } builder.InsertNamespaces(currentNamespace, namespaces, Settings.SortNamespaces); OnCodeGenerated(module, moduleAssetType, enumsName, null, builder); } else { foreach (UEnum unrealEnum in enums) { SlowTaskStep(unrealEnum); GenerateCodeForEnum(module, unrealEnum); } } }
private void UpdateModulesByName() { modulesByName.Clear(); Dictionary <FName, string> modulePaths = FModulesPaths.FindModulePaths("*"); foreach (KeyValuePair <FName, string> modulePath in modulePaths) { modulesByName[modulePath.Key] = UnrealModuleInfo.GetModuleType(modulePath.Value); } }
private void UpdateModulesByName() { modulesByName.Clear(); IPlugin[] plugins = IPluginManager.Instance.GetDiscoveredPlugins(); Dictionary <FName, string> modulePaths = FModulesPaths.FindModulePaths("*"); foreach (KeyValuePair <FName, string> modulePath in modulePaths) { modulesByName[modulePath.Key] = UnrealModuleInfo.GetModuleType(modulePath.Key.ToString(), modulePath.Value, plugins); } IPlugin.Dispose(plugins); }
private void OnEndGenerateModule(UnrealModuleInfo module) { if (codeManager != null) { string moduleInjectedClassesDir = Path.Combine(Settings.GetInjectedClassesDir(), module.Name); if (Directory.Exists(moduleInjectedClassesDir)) { foreach (string file in Directory.EnumerateFiles(moduleInjectedClassesDir, "*.cs", SearchOption.AllDirectories)) { // FIXME: UnrealModuleType is incorrect and may output non engine code in the wrong location string name = Path.GetFileNameWithoutExtension(file); codeManager.OnCodeGenerated(module, UnrealModuleType.Engine, name, null, File.ReadAllText(file)); } } } }
private void UpdateModulesByName() { modulesByName.Clear(); IPlugin[] plugins = IPluginManager.Instance.GetDiscoveredPlugins(); Dictionary <FName, string> modulePaths = FModulesPaths.FindModulePaths("*"); foreach (KeyValuePair <FName, string> modulePath in modulePaths) { modulesByName[modulePath.Key] = UnrealModuleInfo.GetModuleType(modulePath.Key.ToString(), modulePath.Value, plugins); } // Add the C# game code package name to the module list modulesByName[(FName)(Settings.GetProjectName() + "-Managed")] = UnrealModuleType.Game; IPlugin.Dispose(plugins); }
private void GenerateCodeForModule(UnrealModuleInfo module) { List <UStruct> structs = new List <UStruct>(); List <UEnum> enums = new List <UEnum>(); List <UFunction> globalFunctions = new List <UFunction>(); foreach (UStruct unrealStruct in new TObjectIterator <UStruct>()) { if (!unrealStruct.IsA <UFunction>() && unrealStruct.IsIn(module.Package) && CanExportStruct(unrealStruct) && IsAvailableType(unrealStruct)) { structs.Add(unrealStruct); } } foreach (UEnum unrealEnum in new TObjectIterator <UEnum>()) { if (unrealEnum.IsIn(module.Package) && CanExportEnum(unrealEnum) && IsAvailableType(unrealEnum)) { enums.Add(unrealEnum); } } UClass packageClass = UClass.GetClass <UPackage>(); foreach (UFunction function in new TObjectIterator <UFunction>()) { UObject outer = function.GetOuter(); if (outer == null || outer.GetClass() != packageClass) { continue; } if (function.HasAnyFunctionFlags(EFunctionFlags.Delegate | EFunctionFlags.MulticastDelegate) && function.IsIn(module.Package)) { globalFunctions.Add(function); } } SlowTaskSetModuleCount(1); SlowTaskBeginModule(FPackageName.GetShortName(module.Package), structs.Count + enums.Count + globalFunctions.Count); GenerateCodeForModule(module, structs.ToArray(), enums.ToArray(), globalFunctions.ToArray()); }
private void GenerateCodeForGlobalFunctions(UnrealModuleInfo module, UFunction[] globalFunctions) { if (globalFunctions.Length == 0) { return; } // Put all enums into a single file called ModulenameEnums string globalDelegatesName = module.Name + "GlobalDelegates"; UnrealModuleType moduleAssetType; string currentNamespace = GetModuleNamespace(globalFunctions[0], out moduleAssetType, false); List <string> namespaces = GetDefaultNamespaces(); CSharpTextBuilder builder = new CSharpTextBuilder(Settings.IndentType); if (!string.IsNullOrEmpty(currentNamespace)) { builder.AppendLine("namespace " + currentNamespace); builder.OpenBrace(); } foreach (UFunction function in globalFunctions) { if (function.HasAnyFunctionFlags(EFunctionFlags.Delegate | EFunctionFlags.MulticastDelegate)) { AppendDelegateSignature(module, builder, function, null, !function.HasAnyFunctionFlags(EFunctionFlags.Native), namespaces); builder.AppendLine(); } } // Remove any empty lines before adding the close brace builder.RemovePreviousEmptyLines(); if (!string.IsNullOrEmpty(currentNamespace)) { builder.CloseBrace(); } builder.InsertNamespaces(currentNamespace, namespaces, Settings.SortNamespaces); OnCodeGenerated(module, moduleAssetType, globalDelegatesName, null, builder); }
private void GenerateCodeForModule(UnrealModuleInfo module, UStruct[] structs, UEnum[] enums, UFunction[] globalFunctions) { if (structs.Length == 0 && enums.Length == 0 && globalFunctions.Length == 0) { return; } BeginGenerateModule(module); GenerateCodeForGlobalFunctions(module, globalFunctions); foreach (UStruct unrealStruct in structs) { GenerateCodeForStruct(module, unrealStruct); } GenerateCodeForEnums(module, enums, Settings.MergeEnumFiles); EndGenerateModule(module); }
private void GenerateCodeForEnum(UnrealModuleInfo module, CSharpTextBuilder builder, UEnum unrealEnum) { bool isBlueprintType = unrealEnum.IsA <UUserDefinedEnum>(); AppendDocComment(builder, unrealEnum, isBlueprintType); AppendAttribute(builder, unrealEnum, module); // Set the underlying enum type if this enum is tagged as a BlueprintType string enumUnderlyingType = string.Empty; if (unrealEnum.HasMetaData(MDEnum.BlueprintType)) { enumUnderlyingType = " : byte"; } builder.AppendLine("public enum " + GetTypeName(unrealEnum) + enumUnderlyingType); builder.OpenBrace(); // TODO: Blueprint value bitflags // According to issue UE-32816 "enum values are currently assumed to be flag indices and not actual flag mask values" List <EnumValueInfo> enumValues = GetEnumValues(unrealEnum, true); int lastEnumIndex = enumValues.Count; foreach (EnumValueInfo enumValue in enumValues) { AppendDocComment(builder, enumValue.DocCommentSummary); if (isBlueprintType) { builder.AppendLine("[EnumValueName(\"" + enumValue.Name + "\")]"); } builder.AppendLine(string.Format("{0}={1}{2}", isBlueprintType ? enumValue.DisplayName : enumValue.Name, enumValue.Value, --lastEnumIndex > 0 ? "," : string.Empty)); } builder.CloseBrace(); }
private void BeginGenerateModule(UnrealModuleInfo module) { OnBeginGenerateModule(module); }
private string GetFunctionSignatureImpl(UnrealModuleInfo module, UFunction function, UStruct owner, List <string> namespaces) { return(GetFunctionSignature(module, function, owner, null, null, false, true, namespaces)); }
private string GetFunctionSignature(UnrealModuleInfo module, UFunction function, UStruct owner, string customFunctionName, string customModifiers, bool stripAdditionalText, bool isImplementationMethod, List <string> namespaces) { bool isInterface = owner != null && owner.IsChildOf <UInterface>(); bool isDelegate = function.HasAnyFunctionFlags(EFunctionFlags.Delegate | EFunctionFlags.MulticastDelegate); bool isStatic = function.HasAnyFunctionFlags(EFunctionFlags.Static); bool isBlueprintType = owner != null && owner.IsA <UBlueprintGeneratedClass>(); StringBuilder modifiers = new StringBuilder(); if (!string.IsNullOrEmpty(customModifiers)) { modifiers.Append(customModifiers); } else if (isInterface) { // Don't provide any modifiers for interfaces if there isn't one already provided } else { UFunction originalFunction; // NOTE: "isImplementationMethod" is talking about "_Implementation" methods. // "isInterfaceImplementation" is talking about regular methods which are implementations for a interface. bool isInterfaceImplementation; UClass originalOwner = GetOriginalFunctionOwner(function, out originalFunction, out isInterfaceImplementation); // All interface functions in the chain need to be public bool isInterfaceFunc = originalOwner != owner && originalOwner.HasAnyClassFlags(EClassFlags.Interface); if (isImplementationMethod || (function.HasAnyFunctionFlags(EFunctionFlags.Protected) && !isInterfaceFunc && !isDelegate)) { modifiers.Append("protected"); } else { modifiers.Append("public"); } if (isDelegate) { modifiers.Append(" delegate"); } if (isStatic) { modifiers.Append(" static"); } if (!isDelegate && !isStatic) { if (function.HasAnyFunctionFlags(EFunctionFlags.BlueprintEvent)) { UFunction superFunc = function.GetSuperFunction(); if (superFunc != null) { modifiers.Append(" override"); } else { // This have should been filtered out in CanExportFunction() Debug.Assert(originalOwner == owner || isInterfaceImplementation); // Explicit will have the _Implementation as virtual and the function declaration as // non-virtual (which is the same as C++) if (!Settings.UseExplicitImplementationMethods || isImplementationMethod) { modifiers.Append(" virtual"); } } } else { if (originalOwner != owner && !isInterfaceFunc) { // Add "new" if the parent class has a function with the same name but not BlueprintEvent. // (don't do this for interface functions as we are implementing the function not redefining it) modifiers.Append(" new"); } } } } string returnType = "void"; int numReturns = 0; StringBuilder parameters = new StringBuilder(); // index is the index into parameters string Dictionary <int, string> parameterDefaultsByIndex = new Dictionary <int, string>(); // Once this is true all parameters from that point should also have defaults bool hasDefaultParameters = false; // Blueprint can define ref/out parameters with default values, this can't be translated to code bool invalidDefaultParams = false; // Info so we can avoid param name conflicts Dictionary <UProperty, string> paramNames = GetParamNames(function); // Generic array parameters string[] arrayParamNames = function.GetCommaSeperatedMetaData("ArrayParam"); // Generic parameters depending on array type string[] arrayTypeDependentParamNames = function.GetCommaSeperatedMetaData("ArrayTypeDependentParams"); // AutoCreateRefTerm will force ref on given parameter names (comma seperated) string[] autoRefParamNames = function.GetCommaSeperatedMetaData("AutoCreateRefTerm"); // If this is a blueprint type try and getting the return value from the first out param (if there is only one out) UProperty blueprintReturnProperty = function.GetBlueprintReturnProperty(); bool firstParameter = true; foreach (KeyValuePair <UProperty, string> param in paramNames) { UProperty parameter = param.Key; string paramName = param.Value; string rawParamName = parameter.GetName(); if (!parameter.HasAnyPropertyFlags(EPropertyFlags.Parm)) { continue; } if (parameter.HasAnyPropertyFlags(EPropertyFlags.ReturnParm) || parameter == blueprintReturnProperty) { returnType = GetTypeName(parameter, namespaces); numReturns++; } else { if (firstParameter) { firstParameter = false; } else { parameters.Append(", "); } if (!parameter.HasAnyPropertyFlags(EPropertyFlags.ConstParm)) { if (parameter.HasAnyPropertyFlags(EPropertyFlags.ReferenceParm) || autoRefParamNames.Contains(rawParamName)) { parameters.Append("ref "); } else if (parameter.HasAnyPropertyFlags(EPropertyFlags.OutParm)) { parameters.Append("out "); } } string paramTypeName = GetTypeName(parameter, namespaces); if (arrayParamNames.Contains(rawParamName)) { int genericsIndex = paramTypeName.IndexOf('<'); if (genericsIndex >= 0) { paramTypeName = paramTypeName.Substring(0, genericsIndex) + "<T>"; } } else if (arrayTypeDependentParamNames.Contains(rawParamName)) { paramTypeName = "T"; } parameters.Append(paramTypeName + " " + paramName); if (!invalidDefaultParams) { string defaultValue = GetParamDefaultValue(function, parameter, paramTypeName, ref hasDefaultParameters, ref invalidDefaultParams); if (!string.IsNullOrEmpty(defaultValue) && !invalidDefaultParams) { if (isBlueprintType && (parameter.HasAnyPropertyFlags(EPropertyFlags.ReferenceParm | EPropertyFlags.OutParm) || autoRefParamNames.Contains(rawParamName))) { invalidDefaultParams = true; } else { if (!hasDefaultParameters) { hasDefaultParameters = true; } parameterDefaultsByIndex[parameters.Length] = " = " + defaultValue; } } } } } if (numReturns > 1) { FMessage.Log(ELogVerbosity.Error, "More than 1 return on function '" + function.GetPathName() + "'"); } // Insert the default parameters if they aren't invalid if (!invalidDefaultParams) { int offset = 0; foreach (KeyValuePair <int, string> parameterDefault in parameterDefaultsByIndex) { parameters.Insert(parameterDefault.Key + offset, parameterDefault.Value); offset += parameterDefault.Value.Length; } } string functionName = GetFunctionName(function); string additionalStr = string.Empty; if (isDelegate) { functionName = GetTypeNameDelegate(function); additionalStr = ";"; } //if (isInterface) //{ // additionalStr = ";"; //} if (isImplementationMethod) { functionName += Settings.VarNames.ImplementationMethod; } if (!string.IsNullOrEmpty(customFunctionName)) { functionName = customFunctionName; } if (stripAdditionalText) { additionalStr = string.Empty; } string generics = string.Empty; if (arrayParamNames.Length > 0 || arrayTypeDependentParamNames.Length > 0) { generics = "<T>"; } if (modifiers.Length > 0) { modifiers.Append(' '); } return(string.Format("{0}{1} {2}{3}({4}){5}", modifiers, returnType, functionName, generics, parameters, additionalStr)); }
public void GenerateCodeForBlueprints(AssetLoadMode loadMode, bool clearAssetCache, bool skipLevels) { BeginGenerateModules(); string projectPath = FPaths.ProjectFilePath; string projectName = FPaths.GetBaseFilename(projectPath); UnrealModuleInfo module = new UnrealModuleInfo(null, projectName, projectPath); BeginGenerateModule(module); UClass worldClass = GCHelper.Find <UClass>(Classes.UWorld); AssetCache assetCache = new AssetCache(this); if (!clearAssetCache) { assetCache.Load(); } List <string> assetBlacklist = LoadAssetBlacklist(); AssetLogClear(); AssetLogLine("Load assets {0}", DateTime.Now); bool registeredCrashHandler = false; if (Settings.CatchCrashOnAssetLoading) { FCoreDelegates.OnHandleSystemError.Bind(OnAssetLoadingCrash); registeredCrashHandler = true; } using (FARFilter filter = new FARFilter()) { filter.RecursiveClasses = true; filter.ClassNames.Add(UClass.GetClass <UBlueprint>().GetFName()); filter.ClassNames.Add(UClass.GetClass <UBlueprintGeneratedClass>().GetFName()); filter.ClassNames.Add(UClass.GetClass <UUserDefinedStruct>().GetFName()); filter.ClassNames.Add(UClass.GetClass <UUserDefinedEnum>().GetFName()); if (!skipLevels && worldClass != null) { filter.ClassNames.Add(worldClass.GetFName()); } List <FAssetData> assets = FAssetData.Load(filter); SlowTaskSetModuleCount(1); SlowTaskBeginModule("Blueprints", assets.Count); foreach (FAssetData asset in assets) { SlowTaskStep(null); string assetFileName, assetFileNameError; if (!asset.TryGetFilename(out assetFileName, out assetFileNameError)) { FMessage.Log(string.Format("FAssetData.TryGetFilename failed. ObjectPath:'{0}' reason:'{1}'", asset.ObjectPath.ToString(), assetFileNameError)); continue; } bool isEngineAsset = FPaths.IsSameOrSubDirectory(FPaths.EngineContentDir, FPaths.GetPath(assetFileName)); if (loadMode != AssetLoadMode.All) { if ((isEngineAsset && loadMode != AssetLoadMode.Engine) || (!isEngineAsset && loadMode != AssetLoadMode.Game)) { continue; } } if (!assetCache.HasAssetChanged(asset, assetFileName)) { if (Settings.LogAssetLoadingVerbose) { AssetLogLine("'{0}' unchanged", assetFileName); } continue; } // Log that we are loading this asset so we know which assets crash on load AssetLog("'{0}' - ", asset.ObjectPath.ToString()); if (assetBlacklist.Contains(asset.ObjectPath.ToString())) { AssetLogLine("blacklisted"); continue; } loadingAsset = asset.ObjectPath.ToString(); UObject obj = asset.GetAsset(); loadingAsset = null; UClass unrealClass = asset.GetClass(); if (obj == null || unrealClass == null) { AssetLogLine("null"); continue; } AssetLogLine("done"); if (unrealClass.IsChildOf <UBlueprint>()) { UBlueprint blueprint = obj as UBlueprint; if (blueprint != null) { UBlueprintGeneratedClass blueprintGeneratedClass = blueprint.GeneratedClass as UBlueprintGeneratedClass; if (blueprintGeneratedClass != null) { GenerateCodeForStruct(module, blueprintGeneratedClass); } } } else if (unrealClass.IsChildOf <UBlueprintGeneratedClass>()) { UBlueprintGeneratedClass blueprintGeneratedClass = obj as UBlueprintGeneratedClass; if (blueprintGeneratedClass != null) { GenerateCodeForStruct(module, blueprintGeneratedClass); } } else if (unrealClass.IsChildOf <UUserDefinedStruct>()) { UUserDefinedStruct unrealStruct = obj as UUserDefinedStruct; if (unrealStruct != null) { GenerateCodeForStruct(module, unrealStruct); } } else if (unrealClass.IsChildOf <UUserDefinedEnum>()) { UUserDefinedEnum unrealEnum = obj as UUserDefinedEnum; if (unrealEnum != null) { GenerateCodeForEnum(module, unrealEnum); } } else if (unrealClass.IsChildOf(worldClass)) { TArrayUnsafeRef <UObject> levels = new TArrayUnsafeRef <UObject>(Native.Native_UWorld.GetLevels(obj.Address)); foreach (UObject level in levels) { using (TArrayUnsafe <UBlueprint> levelBlueprints = new TArrayUnsafe <UBlueprint>()) { Native.Native_ULevel.GetLevelBlueprints(level.Address, levelBlueprints.Address); foreach (UBlueprint blueprint in levelBlueprints) { UBlueprintGeneratedClass blueprintGeneratedClass = blueprint.GeneratedClass as UBlueprintGeneratedClass; if (blueprintGeneratedClass != null) { //GenerateCodeForStruct(blueprintGeneratedClass); } } } } } } } if (registeredCrashHandler) { FCoreDelegates.OnHandleSystemError.Unbind(OnAssetLoadingCrash); } assetCache.Save(); EndGenerateModule(module); EndGenerateModules(); }
private void AppendDelegateSignature(UnrealModuleInfo module, CSharpTextBuilder builder, UFunction function, UStruct owner, bool isBlueprintType, List <string> namespaces) { AppendDocComment(builder, function, isBlueprintType); AppendAttribute(builder, function, module); string delegateBaseTypeName = function.HasAnyFunctionFlags(EFunctionFlags.MulticastDelegate) ? Names.FMulticastDelegate : Names.FDelegate; string delegateTypeName = GetTypeNameDelegate(function); builder.AppendLine("public class " + delegateTypeName + " : " + delegateBaseTypeName + "<" + delegateTypeName + "." + Settings.VarNames.DelegateSignature + ">"); builder.OpenBrace(); builder.AppendLine(GetFunctionSignature( module, function, owner, Settings.VarNames.DelegateSignature, "public delegate", false, false, namespaces)); builder.AppendLine(); builder.AppendLine("public override " + Settings.VarNames.DelegateSignature + " " + Names.FDelegateBase_GetInvoker + "()"); builder.OpenBrace(); builder.AppendLine("return " + Settings.VarNames.DelegateInvoker + ";"); builder.CloseBrace(); builder.AppendLine(); string functionName = GetFunctionName(function); Dictionary <UProperty, string> paramNames = GetParamNames(function); // Offsets if (Settings.GenerateIsValidSafeguards) { builder.AppendLine("static bool " + functionName + Settings.VarNames.IsValid + ";"); } builder.AppendLine("static IntPtr " + functionName + Settings.VarNames.FunctionAddress + ";"); builder.AppendLine("static int " + functionName + Settings.VarNames.ParamsSize + ";"); foreach (KeyValuePair <UProperty, string> param in paramNames) { UProperty parameter = param.Key; string paramName = param.Value; if (!parameter.HasAnyPropertyFlags(EPropertyFlags.Parm)) { continue; } AppendPropertyOffset(builder, functionName + "_" + paramName, parameter, true, namespaces); } // Add the native type info initializer to get the offsets builder.AppendLine("static void " + Settings.VarNames.LoadNativeType + "()"); builder.OpenBrace(); builder.AppendLine(functionName + Settings.VarNames.FunctionAddress + " = " + Names.NativeReflection_GetFunction + "(\"" + function.GetPathName() + "\");"); builder.AppendLine(functionName + Settings.VarNames.ParamsSize + " = " + Names.NativeReflection_GetFunctionParamsSize + "(" + functionName + Settings.VarNames.FunctionAddress + ");"); foreach (KeyValuePair <UProperty, string> param in paramNames) { UProperty parameter = param.Key; string paramName = param.Value; if (!parameter.HasAnyPropertyFlags(EPropertyFlags.Parm)) { continue; } AppendPropertyOffsetNativeTypeLoader(builder, functionName + "_" + paramName, parameter, functionName); } if (Settings.GenerateIsValidSafeguards) { // XXXX_IsValid = param1_IsValid && param2_IsValid && param3_IsValid; string paramsValid = string.Join(" && ", paramNames.Values.Select(x => functionName + "_" + x + Settings.VarNames.IsValid)); if (!string.IsNullOrEmpty(paramsValid)) { paramsValid = " && " + paramsValid; } builder.AppendLine(functionName + Settings.VarNames.IsValid + " = " + functionName + Settings.VarNames.FunctionAddress + " != IntPtr.Zero" + paramsValid + ";"); builder.AppendLine(Names.NativeReflection_LogFunctionIsValid + "(\"" + function.GetPathName() + "\", " + functionName + Settings.VarNames.IsValid + ");"); } builder.CloseBrace(); builder.AppendLine(); builder.AppendLine(GetFunctionSignature( module, function, owner, Settings.VarNames.DelegateInvoker, "private", true, false, namespaces)); builder.OpenBrace(); AppendFunctionBody(builder, function, false, false, false, namespaces); builder.CloseBrace(); builder.CloseBrace(); }
private void AppendAttribute(CSharpTextBuilder builder, UField field, UnrealModuleInfo module) { AppendAttribute(builder, field, module, false); }
private void GenerateCodeForStruct(UnrealModuleInfo module, UStruct unrealStruct) { bool isBlueprintType = unrealStruct.IsA <UUserDefinedStruct>() || unrealStruct.IsA <UBlueprintGeneratedClass>(); StructInfo structInfo = GetStructInfo(unrealStruct, isBlueprintType); string typeName = GetTypeName(unrealStruct); UnrealModuleType moduleAssetType; string currentNamespace = GetModuleNamespace(unrealStruct, out moduleAssetType); List <string> namespaces = GetDefaultNamespaces(); CSharpTextBuilder builder = new CSharpTextBuilder(Settings.IndentType); if (!string.IsNullOrEmpty(currentNamespace)) { builder.AppendLine("namespace " + currentNamespace); builder.OpenBrace(); } string accessSpecifier = "public"; StringBuilder modifiers = new StringBuilder(accessSpecifier); if (Settings.UseAbstractTypes && structInfo.IsClass && structInfo.Class.HasAnyClassFlags(EClassFlags.Abstract)) { modifiers.Append(" abstract"); } StringBuilder baseTypeStr = new StringBuilder(); UStruct parentStruct = unrealStruct.GetSuperStruct(); if (parentStruct != null && parentStruct != UClass.GetClass <UInterface>() && unrealStruct != UClass.GetClass <UInterface>()) { baseTypeStr.Append(GetTypeName(parentStruct, namespaces)); } if (structInfo.IsClass) { foreach (FImplementedInterface implementedInterface in structInfo.Class.Interfaces) { if (baseTypeStr.Length > 0) { baseTypeStr.Append(", "); } baseTypeStr.Append(GetTypeName(implementedInterface.InterfaceClass, namespaces)); } } if (baseTypeStr.Length > 0) { baseTypeStr.Insert(0, " : "); } AppendDocComment(builder, unrealStruct, isBlueprintType); AppendAttribute(builder, unrealStruct, module, structInfo); if (structInfo.IsInterface) { System.Diagnostics.Debug.Assert(structInfo.Class.Interfaces.Length == 0, "TODO: Interfaces inheriting other interfaces"); string baseInterface = unrealStruct == UClass.GetClass <UInterface>() ? string.Empty : (baseTypeStr.Length == 0 ? " : " : ", ") + Names.IInterface; builder.AppendLine(modifiers + " interface " + typeName + baseTypeStr + baseInterface); } else if (structInfo.IsClass) { builder.AppendLine(modifiers + " partial class " + typeName + baseTypeStr); } else { if (structInfo.StructAsClass) { builder.AppendLine(modifiers + " partial class " + typeName + " : " + Names.StructAsClass); } else { if (structInfo.IsBlittable) { string structLayout = UpdateTypeNameNamespace("StructLayout", "System.Runtime.InteropServices", namespaces); string layoutKind = UpdateTypeNameNamespace("LayoutKind", "System.Runtime.InteropServices", namespaces); builder.AppendLine("[" + structLayout + "(" + layoutKind + ".Sequential)]"); } builder.AppendLine(modifiers + " partial struct " + typeName); } } builder.OpenBrace(); string typeNameEx = structInfo.IsInterface ? typeName + "Impl" : typeName; // Create a seperate builder for building the interface "Impl" class CSharpTextBuilder interfaceImplBuilder = null; if (structInfo.IsInterface) { interfaceImplBuilder = new CSharpTextBuilder(); interfaceImplBuilder.AppendLine(accessSpecifier + " sealed class " + typeNameEx + " : " + Names.IInterfaceImpl + ", " + typeName); interfaceImplBuilder.Indent(); // Move the indent to the same as builder for this point interfaceImplBuilder.OpenBrace(); // Open the class brace } // Create a seperate builder for properties which will be inserted into the native type info initializer CSharpTextBuilder offsetsBuilder = new CSharpTextBuilder(Settings.IndentType); offsetsBuilder.AppendLine("static " + typeNameEx + "()"); offsetsBuilder.IndentCount = builder.IndentCount;// Move the indent to the same as builder offsetsBuilder.OpenBrace(); offsetsBuilder.AppendLine("if (" + Names.UnrealTypes_CanLazyLoadNativeType + "(typeof(" + typeNameEx + ")))"); offsetsBuilder.OpenBrace(); offsetsBuilder.AppendLine(Settings.VarNames.LoadNativeType + "();"); offsetsBuilder.CloseBrace(); offsetsBuilder.AppendLine(Names.UnrealTypes_OnCCtorCalled + "(typeof(" + typeNameEx + "));"); offsetsBuilder.CloseBrace(); offsetsBuilder.AppendLine(); offsetsBuilder.AppendLine("static void " + Settings.VarNames.LoadNativeType + "()"); offsetsBuilder.OpenBrace(); if (structInfo.HasStaticFunction) { builder.AppendLine("static IntPtr " + Settings.VarNames.ClassAddress + ";"); offsetsBuilder.AppendLine(Settings.VarNames.ClassAddress + " = " + (structInfo.IsStruct ? Names.NativeReflection_GetStruct : Names.NativeReflection_GetClass) + "(\"" + unrealStruct.GetPathName() + "\");"); } else { offsetsBuilder.AppendLine("IntPtr " + Settings.VarNames.ClassAddress + " = " + (structInfo.IsStruct ? Names.NativeReflection_GetStruct : Names.NativeReflection_GetClass) + "(\"" + unrealStruct.GetPathName() + "\");"); } if (structInfo.StructAsClass) { offsetsBuilder.AppendLine(typeName + Settings.VarNames.StructAddress + " = " + Settings.VarNames.ClassAddress + ";"); } else if (structInfo.IsStruct) { offsetsBuilder.AppendLine(typeName + Settings.VarNames.StructSize + " = " + Names.NativeReflection_GetStructSize + "(" + Settings.VarNames.ClassAddress + ");"); } if (structInfo.IsStruct && parentStruct != null) { // Export base properties if (Settings.InlineBaseStruct || structInfo.StructAsClass) { UScriptStruct tempParentStruct = parentStruct as UScriptStruct; while (tempParentStruct != null) { StructInfo tempParentStructInfo = GetStructInfo(tempParentStruct); if (tempParentStructInfo != null) { foreach (UProperty property in tempParentStructInfo.GetProperties()) { if (!tempParentStructInfo.IsCollapsedProperty(property)) { GenerateCodeForProperty(module, builder, offsetsBuilder, property, tempParentStructInfo.IsBlueprintType, structInfo, namespaces, tempParentStructInfo.GetPropertyName(property)); } } } tempParentStruct = tempParentStruct.GetSuperStruct() as UScriptStruct; } } else { builder.AppendLine(GetTypeName(parentStruct, namespaces) + " Base;"); } } // Export properties foreach (UProperty property in structInfo.GetProperties()) { if (!structInfo.IsCollapsedProperty(property)) { GenerateCodeForProperty(module, builder, offsetsBuilder, property, isBlueprintType, structInfo, namespaces, structInfo.GetPropertyName(property)); } } foreach (CollapsedMember collapsedMember in structInfo.GetCollapsedMembers()) { GenerateCodeForProperty(module, builder, offsetsBuilder, collapsedMember, isBlueprintType, namespaces); } // Export functions List <ExtensionMethodInfo> extensionMethods = new List <ExtensionMethodInfo>(); foreach (UFunction function in structInfo.GetFunctions()) { if (!structInfo.IsCollapsedFunction(function)) { if (!structInfo.IsInterface) { // If this isn't an interface and the function can be made into an extension method then do so ExtensionMethodInfo extensionMethodInfo = ExtensionMethodInfo.Create(function); if (extensionMethodInfo != null) { extensionMethods.Add(extensionMethodInfo); } } if (function.HasAnyFunctionFlags(EFunctionFlags.Delegate | EFunctionFlags.MulticastDelegate)) { AppendDelegateSignature(module, builder, function, unrealStruct, isBlueprintType, namespaces); builder.AppendLine(); } else if (structInfo.IsInterface) { AppendFunctionOffsets(interfaceImplBuilder, offsetsBuilder, function, false, false, namespaces); AppendDocComment(builder, function, isBlueprintType); AppendAttribute(builder, function, module); builder.AppendLine(GetFunctionSignature(module, function, unrealStruct, namespaces) + ";"); builder.AppendLine(); // Always require a per-instance function address on the interfaces "Impl" class. // This isn't really required if the target function isn't an event but since we are working // with interfaces it is probably best to make sure functions are resolved properly. If we decide // to change this to not require a per-instance function address make sure to update AppendFunctionOffsets // which adds the per-instance function address to the class. Also update AssemblyRewriter.Interface.cs // Also update the "ResetInterface" code which always expects an per-instance address to reset. AppendAttribute(interfaceImplBuilder, function, module); interfaceImplBuilder.AppendLine(GetFunctionSignature(module, function, unrealStruct, null, "public", FunctionSigFlags.None, namespaces)); interfaceImplBuilder.OpenBrace(); AppendFunctionBody(interfaceImplBuilder, function, false, false, true, namespaces); interfaceImplBuilder.CloseBrace(); builder.AppendLine(); } else { AppendFunctionOffsets(builder, offsetsBuilder, function, false, false, namespaces); AppendDocComment(builder, function, isBlueprintType); AppendAttribute(builder, function, module); bool hasSuperFunction = function.GetSuperFunction() != null; if (function.HasAnyFunctionFlags(EFunctionFlags.BlueprintEvent) && !hasSuperFunction) { // Define the declaration method which will call the correct UFunction for the UObject instance builder.AppendLine(GetFunctionSignature(module, function, unrealStruct, namespaces)); builder.OpenBrace(); AppendFunctionBody(builder, function, false, false, true, namespaces); builder.CloseBrace(); builder.AppendLine(); } if (function.HasAnyFunctionFlags(EFunctionFlags.BlueprintEvent)) { if (!Settings.UseExplicitImplementationMethods) { // Used to hide the _Implementation method from being visible in intellisense builder.AppendLine("[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]"); } // Define the _Implementation method builder.AppendLine(GetFunctionSignatureImpl(module, function, unrealStruct, namespaces)); } else { builder.AppendLine(GetFunctionSignature(module, function, unrealStruct, namespaces)); } builder.OpenBrace(); AppendFunctionBody(builder, function, false, false, false, namespaces); builder.CloseBrace(); builder.AppendLine(); } } } if (structInfo.StructAsClass) { if (Settings.GenerateIsValidSafeguards) { builder.AppendLine("static bool " + typeName + Settings.VarNames.IsValid + ";"); // Append XXXX_IsValid = Prop1_IsValid && Prop2_IsValid && Prop3_IsValid...; AppendStructIsValid(offsetsBuilder, typeName, structInfo, parentStruct); } builder.AppendLine("static IntPtr " + typeName + Settings.VarNames.StructAddress + ";"); builder.AppendLine(); builder.AppendLine("protected override IntPtr GetStructAddress()"); builder.OpenBrace(); builder.AppendLine("return " + typeName + Settings.VarNames.StructAddress + ";"); builder.CloseBrace(); builder.AppendLine(); } else if (structInfo.IsStruct) { if (Settings.GenerateIsValidSafeguards && !structInfo.IsBlittable) { builder.AppendLine("static bool " + typeName + Settings.VarNames.IsValid + ";"); } builder.AppendLine("static int " + typeName + Settings.VarNames.StructSize + ";"); builder.AppendLine(); // Add the struct Copy() method (for non blittable structs) builder.AppendLine("public " + typeName + " " + Settings.VarNames.StructCopy + "()"); builder.OpenBrace(); builder.AppendLine(typeName + " result = this;"); foreach (UProperty property in structInfo.GetProperties()) { if (!structInfo.IsCollapsedProperty(property) && IsCollectionProperty(property)) { string propertyName = GetMemberName(property, structInfo.GetPropertyName(property)); builder.AppendLine("if (this." + propertyName + " != null)"); builder.OpenBrace(); UStructProperty structProperty = property as UStructProperty; StructInfo propertyStructInfo = structProperty == null || structProperty.Struct == null ? null : GetStructInfo(structProperty.Struct); if (propertyStructInfo != null && !propertyStructInfo.IsBlittable) { builder.AppendLine("result." + propertyName + " = new " + GetTypeName(property, namespaces) + "();"); builder.AppendLine("for (int i = 0; i < this." + propertyName + ".Count; ++i)"); builder.OpenBrace(); builder.AppendLine("result." + propertyName + ".Add(this." + propertyName + "[i]." + Settings.VarNames.StructCopy + "());"); builder.CloseBrace(); } else { builder.AppendLine("result." + propertyName + " = new " + GetTypeName(property, namespaces) + "(" + "this." + propertyName + ");"); } builder.CloseBrace(); } } if (Settings.InlineBaseStruct) { UScriptStruct tempParentStruct = parentStruct as UScriptStruct; while (tempParentStruct != null) { StructInfo tempParentStructInfo = GetStructInfo(tempParentStruct); if (tempParentStructInfo != null) { foreach (UProperty property in tempParentStructInfo.GetProperties()) { if (!tempParentStructInfo.IsCollapsedProperty(property) && IsCollectionProperty(property)) { string propertyName = GetMemberName(property, tempParentStructInfo.GetPropertyName(property)); builder.AppendLine("if (this." + propertyName + " != null)"); builder.OpenBrace(); builder.AppendLine("result." + propertyName + " = new " + GetTypeName(property, namespaces) + "(" + "this." + propertyName + ");"); builder.CloseBrace(); } } } tempParentStruct = tempParentStruct.GetSuperStruct() as UScriptStruct; } } builder.AppendLine("return result;"); builder.CloseBrace(); builder.AppendLine(); if (structInfo.IsBlittable) { // Validate the size of the blittable struct offsetsBuilder.AppendLine(Names.NativeReflection_ValidateBlittableStructSize + "(" + Settings.VarNames.ClassAddress + ", typeof(" + typeName + "));"); } else { if (Settings.GenerateIsValidSafeguards) { // Append XXXX_IsValid = Prop1_IsValid && Prop2_IsValid && Prop3_IsValid...; AppendStructIsValid(offsetsBuilder, typeName, structInfo, parentStruct); } builder.AppendLine("public static " + typeName + " FromNative(IntPtr nativeBuffer)"); builder.OpenBrace(); builder.AppendLine("return new " + typeName + "(nativeBuffer);"); builder.CloseBrace(); builder.AppendLine(); builder.AppendLine("public static void ToNative(IntPtr nativeBuffer, " + typeName + " value)"); builder.OpenBrace(); builder.AppendLine("value.ToNative(nativeBuffer);"); builder.CloseBrace(); builder.AppendLine(); builder.AppendLine("public static " + typeName + " FromNative(IntPtr nativeBuffer, int arrayIndex, IntPtr prop)"); builder.OpenBrace(); builder.AppendLine("return new " + typeName + "(nativeBuffer + (arrayIndex * " + typeName + Settings.VarNames.StructSize + "));"); builder.CloseBrace(); builder.AppendLine(); builder.AppendLine("public static void ToNative(IntPtr nativeBuffer, int arrayIndex, IntPtr prop, " + typeName + " value)"); builder.OpenBrace(); builder.AppendLine("value.ToNative(nativeBuffer + (arrayIndex * " + typeName + Settings.VarNames.StructSize + "));"); builder.CloseBrace(); builder.AppendLine(); builder.AppendLine("public void ToNative(IntPtr nativeStruct)"); builder.OpenBrace(); AppendStructMarshalerBody(builder, typeName, structInfo, parentStruct, true, namespaces); builder.CloseBrace(); builder.AppendLine(); builder.AppendLine("public " + typeName + "(IntPtr nativeStruct)"); builder.OpenBrace(); /*if (Settings.UObjectAsBlittableType) * { * // UObject types will have an additional backing field which needs to be assigned before being able to * // assign the property * // - The alternative would be to modify the property assignment code to target the backing field instead of * // the property. This is probably the ideal way of doing it but we would need to use a different marshaler * // (BlittableTypeMarshaler<> instead of UObjectMarshaler<>) and ensure the marshaler change doesn't impact * // other generated code elsewhere. * foreach (UProperty property in structInfo.GetProperties()) * { * UObjectProperty objectProperty = property as UObjectProperty; * if (objectProperty != null) * { * string propertyName = GetMemberName(property, structInfo.GetPropertyName(property)); * builder.AppendLine(propertyName + Settings.VarNames.UObjectBlittableName + " = IntPtr.Zero;"); * } * } * }*/ AppendStructMarshalerBody(builder, typeName, structInfo, parentStruct, false, namespaces); builder.CloseBrace(); builder.AppendLine(); } } if (loadNativeTypeInjected.Contains(typeName)) { offsetsBuilder.AppendLine(Settings.VarNames.LoadNativeTypeInjected + "(" + Settings.VarNames.ClassAddress + ");"); } offsetsBuilder.CloseBrace(); // Add the offsets builder if it isn't empty (always required for structs due to struct size export) // Interfaces are built up seperately in a different class which must be added after the interface body. if (!structInfo.IsInterface && (structInfo.HasContent || structInfo.IsStruct)) { builder.AppendLine(offsetsBuilder.ToString()); builder.AppendLine(); } // Remove any trailing empty lines before adding the close brace builder.RemovePreviousEmptyLines(); builder.CloseBrace(); // Add the "Impl" wrapper class for interfaces. This is always required so that we have a default // interface implementation that we can call. if (structInfo.IsInterface) { if (structInfo.HasContent) { interfaceImplBuilder.AppendLine();// Whitespace // Add the ResetInterface method to reset the state of a pooled interface instance interfaceImplBuilder.AppendLine("public override void ResetInterface()"); interfaceImplBuilder.OpenBrace(); foreach (UFunction function in structInfo.GetFunctions()) { interfaceImplBuilder.AppendLine(GetFunctionName(function) + Settings.VarNames.InstanceFunctionAddress + " = IntPtr.Zero;"); } interfaceImplBuilder.CloseBrace(); interfaceImplBuilder.AppendLine(); // Whitespace } interfaceImplBuilder.AppendLine(offsetsBuilder.ToString()); // Add the offsets to the "Impl" class interfaceImplBuilder.CloseBrace(); // Add the close brace for the "Impl" class builder.AppendLine(); // Empty line between interface and "Impl" class builder.AppendLine(interfaceImplBuilder.ToString()); // Add the "Impl" class below the interface } if (!string.IsNullOrEmpty(currentNamespace)) { builder.CloseBrace(); } builder.InsertNamespaces(currentNamespace, namespaces, Settings.SortNamespaces); OnCodeGenerated(module, moduleAssetType, typeName, unrealStruct.GetPathName(), builder); if (extensionMethods.Count > 0) { GenerateCodeForExtensionMethods(module, unrealStruct, extensionMethods); } }
private void GenerateCodeForProperty(UnrealModuleInfo module, CSharpTextBuilder builder, CSharpTextBuilder offsetsBuilder, CollapsedMember collapsedMember, bool isBlueprintType, List <string> namespaces) { StringBuilder modifiers = new StringBuilder(); if (collapsedMember.BackingProperty != null) { UProperty property = collapsedMember.BackingProperty; if (property.HasAnyPropertyFlags(EPropertyFlags.DisableEditOnInstance) && !property.GetBoolMetaData(MDProp.AllowPrivateAccess)) { modifiers.Append("private"); } else if (property.HasAnyPropertyFlags(EPropertyFlags.NativeAccessSpecifierProtected | EPropertyFlags.Protected)) { modifiers.Append("protected"); } else { modifiers.Append("public"); } } else { UFunction function = collapsedMember.Getter != null ? collapsedMember.Getter : collapsedMember.Setter; if (function.HasAnyFunctionFlags(EFunctionFlags.Protected)) { modifiers.Append("protected"); } else { modifiers.Append("public"); } } if (modifiers.Length > 0) { modifiers.Append(" "); } // Note: Potential issues with different categories/docs/attribute on BackingProperty/Getter/Setter UField field = collapsedMember.BackingProperty; if (field == null) { field = collapsedMember.Getter; if (field == null) { field = collapsedMember.Setter; } } // Use either the backing property or the getter function for the documentation UField fieldForDocumentation = collapsedMember.BackingProperty != null ? (UField)collapsedMember.BackingProperty : collapsedMember.Getter; string name = collapsedMember.ResolvedName != null ? collapsedMember.ResolvedName : collapsedMember.Name; string propertyName = GetName(field, name, Settings.MemberCasing, false, true); AppendGetterSetterOffsets(builder, offsetsBuilder, propertyName, collapsedMember.Getter == null || collapsedMember.Setter == null ? collapsedMember.BackingProperty : null, namespaces, collapsedMember.Getter, collapsedMember.Setter); AppendDocComment(builder, fieldForDocumentation, isBlueprintType); AppendAttribute(builder, field, module, true); builder.AppendLine(modifiers + GetTypeName(collapsedMember.Property, namespaces) + " " + propertyName); builder.OpenBrace(); if (collapsedMember.Getter != null) { AppendGetter(builder, propertyName, collapsedMember.Getter, namespaces); } else if (collapsedMember.BackingProperty != null) { AppendGetter(builder, propertyName, collapsedMember.BackingProperty, namespaces); } if (collapsedMember.Setter != null) { AppendSetter(builder, propertyName, collapsedMember.Setter, namespaces); } else if (collapsedMember.BackingProperty != null) { AppendSetter(builder, propertyName, collapsedMember.BackingProperty, namespaces); } builder.CloseBrace(); builder.AppendLine(); }
private void EndGenerateModule(UnrealModuleInfo module) { OnEndGenerateModule(module); }
private void AppendAttribute(CSharpTextBuilder builder, UField field, UnrealModuleInfo module, bool isCollapsedMember) { UnrealModuleType moduleType; UnrealModuleType moduleAssetType; string moduleName = GetModuleName(field, out moduleType, out moduleAssetType); if (string.IsNullOrEmpty(moduleName)) { moduleName = module.Name; } List <string> attributes = new List <string>(); // TODO: Combine all of this into EPropertyType (add some TypeCode into UField?) bool isInterface = false; UEnum unrealEnum = field as UEnum; UClass unrealClass = field as UClass; UScriptStruct unrealStruct = field as UScriptStruct; UFunction unrealFunction = field as UFunction; if (unrealFunction != null) { if (unrealFunction.HasAnyFunctionFlags(EFunctionFlags.Delegate)) { attributes.Add("UDelegate"); } else { string additionalFunctionInfo = string.Empty; // TODO: Only get the script name for virtual functions / interface functions as we currently only need // this for finding the base function for hooking things up to the native base types. string scriptFunctionName; if (unrealFunction.GetScriptName(out scriptFunctionName)) { additionalFunctionInfo += ", OriginalName=\"" + unrealFunction.GetName() + "\""; } if (isCollapsedMember) { // The Flags here might not contain too useful information if there is both a get/set function. // Maybe include a second flags var? attributes.Add("UFunctionAsProp(Flags=0x" + ((uint)unrealFunction.FunctionFlags).ToString("X8") + additionalFunctionInfo + ")"); } else { attributes.Add("UFunction(Flags=0x" + ((uint)unrealFunction.FunctionFlags).ToString("X8") + additionalFunctionInfo + ")"); } } } UProperty unrealProperty = field as UProperty; if (unrealProperty != null) { attributes.Add("UProperty(Flags=(PropFlags)0x" + ((ulong)unrealProperty.PropertyFlags).ToString("X16") + ")"); } if (unrealStruct != null) { attributes.Add("UStruct(Flags=0x" + ((uint)unrealStruct.StructFlags).ToString("X8") + ")"); } else if (unrealClass != null) { // Abstract isn't really required but might help with code browsing to know what is abstract // and what isn't. Therefore put it at the start of the attributes list. if (unrealClass.HasAnyClassFlags(EClassFlags.Abstract)) { attributes.Add("Abstract"); } isInterface = unrealClass.IsChildOf <UInterface>(); if (isInterface) { attributes.Add("UInterface(Flags=0x" + ((uint)unrealClass.ClassFlags).ToString("X8") + ")"); } else { attributes.Add("UClass(Flags=(ClassFlags)0x" + ((uint)unrealClass.ClassFlags).ToString("X8") + ")"); } } if (unrealEnum != null) { attributes.Add("UEnum"); } if (unrealEnum != null || unrealClass != null || unrealStruct != null) { bool blueprintType = false; bool blueprintable = false; if (unrealEnum != null) { blueprintType = field.GetBoolMetaData(MDClass.BlueprintType); } else { GetBlueprintability(field as UStruct, out blueprintType, out blueprintable); } if (blueprintType) { attributes.Add(UMeta.GetKey(MDClass.BlueprintType)); } if (unrealClass != null && blueprintable) { attributes.Add(UMeta.GetKey(MDClass.Blueprintable)); } attributes.Add("UMetaPath(\"" + field.GetPathName() + "\"" + (isInterface ? ", InterfaceImpl=typeof(" + GetTypeName(unrealClass, null) + "Impl" + ")" : string.Empty) + ")"); } else { attributes.Add("UMetaPath(\"" + field.GetPathName() + "\")"); } if (attributes.Count > 0) { builder.AppendLine("[" + string.Join(", ", attributes) + "]"); } }
public void GenerateCodeForModules(UnrealModuleType[] moduleTypes) { BeginGenerateModules(); HashSet <string> moduleNamesWhitelistToLower = new HashSet <string>(); foreach (string moduleName in ModulesNamesWhitelist) { moduleNamesWhitelistToLower.Add(moduleName.ToLower()); } HashSet <string> moduleNamesBlacklistToLower = new HashSet <string>(); foreach (string moduleName in ModulesNamesBlacklist) { moduleNamesBlacklistToLower.Add(moduleName.ToLower()); } Dictionary <UPackage, List <UStruct> > structsByPackage = new Dictionary <UPackage, List <UStruct> >(); Dictionary <UPackage, List <UEnum> > enumsByPackage = new Dictionary <UPackage, List <UEnum> >(); Dictionary <UPackage, List <UFunction> > globalFunctionsByPackage = new Dictionary <UPackage, List <UFunction> >(); foreach (UStruct unrealStruct in new TObjectIterator <UStruct>()) { if (!unrealStruct.IsA <UFunction>() && CanExportStruct(unrealStruct) && IsAvailableType(unrealStruct)) { UPackage package = unrealStruct.GetOutermost(); if (package != null) { List <UStruct> structs; if (!structsByPackage.TryGetValue(package, out structs)) { structsByPackage.Add(package, structs = new List <UStruct>()); } structs.Add(unrealStruct); } } } foreach (UEnum unrealEnum in new TObjectIterator <UEnum>()) { if (CanExportEnum(unrealEnum) && IsAvailableType(unrealEnum)) { UPackage package = unrealEnum.GetOutermost(); if (package != null) { List <UEnum> enums; if (!enumsByPackage.TryGetValue(package, out enums)) { enumsByPackage.Add(package, enums = new List <UEnum>()); } enums.Add(unrealEnum); } } } UClass packageClass = UClass.GetClass <UPackage>(); foreach (UFunction function in new TObjectIterator <UFunction>()) { UObject outer = function.GetOuter(); if (outer == null || outer.GetClass() != packageClass) { continue; } if (function.HasAnyFunctionFlags(EFunctionFlags.Delegate | EFunctionFlags.MulticastDelegate)) { UPackage package = function.GetOutermost(); if (package != null) { List <UFunction> functions; if (!globalFunctionsByPackage.TryGetValue(package, out functions)) { globalFunctionsByPackage.Add(package, functions = new List <UFunction>()); } functions.Add(function); } } else { FMessage.Log(ELogVerbosity.Error, string.Format("Global function which isn't a delegate '{0}'", function.GetName())); } } Dictionary <FName, string> modulePaths = FModulesPaths.FindModulePaths("*"); // Make sure ModulePaths and ModuleNames are the same. Based on comments FindModules may be changed/removed in the // future so we will want to just use FindModulePaths. For now make sure they are synced up. FName[] moduleNames = FModuleManager.Get().FindModules("*"); if (moduleNames.Length != modulePaths.Count) { FMessage.Log(ELogVerbosity.Warning, string.Format("Module count invalid (update FModulePaths). FindModules:{0} FindModulePaths:{1}", moduleNames.Length, modulePaths.Count)); List <FName> additionalNames = new List <FName>(); foreach (KeyValuePair <FName, string> module in modulePaths) { if (moduleNames.Contains(module.Key)) { FMessage.Log(ELogVerbosity.Warning, "Module: " + module.Key + " - " + module.Value); } else { FMessage.Log(ELogVerbosity.Warning, "Additional module: " + module.Key + " - " + module.Value); } } List <FName> missingNames = new List <FName>(); foreach (FName moduleName in moduleNames) { if (!modulePaths.ContainsKey(moduleName)) { FMessage.Log(ELogVerbosity.Warning, "Missing module: " + moduleName); } } } IPlugin[] plugins = IPluginManager.Instance.GetDiscoveredPlugins(); SlowTaskSetModuleCount(modulePaths.Count); foreach (KeyValuePair <FName, string> modulePath in modulePaths) { SlowTaskBeginModule(modulePath.Key.PlainName); string moduleName = modulePath.Key.PlainName; string longPackageName = FPackageName.ConvertToLongScriptPackageName(moduleName); UPackage package = UObject.FindObjectFast <UPackage>(null, new FName(longPackageName), false, false); if (package != null) { UnrealModuleInfo moduleInfo = new UnrealModuleInfo(package, moduleName, modulePath.Value, UnrealModuleInfo.GetModuleType(moduleName, modulePath.Value, plugins)); if (moduleInfo.Type == UnrealModuleType.Unknown) { FMessage.Log(ELogVerbosity.Error, string.Format("Unknown module type on module '{0}' '{1}'", moduleInfo.Name, moduleInfo.Package)); } else if (!moduleTypes.Contains(moduleInfo.Type) || moduleNamesBlacklistToLower.Contains(moduleInfo.Name.ToLower()) || (moduleNamesWhitelistToLower.Count > 0 && !moduleNamesWhitelistToLower.Contains(moduleInfo.Name.ToLower()))) { continue; } List <UStruct> structs; if (!structsByPackage.TryGetValue(package, out structs)) { structs = new List <UStruct>(); } List <UEnum> enums; if (!enumsByPackage.TryGetValue(package, out enums)) { enums = new List <UEnum>(); } List <UFunction> globalFunctions; if (!globalFunctionsByPackage.TryGetValue(package, out globalFunctions)) { globalFunctions = new List <UFunction>(); } SlowTaskUpdateTarget(structs.Count + enums.Count + globalFunctions.Count); GenerateCodeForModule(moduleInfo, structs.ToArray(), enums.ToArray(), globalFunctions.ToArray()); } } IPlugin.Dispose(plugins); EndGenerateModules(); }
private void AppendAttribute(CSharpTextBuilder builder, UField field, UnrealModuleInfo module, bool isCollapsedMember) { UnrealModuleType moduleType; UnrealModuleType moduleAssetType; string moduleName = GetModuleName(field, out moduleType, out moduleAssetType); if (string.IsNullOrEmpty(moduleName)) { moduleName = module.Name; } List <string> attributes = new List <string>(); // TODO: Combine all of this into EPropertyType (add some TypeCode into UField?) bool isInterface = false; UEnum unrealEnum = field as UEnum; UClass unrealClass = field as UClass; UScriptStruct unrealStruct = field as UScriptStruct; UFunction unrealFunction = field as UFunction; if (unrealFunction != null) { if (unrealFunction.HasAnyFunctionFlags(EFunctionFlags.Delegate)) { attributes.Add("UDelegate"); } else { if (isCollapsedMember) { // The Flags here might not contain too useful information if there is both a get/set function. // Maybe include a second flags var? attributes.Add("UFunctionAsProp(Flags=0x" + ((uint)unrealFunction.FunctionFlags).ToString("X8") + ")"); } else { attributes.Add("UFunction(Flags=0x" + ((uint)unrealFunction.FunctionFlags).ToString("X8") + ")"); } } } UProperty unrealProperty = field as UProperty; if (unrealProperty != null) { attributes.Add("UProperty(Flags=(PropFlags)0x" + ((ulong)unrealProperty.PropertyFlags).ToString("X16") + ")"); } if (unrealStruct != null) { attributes.Add("UStruct(Flags=0x" + ((uint)unrealStruct.StructFlags).ToString("X8") + ")"); } else if (unrealClass != null) { // Abstract isn't really required but might help with code browsing to know what is abstract // and what isn't. Therefore put it at the start of the attributes list. if (unrealClass.HasAnyClassFlags(EClassFlags.Abstract)) { attributes.Add("Abstract"); } isInterface = unrealClass.IsChildOf <UInterface>(); if (isInterface) { attributes.Add("UInterface(Flags=0x" + ((uint)unrealClass.ClassFlags).ToString("X8") + ")"); } else { // Should we skip "inherit" config name? string configNameStr = string.Empty; if (unrealClass.ClassConfigName != FName.None && !unrealClass.ClassConfigName.ToString().Equals("inherit", StringComparison.InvariantCultureIgnoreCase)) { configNameStr = ", Config=\"" + unrealClass.ClassConfigName + "\""; } attributes.Add("UClass(Flags=(ClassFlags)0x" + ((uint)unrealClass.ClassFlags).ToString("X8") + configNameStr + ")"); } } if (unrealEnum != null) { attributes.Add("UEnum"); } if (unrealEnum != null || unrealClass != null || unrealStruct != null) { bool blueprintType = false; bool blueprintable = false; if (unrealEnum != null) { blueprintType = field.GetBoolMetaData(MDClass.BlueprintType); } else { GetBlueprintability(field as UStruct, out blueprintType, out blueprintable); } if (blueprintType) { attributes.Add(UMeta.GetKey(MDClass.BlueprintType)); } if (unrealClass != null && blueprintable) { attributes.Add(UMeta.GetKey(MDClass.Blueprintable)); } if (isInterface) { } attributes.Add("UMetaPath(\"" + field.GetPathName() + "\", \"" + moduleName + "\", UnrealModuleType." + GetUnrealModuleTypeString(moduleType, moduleAssetType) + (isInterface ? ", InterfaceImpl=typeof(" + GetTypeName(unrealClass, null) + "Impl" + ")" : string.Empty) + ")"); } else { attributes.Add("UMetaPath(\"" + field.GetPathName() + "\")"); } if (attributes.Count > 0) { builder.AppendLine("[" + string.Join(", ", attributes) + "]"); } }
private void GenerateCodeForProperty(UnrealModuleInfo module, CSharpTextBuilder builder, CSharpTextBuilder offsetsBuilder, UProperty property, bool isBlueprintType, StructInfo structInfo, List <string> namespaces, string customName = null) { bool isOwnerStruct = structInfo != null && structInfo.IsStruct; bool isOwnerStructAsClass = structInfo != null && structInfo.StructAsClass; StringBuilder modifiers = new StringBuilder(); if ((// private (there is little point in allowing private code gen so make this protected instead?) (property.HasAnyPropertyFlags(EPropertyFlags.DisableEditOnInstance) && !property.GetBoolMetaData(MDProp.AllowPrivateAccess)) || // protected (!isOwnerStruct && property.HasAnyPropertyFlags(EPropertyFlags.NativeAccessSpecifierProtected | EPropertyFlags.Protected))) // If this is being force exported make it public instead of protected && !forceExportProperties.Contains(property.GetPathName())) { modifiers.Append("protected"); } else { modifiers.Append("public"); } if (modifiers.Length > 0) { modifiers.Append(" "); } string propertyName = GetMemberName(property, customName); string propertyTypeName = GetTypeName(property, namespaces); AppendGetterSetterOffsets(builder, offsetsBuilder, propertyName, property, namespaces); AppendDocComment(builder, property, isBlueprintType); AppendAttribute(builder, property, module); if (isOwnerStruct && !isOwnerStructAsClass) { if (structInfo.IsBlittable && (property is UObjectProperty) && Settings.UObjectAsBlittableType && property.PropertyType != EPropertyType.Class) { builder.AppendLine("private IntPtr " + propertyName + Settings.VarNames.UObjectBlittableName + ";"); builder.AppendLine(modifiers + propertyTypeName + " " + propertyName); builder.OpenBrace(); builder.AppendLine("get { return " + Names.GCHelper_Find + "<" + propertyTypeName + ">(" + propertyName + Settings.VarNames.UObjectBlittableName + "); }"); builder.AppendLine("set { " + propertyName + Settings.VarNames.UObjectBlittableName + " = value == null ? IntPtr.Zero : value." + Names.UObject_Address + "; }"); builder.CloseBrace(); } else { builder.AppendLine(modifiers + propertyTypeName + " " + propertyName + ";"); } } else { builder.AppendLine(modifiers + propertyTypeName + " " + propertyName); builder.OpenBrace(); AppendGetter(builder, propertyName, property, namespaces); if ((!property.HasAnyPropertyFlags(EPropertyFlags.BlueprintReadOnly) || forceExportProperties.Contains(property.GetPathName())) && !IsCollectionProperty(property) && !IsDelegateProperty(property) && !property.IsFixedSizeArray) { AppendSetter(builder, propertyName, property, namespaces); } builder.CloseBrace(); } builder.AppendLine(); }
private void OnEndGenerateModule(UnrealModuleInfo module) { }