protected override bool Generate(SessionTemplateGeneratorParameters parameters) { if (parameters == null) { throw new ArgumentNullException(nameof(parameters)); } // Structure of files to generate: // $Name$.sdpkg // $Name$.targets // Assets\ // $Name$.Game\ // $Name$.Windows\ // $Name$.Android\ // $Name$.iOS\ var logger = parameters.Logger; var platforms = parameters.GetTag(PlatformsKey); var name = parameters.Name; var outputDirectory = parameters.OutputDirectory; var orientation = parameters.GetTag(OrientationKey); // Generate the package //var package = NewPackageTemplateGenerator.GeneratePackage(parameters); // Generate projects for this package var session = parameters.Session; var projectGameName = Utilities.BuildValidNamespaceName(name); var stepIndex = 0; var stepCount = platforms.Count + 1; // Log progress ProjectTemplateGeneratorHelper.Progress(logger, $"Generating {projectGameName}...", stepIndex++, stepCount); // Generate the Game library var project = ProjectTemplateGeneratorHelper.GenerateTemplate(parameters, platforms, "ProjectLibrary.Game/ProjectLibrary.Game.ttproj", projectGameName, PlatformType.Shared, null, ProjectType.Library, orientation); var package = project.Package; //write gitignore WriteGitIgnore(parameters); // Setup the assets folder //Directory.CreateDirectory(UPath.Combine(package.RootDirectory, (UDirectory)"Assets/Shared")); session.Projects.Add(project); // Load missing references session.LoadMissingDependencies(parameters.Logger); // Load dependency assets (needed for camera script template) session.LoadMissingAssets(parameters.Logger, project.FlattenedDependencies.Select(x => x.Package).NotNull()); // Add Effects as an asset folder in order to load sdsl package.AssetFolders.Add(new AssetFolder("Effects")); var packageParameters = new PackageTemplateGeneratorParameters { Name = package.Meta.Name, OutputDirectory = package.FullPath.GetFullDirectory(), Description = parameters.Description, Package = package, Logger = parameters.Logger, Namespace = parameters.Namespace }; // Generate executable projects for each platform var platformProjects = ProjectTemplateGeneratorHelper.UpdatePackagePlatforms(packageParameters, platforms, orientation, false).ToList(); // Add asset packages CopyAssetPacks(parameters, package); // Create camera script var cameraScriptTemplate = TemplateManager.FindTemplates(package.Session).OfType <TemplateAssetDescription>().FirstOrDefault(x => x.DefaultOutputName == CameraScriptDefaultOutputName); if (cameraScriptTemplate == null) { throw new InvalidOperationException($"Could not find template for script '{CameraScriptDefaultOutputName}'"); } var cameraScriptParameters = new AssetTemplateGeneratorParameters(string.Empty) { Name = cameraScriptTemplate.DefaultOutputName, Description = cameraScriptTemplate, Namespace = parameters.Namespace, Package = package, Logger = logger, Unattended = true, }; ScriptTemplateGenerator.SetClassName(cameraScriptParameters, cameraScriptTemplate.DefaultOutputName); if (!ScriptTemplateGenerator.Default.PrepareForRun(cameraScriptParameters).Result || !ScriptTemplateGenerator.Default.Run(cameraScriptParameters)) { throw new InvalidOperationException($"Could not create script '{CameraScriptDefaultOutputName}'"); } // Force save after having created the script // Note: We do that AFTER GameSettings is dirty, otherwise it would ask for an assembly reload (game settings saved might mean new graphics API) SaveSession(parameters); // Load missing references session.LoadMissingReferences(parameters.Logger); // Setup GraphicsCompositor using DefaultGraphicsCompositor var graphicsProfile = parameters.GetTag(GraphicsProfileKey); var defaultCompositorUrl = graphicsProfile >= GraphicsProfile.Level_10_0 ? StridePackageUpgrader.DefaultGraphicsCompositorLevel10Url : StridePackageUpgrader.DefaultGraphicsCompositorLevel9Url; var defaultCompositor = session.FindAsset(defaultCompositorUrl); var graphicsCompositor = new AssetItem("GraphicsCompositor", defaultCompositor.CreateDerivedAsset()); package.Assets.Add(graphicsCompositor); graphicsCompositor.IsDirty = true; // Setup GameSettingsAsset var gameSettingsAsset = GameSettingsFactory.Create(); gameSettingsAsset.GetOrCreate <EditorSettings>().RenderingMode = parameters.GetTag(IsHDRKey) ? RenderingMode.HDR : RenderingMode.LDR; gameSettingsAsset.GraphicsCompositor = AttachedReferenceManager.CreateProxyObject <GraphicsCompositor>(graphicsCompositor.ToReference()); var renderingSettings = gameSettingsAsset.GetOrCreate <RenderingSettings>(); renderingSettings.DefaultGraphicsProfile = parameters.GetTag(GraphicsProfileKey); renderingSettings.DisplayOrientation = (RequiredDisplayOrientation)orientation; var gameSettingsAssetItem = new AssetItem(GameSettingsAsset.GameSettingsLocation, gameSettingsAsset); package.Assets.Add(gameSettingsAssetItem); gameSettingsAssetItem.IsDirty = true; // Add assets to the package AddAssets(parameters, package, projectGameName); // Log done ProjectTemplateGeneratorHelper.Progress(logger, "Done", stepCount, stepCount); // Set current project session.CurrentProject = platformProjects.FirstOrDefault(x => x.Platform == PlatformType.Windows) ?? project; return(true); }
private BuildResultCode BuildMaster() { // Only querying graphics platform, let's load package, print it and exit if (builderOptions.GetGraphicsPlatform) { return(BuildGetGraphicsPlatform()); } AssetCompilerContext context = null; PackageSession projectSession = null; try { if (!PackageSessionPublicHelper.FindAndSetMSBuildVersion()) { var message = "Could not find a compatible version of MSBuild.\r\n\r\n" + "Check that you have a valid installation with the required workloads, or go to [www.visualstudio.com/downloads](https://www.visualstudio.com/downloads) to install a new one."; builderOptions.Logger.Error(message); return(BuildResultCode.BuildError); } var sessionLoadParameters = new PackageLoadParameters { AutoCompileProjects = !builderOptions.DisableAutoCompileProjects, ExtraCompileProperties = builderOptions.ExtraCompileProperties, RemoveUnloadableObjects = true, }; // Loads the root Package var projectSessionResult = PackageSession.Load(builderOptions.PackageFile, sessionLoadParameters); projectSessionResult.CopyTo(builderOptions.Logger); if (projectSessionResult.HasErrors) { return(BuildResultCode.BuildError); } projectSession = projectSessionResult.Session; // Check build configuration var package = projectSession.LocalPackages.Last(); // Check build profile var buildProfile = package.Profiles.FirstOrDefault(pair => pair.Name == builderOptions.BuildProfile); if (buildProfile == null) { builderOptions.Logger.Error($"Unable to find profile [{builderOptions.BuildProfile}] in package [{package.FullPath}]"); return(BuildResultCode.BuildError); } // Setup variables var buildDirectory = builderOptions.BuildDirectory; var outputDirectory = builderOptions.OutputDirectory; // Process game settings asset var gameSettingsAsset = package.GetGameSettingsAsset(); if (gameSettingsAsset == null) { builderOptions.Logger.Warning($"Could not find game settings asset at location [{GameSettingsAsset.GameSettingsLocation}]. Use a Default One"); gameSettingsAsset = GameSettingsFactory.Create(); } // Create context context = new AssetCompilerContext { Profile = builderOptions.BuildProfile, Platform = builderOptions.Platform, CompilationContext = typeof(AssetCompilationContext), BuildConfiguration = builderOptions.ProjectConfiguration }; // Command line properties foreach (var property in builderOptions.Properties) { context.OptionProperties.Add(property.Key, property.Value); } // Set current game settings context.SetGameSettingsAsset(gameSettingsAsset); // Builds the project var assetBuilder = new PackageCompiler(new RootPackageAssetEnumerator(package)); assetBuilder.AssetCompiled += RegisterBuildStepProcessedHandler; context.Properties.Set(BuildAssetNode.VisitRuntimeTypes, true); var assetBuildResult = assetBuilder.Prepare(context); assetBuildResult.CopyTo(builderOptions.Logger); if (assetBuildResult.HasErrors) { return(BuildResultCode.BuildError); } // Setup the remote process build var remoteBuilderHelper = new PackageBuilderRemoteHelper(projectSession.AssemblyContainer, builderOptions); // Create the builder var indexName = "index." + builderOptions.BuildProfile; builder = new Builder(builderOptions.Logger, buildDirectory, builderOptions.BuildProfile, indexName) { ThreadCount = builderOptions.ThreadCount, TryExecuteRemote = remoteBuilderHelper.TryExecuteRemote }; builder.MonitorPipeNames.AddRange(builderOptions.MonitorPipeNames); // Add build steps generated by AssetBuilder builder.Root.Add(assetBuildResult.BuildSteps); // Run builder var result = builder.Run(Builder.Mode.Build); builder.WriteIndexFile(false); // Fill list of bundles var bundlePacker = new BundlePacker(); bundlePacker.Build(builderOptions.Logger, projectSession, buildProfile, indexName, outputDirectory, builder.DisableCompressionIds, context.GetCompilationMode() != CompilationMode.AppStore); return(result); } finally { builder?.Dispose(); // Dispose the session (in order to unload assemblies) projectSession?.Dispose(); context?.Dispose(); // Make sure that MSBuild doesn't hold anything else VSProjectHelper.Reset(); } }
/// <summary> /// Checks if a default scene exists for this game package. /// </summary> /// <param name="log">The log to output the result of the validation.</param> public override void Run(ILogger log) { if (log == null) { throw new ArgumentNullException(nameof(log)); } foreach (var package in Session.Packages) { // Make sure package has its assets loaded if (package.State < PackageState.AssetsReady) { continue; } var hasGameExecutable = package.Profiles.SelectMany(profile => profile.ProjectReferences).Any(projectRef => projectRef.Type == ProjectType.Executable); if (!hasGameExecutable) { continue; } // Find game settings var gameSettingsAssetItem = package.Assets.Find(GameSettingsAsset.GameSettingsLocation); AssetItem defaultScene = null; // If game settings is found, try to find default scene inside var defaultSceneRuntime = ((GameSettingsAsset)gameSettingsAssetItem?.Asset)?.DefaultScene; var defaultSceneReference = AttachedReferenceManager.GetAttachedReference(defaultSceneRuntime); if (defaultSceneReference != null) { // Find it either by Url or Id defaultScene = package.Assets.Find(defaultSceneReference.Id) ?? package.Assets.Find(defaultSceneReference.Url); // Check it is actually a scene asset if (defaultScene != null && !(defaultScene.Asset is SceneAsset)) { defaultScene = null; } } // Find or create default scene if (defaultScene == null) { defaultScene = package.Assets.Find(GameSettingsAsset.DefaultSceneLocation); if (defaultScene != null && !(defaultScene.Asset is SceneAsset)) { defaultScene = null; } } // Otherwise, try to find any scene if (defaultScene == null) { defaultScene = package.Assets.FirstOrDefault(x => x.Asset is SceneAsset); } // Nothing found, let's create an empty one if (defaultScene == null) { log.Error(package, null, AssetMessageCode.DefaultSceneNotFound, null); var defaultSceneName = NamingHelper.ComputeNewName(GameSettingsAsset.DefaultSceneLocation, package.Assets, a => a.Location); var defaultSceneAsset = DefaultAssetFactory <SceneAsset> .Create(); defaultScene = new AssetItem(defaultSceneName, defaultSceneAsset); package.Assets.Add(defaultScene); defaultScene.IsDirty = true; } // Create game settings if not done yet if (gameSettingsAssetItem == null) { log.Error(package, null, AssetMessageCode.AssetNotFound, GameSettingsAsset.GameSettingsLocation); var gameSettingsAsset = GameSettingsFactory.Create(); gameSettingsAsset.DefaultScene = AttachedReferenceManager.CreateProxyObject <Scene>(defaultScene.Id, defaultScene.Location); gameSettingsAssetItem = new AssetItem(GameSettingsAsset.GameSettingsLocation, gameSettingsAsset); package.Assets.Add(gameSettingsAssetItem); gameSettingsAssetItem.IsDirty = true; } } }
private BuildResultCode BuildMaster() { try { PackageSessionPublicHelper.FindAndSetMSBuildVersion(); } catch (Exception e) { var message = "Could not find a compatible version of MSBuild.\r\n\r\n" + "Check that you have a valid installation with the required workloads, or go to [www.visualstudio.com/downloads](https://www.visualstudio.com/downloads) to install a new one.\r\n\r\n" + e; builderOptions.Logger.Error(message); return(BuildResultCode.BuildError); } AssetCompilerContext context = null; PackageSession projectSession = null; try { var sessionLoadParameters = new PackageLoadParameters { AutoCompileProjects = !builderOptions.DisableAutoCompileProjects, ExtraCompileProperties = builderOptions.ExtraCompileProperties, RemoveUnloadableObjects = true, BuildConfiguration = builderOptions.ProjectConfiguration, }; // Loads the root Package var projectSessionResult = PackageSession.Load(builderOptions.PackageFile, sessionLoadParameters); projectSessionResult.CopyTo(builderOptions.Logger); if (projectSessionResult.HasErrors) { return(BuildResultCode.BuildError); } projectSession = projectSessionResult.Session; // Find loaded package (either sdpkg or csproj) -- otherwise fallback to first one var packageFile = (UFile)builderOptions.PackageFile; var package = projectSession.Packages.FirstOrDefault(x => x.FullPath == packageFile || (x.Container is SolutionProject project && project.FullPath == packageFile)) ?? projectSession.LocalPackages.FirstOrDefault() ?? projectSession.Packages.FirstOrDefault(); // Setup variables var buildDirectory = builderOptions.BuildDirectory; var outputDirectory = builderOptions.OutputDirectory; // Process game settings asset var gameSettingsAsset = package.GetGameSettingsAsset(); if (gameSettingsAsset == null) { builderOptions.Logger.Warning($"Could not find game settings asset at location [{GameSettingsAsset.GameSettingsLocation}]. Use a Default One"); gameSettingsAsset = GameSettingsFactory.Create(); } // Create context context = new AssetCompilerContext { Platform = builderOptions.Platform, CompilationContext = typeof(AssetCompilationContext), BuildConfiguration = builderOptions.ProjectConfiguration, Package = package, }; // Command line properties foreach (var property in builderOptions.Properties) { context.OptionProperties.Add(property.Key, property.Value); } // Set current game settings context.SetGameSettingsAsset(gameSettingsAsset); // Builds the project var assetBuilder = new PackageCompiler(new RootPackageAssetEnumerator(package)); assetBuilder.AssetCompiled += RegisterBuildStepProcessedHandler; context.Properties.Set(BuildAssetNode.VisitRuntimeTypes, true); var assetBuildResult = assetBuilder.Prepare(context); assetBuildResult.CopyTo(builderOptions.Logger); if (assetBuildResult.HasErrors) { return(BuildResultCode.BuildError); } // Setup the remote process build var remoteBuilderHelper = new PackageBuilderRemoteHelper(projectSession.AssemblyContainer, builderOptions); var indexName = $"index.{package.Meta.Name}.{builderOptions.Platform}"; // Add runtime identifier (if any) to avoid clash when building multiple at the same time (this happens when using ExtrasBuildEachRuntimeIdentifier feature of MSBuild.Sdk.Extras) if (builderOptions.Properties.TryGetValue("RuntimeIdentifier", out var runtimeIdentifier)) { indexName += $".{runtimeIdentifier}"; } if (builderOptions.Properties.TryGetValue("StrideGraphicsApi", out var graphicsApi)) { indexName += $".{graphicsApi}"; } // Create the builder builder = new Builder(builderOptions.Logger, buildDirectory, indexName) { ThreadCount = builderOptions.ThreadCount, TryExecuteRemote = remoteBuilderHelper.TryExecuteRemote }; builder.MonitorPipeNames.AddRange(builderOptions.MonitorPipeNames); // Add build steps generated by AssetBuilder builder.Root.Add(assetBuildResult.BuildSteps); // Run builder var result = builder.Run(Builder.Mode.Build); builder.WriteIndexFile(false); // Fill list of bundles var bundlePacker = new BundlePacker(); var bundleFiles = new List <string>(); bundlePacker.Build(builderOptions.Logger, projectSession, package, indexName, outputDirectory, builder.DisableCompressionIds, context.GetCompilationMode() != CompilationMode.AppStore, bundleFiles); if (builderOptions.MSBuildUpToDateCheckFileBase != null) { SaveBuildUpToDateFile(builderOptions.MSBuildUpToDateCheckFileBase, builderOptions.PackageFile, package, bundleFiles); } return(result); } finally { builder?.Dispose(); // Dispose the session (in order to unload assemblies) projectSession?.Dispose(); context?.Dispose(); // Make sure that MSBuild doesn't hold anything else VSProjectHelper.Reset(); } }
private void UpdateCurrentGameSettings() { currentPackage = session.CurrentProject?.Package; CurrentGameSettings = currentPackage?.GetGameSettingsAssetOrDefault() ?? GameSettingsFactory.Create(); RaiseGameSettings(CurrentGameSettings); }
private BuildResultCode BuildMaster() { // Only querying graphics platform, let's load package, print it and exit if (builderOptions.GetGraphicsPlatform) { return(BuildGetGraphicsPlatform()); } AssetCompilerContext context = null; PackageSession projectSession = null; try { // TODO handle solution file + package-id ? // When the current platform is not on windows, we need to make sure that all plugins are build, so we // setup auto-compile when loading the session var sessionLoadParameters = new PackageLoadParameters { AutoCompileProjects = builderOptions.Platform != PlatformType.Windows || !builderOptions.DisableAutoCompileProjects, ExtraCompileProperties = builderOptions.ExtraCompileProperties, RemoveUnloadableObjects = true, }; // Loads the root Package var projectSessionResult = PackageSession.Load(builderOptions.PackageFile, sessionLoadParameters); projectSessionResult.CopyTo(builderOptions.Logger); if (projectSessionResult.HasErrors) { return(BuildResultCode.BuildError); } projectSession = projectSessionResult.Session; // Check build configuration var package = projectSession.LocalPackages.Last(); // Check build profile var sharedProfile = package.Profiles.FindSharedProfile(); var buildProfile = package.Profiles.FirstOrDefault(pair => pair.Name == builderOptions.BuildProfile); if (buildProfile == null) { builderOptions.Logger.Error($"Unable to find profile [{builderOptions.BuildProfile}] in package [{package.FullPath}]"); return(BuildResultCode.BuildError); } // Setup variables var buildDirectory = builderOptions.BuildDirectory; var outputDirectory = builderOptions.OutputDirectory; // Process game settings asset var gameSettingsAsset = package.GetGameSettingsAsset(); if (gameSettingsAsset == null) { builderOptions.Logger.Warning($"Could not find game settings asset at location [{GameSettingsAsset.GameSettingsLocation}]. Use a Default One"); gameSettingsAsset = GameSettingsFactory.Create(); } // Create context context = new AssetCompilerContext { Profile = builderOptions.BuildProfile, Platform = builderOptions.Platform, BuildConfiguration = builderOptions.ProjectConfiguration }; // Command line properties foreach (var property in builderOptions.Properties) { context.OptionProperties.Add(property.Key, property.Value); } // Set current game settings context.SetGameSettingsAsset(gameSettingsAsset); // Builds the project var assetBuilder = new PackageCompiler(new RootPackageAssetEnumerator(package)); assetBuilder.AssetCompiled += RegisterBuildStepProcessedHandler; var assetBuildResult = assetBuilder.Compile(context); assetBuildResult.CopyTo(builderOptions.Logger); if (assetBuildResult.HasErrors) { return(BuildResultCode.BuildError); } // Add specific steps to generate shaders // TODO: This doesn't really belong here, where should we move it? //assetBuildResult.BuildSteps.Add(new WaitBuildStep()); //assetBuildResult.BuildSteps.Add(new CompileDefaultSceneEffectCommand(context, package, assetBuildResult)); // Create the builder var indexName = "index." + builderOptions.BuildProfile; builder = new Builder(builderOptions.Logger, buildDirectory, builderOptions.BuildProfile, indexName) { ThreadCount = builderOptions.ThreadCount }; // Note: try to get exec server if it exists, otherwise use CompilerApp.exe builder.SlaveBuilderPath = (string)AppDomain.CurrentDomain.GetData("RealEntryAssemblyFile") ?? typeof(PackageBuilder).Assembly.Location; builder.MonitorPipeNames.AddRange(builderOptions.MonitorPipeNames); // Add build steps generated by AssetBuilder builder.Root.Add(assetBuildResult.BuildSteps); // Run builder var result = builder.Run(Builder.Mode.Build); builder.WriteIndexFile(false); // Fill list of bundles var bundlePacker = new BundlePacker(); bundlePacker.Build(builderOptions.Logger, projectSession, buildProfile, indexName, outputDirectory, builder.DisableCompressionIds); return(result); } finally { builder?.Dispose(); // Dispose the session (in order to unload assemblies) projectSession?.Dispose(); context?.Dispose(); } }
private BuildResultCode BuildMaster() { // Only querying graphics platform, let's load package, print it and exit if (builderOptions.GetGraphicsPlatform) { return(BuildGetGraphicsPlatform()); } assetLogger = new RemoteLogForwarder(builderOptions.Logger, builderOptions.LogPipeNames); AssetCompilerContext context = null; GlobalLogger.GlobalMessageLogged += assetLogger; PackageSession projectSession = null; try { // TODO handle solution file + package-id ? // When the current platform is not on windows, we need to make sure that all plugins are build, so we // setup auto-compile when loading the session var sessionLoadParameters = new PackageLoadParameters { AutoCompileProjects = builderOptions.Platform != PlatformType.Windows || !builderOptions.DisableAutoCompileProjects, ExtraCompileProperties = builderOptions.ExtraCompileProperties, }; // Loads the root Package var projectSessionResult = PackageSession.Load(builderOptions.PackageFile, sessionLoadParameters); if (projectSessionResult.HasErrors) { projectSessionResult.CopyTo(builderOptions.Logger); return(BuildResultCode.BuildError); } projectSession = projectSessionResult.Session; // Check build configuration var package = projectSession.LocalPackages.Last(); // Check build profile var sharedProfile = package.Profiles.FindSharedProfile(); var buildProfile = package.Profiles.FirstOrDefault(pair => pair.Name == builderOptions.BuildProfile); if (buildProfile == null) { builderOptions.Logger.Error("Unable to find profile [{0}] in package [{1}]", builderOptions.BuildProfile, package.FullPath); return(BuildResultCode.BuildError); } // Setup variables var buildDirectory = builderOptions.BuildDirectory; var outputDirectory = builderOptions.OutputDirectory; // Process game settings asset var gameSettingsAsset = package.GetGameSettingsAsset(); if (gameSettingsAsset == null) { builderOptions.Logger.Warning("Could not find game settings asset at location [{0}]. Use a Default One", GameSettingsAsset.GameSettingsLocation); gameSettingsAsset = GameSettingsFactory.Create(); } // Create context context = new AssetCompilerContext { Profile = builderOptions.BuildProfile, Platform = builderOptions.Platform, BuildConfiguration = builderOptions.ProjectConfiguration }; // Command line properties foreach (var property in builderOptions.Properties) { context.OptionProperties.Add(property.Key, property.Value); } // Set current game settings context.SetGameSettingsAsset(gameSettingsAsset); // Copy properties from shared profiles to context properties if (sharedProfile != null) { sharedProfile.Properties.CopyTo(context.PackageProperties, true); } // Copy properties from build profile buildProfile.Properties.CopyTo(context.PackageProperties, true); // Builds the project var assetBuilder = new PackageCompiler(new RootPackageAssetEnumerator(package)); assetBuilder.AssetCompiled += RegisterBuildStepProcessedHandler; var assetBuildResult = assetBuilder.Compile(context); assetBuildResult.CopyTo(builderOptions.Logger); if (assetBuildResult.HasErrors) { return(BuildResultCode.BuildError); } // Create the builder var indexName = "index." + builderOptions.BuildProfile; builder = new Builder(builderOptions.Logger, buildDirectory, builderOptions.BuildProfile, indexName) { ThreadCount = builderOptions.ThreadCount }; builder.MonitorPipeNames.AddRange(builderOptions.MonitorPipeNames); // Add build steps generated by AssetBuilder builder.Root.Add(assetBuildResult.BuildSteps); // Run builder var result = builder.Run(Builder.Mode.Build); builder.WriteIndexFile(false); // Fill list of bundles var bundlePacker = new BundlePacker(); bundlePacker.Build(builderOptions.Logger, projectSession, buildProfile, indexName, outputDirectory, builder.DisableCompressionIds); return(result); } finally { builder?.Dispose(); // Dispose the session (in order to unload assemblies) projectSession?.Dispose(); context?.Dispose(); // Flush and close logger GlobalLogger.GlobalMessageLogged -= assetLogger; assetLogger.Dispose(); } }