Exemplo n.º 1
0
        private static void GenerateAndCompileMissingAssemblies()
        {
            string projectFileName = FPaths.ProjectFilePath;

            if (!FBuild.WithEditor || string.IsNullOrEmpty(projectFileName))
            {
                return;
            }

            // NOTE: This is called before ManagedUnrealModuleInfo.Load / ManagedUnrealTypes.Load so some things may not be accessible.
            //       Maybe call load then unload after this is finished?

            // NOTE: Most of the functions called here use FSlowTask but the UI isn't available until the engine is fully initialized.
            //       Instead use FFeedbackContext to display a progress bar (FDesktopPlatformModule::Get()->GetNativeFeedbackContext())
            // TODO: Redirect some of the FSlowTask messages to the log, so that the "show log" button displays useful info?
            codeGenContext = FFeedbackContext.GetGetDesktopFeedbackContext();

            string dialogTitle = "USharp";

            CodeGeneratorSettings settings = new CodeGeneratorSettings();

            string engineWrapperDllPath     = Path.Combine(settings.GetManagedModulesDir(), "bin", "Debug", "UnrealEngine.dll");
            string engineWrapperSlnPath     = Path.Combine(settings.GetManagedModulesDir(), "UnrealEngine.sln");
            bool   compileEngineWrapperCode = false;

            if (!File.Exists(engineWrapperSlnPath))
            {
                if (FMessage.OpenDialog(EAppMsgType.YesNo, "C# engine wrapper code not found. Generate it now?", dialogTitle) == EAppReturnType.Yes)
                {
                    codeGenContext.BeginSlowTask("Generating C# engine wrapper code (this might take a while...)", true);
                    CodeGenerator.GenerateCode(new string[] { "modules" });
                    codeGenContext.EndSlowTask();
                    compileEngineWrapperCode = true;
                }
            }
            if (compileEngineWrapperCode || (!File.Exists(engineWrapperDllPath) && File.Exists(engineWrapperSlnPath)))
            {
                if (compileEngineWrapperCode ||
                    FMessage.OpenDialog(EAppMsgType.YesNo, "C# engine wrapper code isn't compiled. Compile it now?", dialogTitle) == EAppReturnType.Yes)
                {
                    codeGenContext.BeginSlowTask("Compiling C# engine wrapper code (this might take a while...)", true);
                    bool compiled = CodeGenerator.CompileGeneratedCode();
                    codeGenContext.EndSlowTask();

                    if (!compiled)
                    {
                        WarnCompileFailed(settings, null, dialogTitle);
                    }
                }
            }

            string projectName = Path.GetFileNameWithoutExtension(projectFileName);
            string gameSlnPath = Path.Combine(settings.GetManagedDir(), projectName + ".Managed.sln");
            string gameDllPath = Path.Combine(FPaths.ProjectDir, "Binaries", "Managed", projectName + ".Managed.dll");

            if (!File.Exists(gameSlnPath) &&
                FMessage.OpenDialog(EAppMsgType.YesNo, "USharp is enabled but the C# game project files weren't found. Generate them now?", dialogTitle) == EAppReturnType.Yes)
            {
                TemplateProjectGenerator.Generate();
            }

            if (File.Exists(gameSlnPath) && !File.Exists(gameDllPath) &&
                FMessage.OpenDialog(EAppMsgType.YesNo, "C# game project code isn't compiled. Compile it now?", dialogTitle) == EAppReturnType.Yes)
            {
                codeGenContext.BeginSlowTask("Compiling C# game project code (this might take a while...)", true);
                bool compiled = CodeGenerator.CompileCode(gameSlnPath, null);
                codeGenContext.EndSlowTask();

                if (!compiled)
                {
                    WarnCompileFailed(settings, null, dialogTitle);
                }
            }

            codeGenContext = null;
        }
