Example #1
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();
            }

            using (var timing = HotReload.Timing.Create(HotReload.Timing.NativeFunctions_GenerateAndCompileMissingAssemblies))
            {
                // Update the C# game project props file
                ProjectProps.Update();

                // Prompt to compile the C# engine wrapper code / C# game code (if it isn't already compiled)
                GenerateAndCompileMissingAssemblies();
            }

            // 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());
                    }
                }
            }

            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();
            }
        }
Example #2
0
        private static unsafe void SetDotNetRuntime(string[] args)
        {
            // It's probably possible to dynamically load runtimes by adding a function to SharedRuntimeState (and slightly modifying
            // the current load checks inside of CSharpLoader::Load)
            const string enableMoreRuntimesStr =
                "Only one runtime has been loaded. Modify /USharp/Binaries/Managed/Runtimes/DotNetRuntime.txt to add more runtimes and then reopen the editor.";

            if (args != null && args.Length > 0)
            {
                bool handled = true;
                switch (args[0].ToLower())
                {
                case "diag":
                {
                    // Diagnostics...
                    FMessage.Log("============================================================================================");
                    FMessage.Log("Loaded modules in " + SharedRuntimeState.CurrentRuntime + ":");
                    foreach (System.Reflection.Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
                    {
                        FMessage.Log(assembly.FullName);
                    }

                    // Also print out the loaded AppDomain instances when under the .NET Framework (CLR)
                    if (AssemblyContext.IsCLR)
                    {
                        FMessage.Log("================ Domains:");
                        string[] appDomains = AppDomainDiagnostic.GetNames();
                        if (appDomains != null)
                        {
                            foreach (string appDomain in appDomains)
                            {
                                FMessage.Log(appDomain);
                            }
                        }
                    }
                }
                break;

                case "reload":
                {
                    SharedRuntimeState.Instance->Reload = true;
                }
                break;

                default:
                    handled = false;
                    break;
                }

                if (handled)
                {
                    return;
                }

                if (SharedRuntimeState.HaveMultipleRuntimesLoaded())
                {
                    EDotNetRuntime runtime = EDotNetRuntime.None;
                    switch (args[0].ToLower())
                    {
                    case "mono":
                        runtime = EDotNetRuntime.Mono;
                        break;

                    case "clr":
                        runtime = EDotNetRuntime.CLR;
                        break;

                    case "coreclr":
                        runtime = EDotNetRuntime.CoreCLR;
                        break;
                    }
                    if (runtime == EDotNetRuntime.None)
                    {
                        FMessage.Log("Unknown runtime '" + args[0] + "'. Current runtime: " + SharedRuntimeState.GetRuntimeInfo(true));
                    }
                    else if (!SharedRuntimeState.IsRuntimeLoaded(runtime))
                    {
                        FMessage.Log(runtime + " isn't loaded. Current runtime: " + SharedRuntimeState.GetRuntimeInfo(true));
                    }
                    else if (SharedRuntimeState.Instance->NextRuntime != EDotNetRuntime.None)
                    {
                        FMessage.Log("Runtime change already queued (" + SharedRuntimeState.Instance->NextRuntime.ToString() + ")");
                    }
                    else if (SharedRuntimeState.Instance->Reload)
                    {
                        FMessage.Log("The active runtime is currently reloading (" + SharedRuntimeState.Instance->ActiveRuntime + ")");
                    }
                    else if (SharedRuntimeState.Instance->ActiveRuntime == runtime)
                    {
                        FMessage.Log(runtime.ToString() + " is already the active runtime");
                    }
                    else
                    {
                        SharedRuntimeState.Instance->RuntimeCounter++;
                        SharedRuntimeState.Instance->NextRuntime = runtime;
                        FMessage.Log("Changing runtime to " + runtime.ToString() + "...");
                    }
                }
                else
                {
                    FMessage.Log(ELogVerbosity.Error, enableMoreRuntimesStr);
                    FMessage.Log("Runtime: " + SharedRuntimeState.GetRuntimeInfo(true));
                }
            }
            else
            {
                if (!SharedRuntimeState.HaveMultipleRuntimesLoaded())
                {
                    FMessage.Log(enableMoreRuntimesStr);
                }
                FMessage.Log("Runtime: " + SharedRuntimeState.GetRuntimeInfo(true));
            }
        }