private static async Task StartDebugHost(string executableOutputPath, ProjectWatcher projectWatcher, TaskCompletionSource <bool> projectCouldFirstCompile, TimeSpan recompilationDelay, Process debuggerProcess, LoggerResult logger) { // Clear logger, so we don't fail because of a previous debug session logger.Clear(); logger.HasErrors = false; var assemblyRecompiler = new AssemblyRecompiler(); AssemblyRecompiler.UpdateResult updateResult; // TODO: When should we do the NuGet restore? Should we do it only once, or every change? try { updateResult = await assemblyRecompiler.Recompile(projectWatcher.CurrentGameLibrary, logger); if (updateResult.HasErrors) { // Failure during initial compilation updateResult.Error("Initial LiveScripting compilation failed, can't start live scripting"); projectCouldFirstCompile.TrySetResult(false); return; } } catch (Exception e) { projectCouldFirstCompile.TrySetException(e); throw; } // Notify project could compile succesfully projectCouldFirstCompile.TrySetResult(true); using (var debugHost = new DebugHost()) { // Start the debug host and wait for it to be available debugHost.Start(executableOutputPath, debuggerProcess, logger); var debugTarget = await debugHost.GameHost.Target; bool firstLoad = true; // List of currently loaded assemblies var loadedAssemblies = new Dictionary <AssemblyRecompiler.SourceGroup, DebugAssembly>(AssemblyRecompiler.SourceGroupComparer.Default); // Listen for game exited event var gameExited = new CancellationTokenSource(); debugHost.GameHost.GameExited += gameExited.Cancel; while (!gameExited.IsCancellationRequested) { if (!updateResult.HasErrors) { // Assemblies to unload, based on currently loaded ones var assembliesToUnload = updateResult.UnloadedProjects.Select(x => loadedAssemblies[x]).ToList(); // Load new assemblies foreach (var loadedProject in updateResult.LoadedProjects) { var assembly = debugTarget.AssemblyLoadRaw(loadedProject.PE, loadedProject.PDB); loadedAssemblies[loadedProject] = assembly; } // Assemblies to load, based on the updated SourceGroup mapping var assembliesToLoad = updateResult.LoadedProjects.Select(x => loadedAssemblies[x]).ToList(); // Update runtime game to use new assemblies debugTarget.AssemblyUpdate(assembliesToUnload, assembliesToLoad); // Start game on first load if (firstLoad) { // Arbitrarily launch first game (should be only one anyway?) // TODO: Maybe game is not even necessary anymore and we should just instantiate a "DefaultSceneGame"? var games = debugTarget.GameEnumerateTypeNames(); debugTarget.GameLaunch(games.First()); firstLoad = false; } } // Wait for any file change that would trigger a recompilation (or a game exit event) await projectWatcher.ReceiveAndDiscardChanges(recompilationDelay, gameExited.Token); // Check if live session exited to avoid recompiling for nothing if (gameExited.IsCancellationRequested) { break; } // Update result for next loop updateResult = await assemblyRecompiler.Recompile(projectWatcher.CurrentGameLibrary, logger); } } }