Exemplo n.º 2
0
        private static void OnNativeFunctionsRegistered()
        {
            bool reloading = HotReload.IsReloading;

            HotReload.MinimalReload = Native_SharpHotReloadUtils.Get_MinimalHotReload();

            FMessage.Log("Runtime: " + SharedRuntimeState.GetRuntimeInfo(false));

            // HACK: Removing EPackageFlags.EditorOnly on the USharp package so that C# classes aren't tagged as
            //       EObjectMark.EditorOnly. The correct thing to do would be to seperate USharp into seperate
            //       Editor/Runtime modules.
            IntPtr package = NativeReflection.FindPackage(IntPtr.Zero, "/Script/USharp");

            if (package != IntPtr.Zero)
            {
                Native_UPackage.ClearPackageFlags(package, EPackageFlags.EditorOnly);
            }

            using (var timing = HotReload.Timing.Create(HotReload.Timing.UnrealTypes_Load))
            {
                UnrealTypes.Load();
            }

            if (HotReload.IsReloading)
            {
                HotReload.OnPreReloadBegin();
            }

            using (var timing = HotReload.Timing.Create(HotReload.Timing.UnrealTypes_LoadNative))
            {
                // Load the underlying native type info for generated types (class address/properties/functions/offsets)
                UnrealTypes.LoadNative();
            }

            using (var timing = HotReload.Timing.Create(HotReload.Timing.UClass_Load))
            {
                // Load native classes
                UClass.Load();
            }

            // If any assemblies are loaded make sure to load their unreal types
            if (!AssemblyContext.IsCoreCLR || CurrentAssemblyContext.Reference.IsInvalid)
            {
                // .NET Core should resolve with AssemblyLoadContext.Resolving (unless the contexts aren't set up)
                CurrentAssemblyContext.AssemblyResolve += CurrentDomain_AssemblyResolve;
            }
            CurrentAssemblyContext.AssemblyLoad += OnAssemblyLoad;
            CurrentAssemblyContext.Resolving    += CurrentAssemblyContext_Resolving;

            using (var timing = HotReload.Timing.Create(HotReload.Timing.NativeFunctions_LoadAssemblies))
            {
                // Load managed assemblies (game assembly, and any others which may need loading)
                LoadAssemblies();
            }

            if (HotReload.IsReloading)
            {
                HotReload.OnPreReloadEnd();
            }

            using (var timing = HotReload.Timing.Create(HotReload.Timing.ManagedUnrealModuleInfo_Load))
            {
                // Load managed module infos
                ManagedUnrealModuleInfo.Load();
            }

            using (var timing = HotReload.Timing.Create(HotReload.Timing.ManagedUnrealTypes_Load))
            {
                // Load / register managed unreal types
                ManagedUnrealTypes.Load();
            }

            using (var timing = HotReload.Timing.Create(HotReload.Timing.HotReload_OnReload))
            {
                // Let HotReload handle reloading if this is a reload
                if (HotReload.IsReloading)
                {
                    HotReload.OnReload();
                }
            }

            // Clear the hot-reload data store if it isn't cleared already
            if (HotReload.Data != null)
            {
                HotReload.Data.Close();
                HotReload.Data = null;
            }

            if (FBuild.WithEditor && reloading)
            {
                using (var timing = HotReload.Timing.Create(HotReload.Timing.UObject_CollectGarbage))
                {
                    // If we are hotreloading collect garbage to clean up trashed types / reinstanced objects
                    UObject.CollectGarbage(GCHelper.GarbageCollectionKeepFlags, true);
                }

                if (!ManagedUnrealTypes.SkipBroadcastHotReload)
                {
                    using (var timing = HotReload.Timing.Create(HotReload.Timing.SharpHotReloadUtils_BroadcastOnHotReload))
                    {
                        // Broadcast the native OnHotReload (if we don't do this we would need to reimplement various
                        // handlers to ensure correct reloading. One example is FBlueprintActionDatabase::ReloadAll
                        // which needs to be called otherwise the action database will hold onto our old class members
                        // and would produce erros when opening blueprints).

                        // true will show the C++ "Hot Reload Complete!" notification (are there any other differences?)
                        //Native_SharpHotReloadUtils.BroadcastOnHotReload(true);

                        // The notification rendering gets messed up the longer hotreload takes. Wait 1 frame to ensure
                        // that the notification gets fully rendered (though the audio still seems to mess up)
                        Coroutine.StartCoroutine(null, DeferBroadcastHotReload());
                    }
                }
            }

            // Generate / update the C# game project
            TemplateProjectGenerator.Generate();

            using (var timing = HotReload.Timing.Create(HotReload.Timing.GC_Collect))
            {
                // We likely created a bunch of garbage, best to clean it up now.
                GC.Collect();
            }
        }