Example #1
0
        private IntPtr CreateProperty(IntPtr outer, PropertyInfo propertyInfo)
        {
            // Note that HeaderParser.cpp and UObjectGlobals.cpp use "new" instead of NewObject for creating properties
            // KismetCompilerMisc.cpp uses NewObject
            // The "new" initialization sets the offset and adds the property to the owner which in the case of UStruct
            // does the following:
            // void UStruct::AddCppProperty(UProperty* Property) { Property->Next = Children; Children = Property; }

            USharpPathAttribute pathAttribute = propertyInfo.GetCustomAttribute <USharpPathAttribute>();

            if (pathAttribute == null)
            {
                return(IntPtr.Zero);
            }

            string root, directory, moduleName, typeName, propertyName;

            FPackageName.GetPathInfo(pathAttribute.Path, out root, out directory, out moduleName, out typeName, out propertyName);
            if (string.IsNullOrEmpty(propertyName))
            {
                return(IntPtr.Zero);
            }

            IntPtr property = CreateProperty(outer, propertyInfo.PropertyType, propertyName, pathAttribute.PropertyType,
                                             pathAttribute.InnerPropertyType1, pathAttribute.InnerPropertyType2);

            if (property == IntPtr.Zero)
            {
                return(IntPtr.Zero);
            }

            if (FBuild.WithMetaData)
            {
                IntPtr outermost = Native_UObjectBaseUtility.GetOutermost(property);
                IntPtr metadata  = outermost == IntPtr.Zero ? IntPtr.Zero : Native_UPackage.GetMetaData(outermost);

                if (metadata != IntPtr.Zero)
                {
                    string categoryName = null;
                    //propertyInfo.GetCustomAttribute

                    if (string.IsNullOrEmpty(categoryName))
                    {
                        categoryName = "Default";
                    }

                    SetMetaData(metadata, property, "Category", categoryName);
                }
            }

            return(property);
        }
Example #2
0
        public void OnCodeGenerated(CodeGenerator.UnrealModuleInfo module, UnrealModuleType moduleAssetType, string typeName, string path, string code)
        {
            // Note: path will be empty if using combined enums file or global delegates files
            string root, directory, moduleName, assetName, memberName;

            FPackageName.GetPathInfo(path, out root, out directory, out moduleName, out assetName, out memberName);
            //Log("path:'{0}' root:'{1}' directory:'{2}' asset:'{3}' member:'{4}'", path, root, directory, assetName, memberName);

            string rootFolderName = GetRootFolderName(path, root, module.Type, moduleAssetType);

            if (string.IsNullOrEmpty(rootFolderName) && !string.IsNullOrEmpty(path))
            {
                Log(ELogVerbosity.Error, "Unknown asset root '{0}' ModuleType:'{1}' ModuleAssetType:'{2}' Path:'{3}'",
                    root, module.Type, moduleAssetType, path);
                return;
            }

            string name = Settings.UseTypeNameAsSourceFileName || string.IsNullOrEmpty(assetName) ? typeName : assetName;

            string sourceFilePath = null;
            string projPath       = null;
            string slnPath        = null;

            switch (module.Type)
            {
            case UnrealModuleType.Game:
            {
                string relativeSourceFilePath = null;
                if (EmulateGameFolderStructure(moduleAssetType))
                {
                    relativeSourceFilePath = Path.Combine(directory, name + ".cs");
                }
                else
                {
                    relativeSourceFilePath = name + ".cs";
                }
                string baseCodeDir = Settings.GetGeneratedCodeDir(false);
                if (module.IsBlueprint)
                {
                    baseCodeDir = Path.Combine(Settings.GetManagedDir(), Settings.GetProjectName() + ".Managed", "Blueprint", "Generated");
                }
                if (moduleAssetType == UnrealModuleType.Unknown)
                {
                    // Don't use root folders for native game code wrappers as root folders don't make much sense for them
                    sourceFilePath = Path.Combine(baseCodeDir, relativeSourceFilePath);
                }
                else
                {
                    sourceFilePath = Path.Combine(baseCodeDir, rootFolderName, relativeSourceFilePath);
                }
                slnPath  = GameSlnPath;
                projPath = module.IsBlueprint ? GameProjPath : GameNativeGenerationProjPath;
            }
            break;

            case UnrealModuleType.EnginePlugin:
            case UnrealModuleType.Engine:
            {
                bool mergeAsPluginProj = false;
                bool mergeAsUnrealProj = false;
                switch (Settings.EngineProjMerge)
                {
                case CodeGeneratorSettings.ManagedEngineProjMerge.Engine:
                    if (module.Type == UnrealModuleType.Engine)
                    {
                        mergeAsUnrealProj = true;
                    }
                    break;

                case CodeGeneratorSettings.ManagedEngineProjMerge.Plugins:
                    if (module.Type == UnrealModuleType.EnginePlugin)
                    {
                        mergeAsPluginProj = true;
                    }
                    break;

                case CodeGeneratorSettings.ManagedEngineProjMerge.EngineAndPlugins:
                    if (module.Type == UnrealModuleType.EnginePlugin)
                    {
                        mergeAsPluginProj = true;
                    }
                    else
                    {
                        mergeAsUnrealProj = true;
                    }
                    break;

                case CodeGeneratorSettings.ManagedEngineProjMerge.EngineAndPluginsCombined:
                    mergeAsUnrealProj = true;
                    break;
                }
                if (mergeAsPluginProj || mergeAsUnrealProj)
                {
                    string projName = mergeAsUnrealProj ? "UnrealEngine.csproj" : "UnrealEngine.Plugins.csproj";
                    if (Settings.EngineProjMerge == CodeGeneratorSettings.ManagedEngineProjMerge.EngineAndPluginsCombined)
                    {
                        projPath = Path.Combine(Settings.GetManagedModulesDir(), projName);
                    }
                    else
                    {
                        projPath = Path.Combine(Settings.GetManagedModulesDir(), rootFolderName, projName);
                    }
                }
                else
                {
                    projPath = Path.Combine(Settings.GetManagedModulesDir(), rootFolderName, module.Name, module.Name + ".csproj");
                }

                sourceFilePath = Path.Combine(Settings.GetManagedModulesDir(), rootFolderName, module.Name, name + ".cs");

                if (Settings.ModulesLocation == CodeGeneratorSettings.ManagedModulesLocation.GameFolderCombineSln)
                {
                    slnPath = GameSlnPath;
                }
                else if (Settings.ModulesLocation == CodeGeneratorSettings.ManagedModulesLocation.GameFolderCombineSlnProj)
                {
                    slnPath  = GameSlnPath;
                    projPath = GameProjPath;
                }
                else
                {
                    slnPath = Path.Combine(Settings.GetManagedModulesDir(), "UnrealEngine.sln");
                }
            }
            break;

            case UnrealModuleType.GamePlugin:
            {
                if (moduleAssetType == UnrealModuleType.Unknown)
                {
                    // Don't use root folders for native game code wrappers as root folders don't make much sense for them
                    sourceFilePath = Path.Combine(Settings.GetGeneratedCodeDir(true), module.Name, name + ".cs");
                }
                else
                {
                    sourceFilePath = Path.Combine(Settings.GetGeneratedCodeDir(true), rootFolderName, module.Name, name + ".cs");
                }
                slnPath = GameSlnPath;

                if (Settings.GameProjMerge == CodeGeneratorSettings.ManagedGameProjMerge.GameAndPlugins)
                {
                    projPath = GameNativeGenerationProjPath;
                }
                else if (Settings.GameProjMerge == CodeGeneratorSettings.ManagedGameProjMerge.Plugins)
                {
                    projPath = GamePluginGenerationProjPath;
                }
                else
                {
                    projPath = Path.Combine(Settings.GetManagedDir(), rootFolderName, module.Name, module.Name + ".csproj");
                }
            }
            break;
            }

            if (!string.IsNullOrWhiteSpace(sourceFilePath))
            {
                sourceFilePath = Path.GetFullPath(sourceFilePath);
            }
            if (!string.IsNullOrWhiteSpace(projPath))
            {
                projPath = Path.GetFullPath(projPath);
            }
            if (!string.IsNullOrWhiteSpace(slnPath))
            {
                slnPath = Path.GetFullPath(slnPath);
            }

            if (string.IsNullOrWhiteSpace(sourceFilePath) || string.IsNullOrWhiteSpace(projPath) || string.IsNullOrWhiteSpace(slnPath))
            {
                Log(ELogVerbosity.Error, "Unknown output location for '{0}' '{1}'", typeName, path);
            }
            else if (!ValidateOutputPath(sourceFilePath) || !ValidateOutputPath(projPath) || !ValidateOutputPath(slnPath))
            {
                Log(ELogVerbosity.Error, "Invalid output path '{0}'", sourceFilePath);
            }
            else
            {
                //FMessage.Log(ELogVerbosity.Log, sourceFilePath + " | " + projPath + " | " + slnPath);

                try
                {
                    if (UpdateSolutionAndProject(slnPath, projPath))
                    {
                        if (!AddSourceFile(slnPath, projPath, sourceFilePath, code))
                        {
                            Log(ELogVerbosity.Error, "Failed to add source file '{0}'", sourceFilePath);
                        }
                    }
                    else
                    {
                        Log(ELogVerbosity.Error, "Failed to create sln/csproj '{0}' '{1}'", slnPath, projPath);
                    }
                }
                catch (Exception e)
                {
                    Log(ELogVerbosity.Error, "Exception when adding source file '{0}' {1}", sourceFilePath, e);
                }
            }
        }
Example #3
0
        public static ManagedUnrealClass CreateClass(Type type)
        {
            ManagedUnrealClass existingClass = FindClass(type);

            if (existingClass != null)
            {
                if (!FBuild.WithHotReload)
                {
                    // TODO: Add support for hotreloading C# classes when WITH_HOT_RELOAD isn't available
                    // - WITH_HOT_RELOAD will be false on shipping, monolithic and server builds
                    // - Would need to make a copy of FHotReloadClassReinstancer (or just use it directly if
                    //   it doesn't depend on WITH_HOT_RELOAD and gets compiled into builds)
                    // - Would likely break blueprint classes which depend on any C# classes reinstanced in this way
                    return(existingClass);
                }

                existingClass.Clear();
                HotReloadClassCount++;
            }

            if (!type.IsSubclassOf(typeof(UObject)))
            {
                return(null);
            }

            USharpPathAttribute pathAttribute = type.GetCustomAttribute <USharpPathAttribute>();

            if (pathAttribute == null || string.IsNullOrEmpty(pathAttribute.Path))
            {
                return(null);
            }

            IntPtr parentClass = GetStaticClass(type.BaseType);

            if (parentClass == IntPtr.Zero)
            {
                return(null);
            }

            string root, directory, moduleName, className, memberName;

            FPackageName.GetPathInfo(pathAttribute.Path, out root, out directory, out moduleName, out className, out memberName);

            string packageName = "/" + root + "/" + directory;

            if (string.IsNullOrEmpty(moduleName) || string.IsNullOrEmpty(className))
            {
                return(null);
            }

            IntPtr package = NativeReflection.FindObject(Native_UPackage.StaticClass(), IntPtr.Zero, packageName, true);

            if (package == IntPtr.Zero)
            {
                package = NativeReflection.CreatePackage(IntPtr.Zero, packageName);
                Native_UPackage.SetPackageFlags(package, EPackageFlags.CompiledIn);

                // TODO: Find how to create a proper guid for a package (UHT CodeGenerator.cpp seems to use a crc of generated code)
                using (System.Security.Cryptography.SHA256 sha256 = System.Security.Cryptography.SHA256.Create())
                {
                    byte[] hash = sha256.ComputeHash(Encoding.ASCII.GetBytes(packageName));

                    // Truncate the hash
                    byte[] buffer = new byte[16];
                    Buffer.BlockCopy(hash, 0, buffer, 0, buffer.Length);

                    Native_UPackage.SetGuid(package, new Guid(buffer));
                }
            }

            ManagedUnrealClass managedUnrealClass = null;

            if (existingClass != null)
            {
                managedUnrealClass = existingClass;
            }
            else
            {
                managedUnrealClass = new ManagedUnrealClass(type, packageName, className, parentClass);
            }

            managedUnrealClass.StaticClass = USharpClass.CreateClassPtr(
                managedUnrealClass.PackageName,
                managedUnrealClass.ClassName,
                (uint)Native_UStruct.GetPropertiesSize(managedUnrealClass.ParentClass),
                EClassFlags.None,
                EClassCastFlags.None,
                managedUnrealClass.ConfigName,
                managedUnrealClass.ParentClass,
                managedUnrealClass.WithinClass,
                managedUnrealClass.ClassConstructor,
                managedUnrealClass.ClassVTableHelperCtorCaller,
                managedUnrealClass.ClassAddReferencedObjects);

            Native_UObjectBase.UObjectForceRegistration(managedUnrealClass.StaticClass);

            if (existingClass == null)
            {
                Classes.Add(type, managedUnrealClass);
                ClassesByAddress.Add(managedUnrealClass.StaticClass, managedUnrealClass);
            }

            managedUnrealClass.Initialize();

            return(managedUnrealClass);
        }