protected void WriteGlobalJson(SessionTemplateGeneratorParameters parameters) { if (!RuntimeInformation.FrameworkDescription.StartsWith(".NET Core")) { return; } var sdkVersion = MSBuildLocator.QueryVisualStudioInstances() .First(vs => vs.DiscoveryType == DiscoveryType.DotNetSdk && vs.Version.Major >= 3).Version; var fileName = UFile.Combine(parameters.OutputDirectory, "global.json"); File.WriteAllText(fileName.ToWindowsPath(), GlobalJson(sdkVersion.ToString())); }
private void Rename(string newName) { string error; if (!IsValidName(newName, out error)) { ServiceProvider.Get <IDialogService>().BlockingMessageBox(string.Format(Tr._p("Message", "This package couldn't be renamed. {0}"), error), MessageBoxButton.OK, MessageBoxImage.Information); return; } var newPath = UFile.Combine(PackagePath.GetFullDirectory(), newName + PackagePath.GetFileExtension()); Rename(newPath); }
private async Task GeneratePrecompiledFont() { var font = (SpriteFontAsset)AssetItem.Asset; var dialogService = ServiceProvider.Get <IDialogService>(); // Dynamic font cannot be precompiled if (font.FontType is RuntimeRasterizedSpriteFontType) { // Note: Markdown (**, _) are used to format the text. await dialogService.MessageBox(Tr._p("Message", "**Only static fonts can be precompiled.**\r\n\r\nClear the _Is Dynamic_ property on this font and try again."), MessageBoxButton.OK, MessageBoxImage.Error); return; } // Compute unique name var precompiledName = NamingHelper.ComputeNewName($"{AssetItem.Location.GetFileNameWithoutExtension()} (Precompiled)", Directory.Assets, x => x.Name); // Ask location for generated texture var folderDialog = dialogService.CreateFolderOpenModalDialog(); folderDialog.InitialDirectory = (Session.CurrentProject?.Package?.RootDirectory ?? Session.SolutionPath.GetFullDirectory()).ToWindowsPath() + "\\Resources"; var dialogResult = await folderDialog.ShowModal(); if (dialogResult != DialogResult.Ok) { return; } bool srgb; var gameSettings = Session.CurrentProject?.Package.GetGameSettingsAsset(); if (gameSettings == null) { var buttons = DialogHelper.CreateButtons(new[] { ColorSpace.Linear.ToString(), ColorSpace.Gamma.ToString(), Tr._p("Button", "Cancel") }, 1, 3); var result = await dialogService.MessageBox(Tr._p("Message", "Which color space do you want to use?"), buttons, MessageBoxImage.Question); // Close without clicking a button or Cancel if (result == 0 || result == 3) { return; } srgb = result == 2; } else { srgb = gameSettings.GetOrCreate <RenderingSettings>().ColorSpace == ColorSpace.Linear; } var precompiledFontAsset = (font.FontType is SignedDistanceFieldSpriteFontType) ? font.GeneratePrecompiledSDFSpriteFont(AssetItem, UFile.Combine(folderDialog.Directory, precompiledName)) : font.GeneratePrecompiledSpriteFont(AssetItem, UFile.Combine(folderDialog.Directory, precompiledName), srgb); // NOTE: following code could be factorized with AssetFactoryViewModel var defaultLocation = UFile.Combine(Directory.Path, precompiledName); var assetItem = new AssetItem(defaultLocation, precompiledFontAsset); AssetViewModel assetViewModel; using (var transaction = UndoRedoService.CreateTransaction()) { // FIXME: do we need to delete the generated file upon undo? assetViewModel = Directory.Package.CreateAsset(Directory, assetItem, true, null); UndoRedoService.SetName(transaction, $"Create Asset '{precompiledName}'"); } Session.CheckConsistency(); if (assetViewModel != null) { Session.ActiveAssetView.SelectAssetCommand.Execute(assetViewModel); } }
protected void WriteGitIgnore(SessionTemplateGeneratorParameters parameters) { var fileName = UFile.Combine(parameters.OutputDirectory, ".gitignore"); File.WriteAllText(fileName.ToWindowsPath(), GitIgnore); }
public override bool Upgrade(PackageLoadParameters loadParameters, PackageSession session, ILogger log, Package dependentPackage, PackageDependency dependency, Package dependencyPackage, IList <PackageLoadingAssetFile> assetFiles) { #if XENKO_SUPPORT_BETA_UPGRADE // Graphics Compositor asset if (dependency.Version.MinVersion < new PackageVersion("1.11.0.0")) { // Find game settings (if there is none, it's not a game and nothing to do) var gameSettings = assetFiles.FirstOrDefault(x => x.AssetLocation == GameSettingsAsset.GameSettingsLocation); if (gameSettings != null) { RunAssetUpgradersUntilVersion(log, dependentPackage, dependency.Name, gameSettings.Yield().ToList(), new PackageVersion("1.10.0-alpha02")); using (var gameSettingsYaml = gameSettings.AsYamlAsset()) { // Figure out graphics profile; default is Level_10_0 (which is same as GraphicsCompositor default) var graphicsProfile = GraphicsProfile.Level_10_0; try { foreach (var mapping in gameSettingsYaml.DynamicRootNode.Defaults) { if (mapping.Node.Tag == "!Xenko.Graphics.RenderingSettings,Xenko.Graphics") { if (mapping.DefaultGraphicsProfile != null) { Enum.TryParse((string)mapping.DefaultGraphicsProfile, out graphicsProfile); } break; } } } catch { // If something goes wrong, keep going with the default value } // Add graphics compositor asset by creating a derived asset of Compositing/DefaultGraphicsCompositor.xkgfxcomp var graphicsCompositorUrl = graphicsProfile >= GraphicsProfile.Level_10_0 ? DefaultGraphicsCompositorLevel10Url : DefaultGraphicsCompositorLevel9Url; var defaultGraphicsCompositor = dependencyPackage.Assets.Find(graphicsCompositorUrl); if (defaultGraphicsCompositor == null) { log.Error($"Could not find graphics compositor in Xenko package at location [{graphicsCompositorUrl}]"); return(false); } // Note: we create a derived asset without its content // We don't use defaultGraphicsCompositor content because it might be a newer version that next upgrades might not understand. // The override system will restore all the properties for us. var graphicsCompositorAssetId = AssetId.New(); var graphicsCompositorAsset = new PackageLoadingAssetFile(dependentPackage, "GraphicsCompositor.xkgfxcomp", null) { AssetContent = System.Text.Encoding.UTF8.GetBytes($"!GraphicsCompositorAsset\r\nId: {graphicsCompositorAssetId}\r\nSerializedVersion: {{Xenko: 1.10.0-beta01}}\r\nArchetype: {defaultGraphicsCompositor.ToReference()}"), }; assetFiles.Add(graphicsCompositorAsset); // Update game settings to point to our newly created compositor gameSettingsYaml.DynamicRootNode.GraphicsCompositor = new AssetReference(graphicsCompositorAssetId, graphicsCompositorAsset.AssetLocation).ToString(); } } // Delete EffectLogAsset foreach (var assetFile in assetFiles) { if (assetFile.FilePath.GetFileNameWithoutExtension() == EffectLogAsset.DefaultFile) { assetFile.Deleted = true; } } } if (dependency.Version.MinVersion < new PackageVersion("1.11.1.0")) { ConvertNormalMapsInvertY(assetFiles); } // Skybox/Background separation if (dependency.Version.MinVersion < new PackageVersion("1.11.1.1")) { SplitSkyboxLightingUpgrader upgrader = new SplitSkyboxLightingUpgrader(); foreach (var skyboxAsset in assetFiles.Where(f => f.FilePath.GetFileExtension() == ".xksky")) { upgrader.ProcessSkybox(skyboxAsset); } foreach (var sceneAsset in assetFiles.Where(f => (f.FilePath.GetFileExtension() == ".xkscene") || (f.FilePath.GetFileExtension() == ".xkprefab"))) { using (var yaml = sceneAsset.AsYamlAsset()) { upgrader.UpgradeAsset(yaml.DynamicRootNode); } } } if (dependency.Version.MinVersion < new PackageVersion("1.11.1.2")) { var navigationMeshAssets = assetFiles.Where(f => f.FilePath.GetFileExtension() == ".xknavmesh"); var scenes = assetFiles.Where(f => f.FilePath.GetFileExtension() == ".xkscene"); UpgradeNavigationBoundingBox(navigationMeshAssets, scenes); // Upgrade game settings to have groups for navigation meshes var gameSettingsAsset = assetFiles.FirstOrDefault(x => x.AssetLocation == GameSettingsAsset.GameSettingsLocation); if (gameSettingsAsset != null) { // Upgrade the game settings first to contain navigation mesh settings entry RunAssetUpgradersUntilVersion(log, dependentPackage, dependency.Name, gameSettingsAsset.Yield().ToList(), new PackageVersion("1.11.1.2")); UpgradeNavigationMeshGroups(navigationMeshAssets, gameSettingsAsset); } } if (dependency.Version.MinVersion < new PackageVersion("2.0.0.2")) { RunAssetUpgradersUntilVersion(log, dependentPackage, dependency.Name, assetFiles, new PackageVersion("2.0.0.0")); Guid defaultCompositorId = Guid.Empty; var defaultGraphicsCompositorCameraSlot = Guid.Empty; // Step one: find the default compositor, that will be the reference one to patch scenes var gameSettings = assetFiles.FirstOrDefault(x => x.AssetLocation == GameSettingsAsset.GameSettingsLocation); if (gameSettings != null) { using (var gameSettingsYaml = gameSettings.AsYamlAsset()) { dynamic asset = gameSettingsYaml.DynamicRootNode; string compositorReference = asset.GraphicsCompositor?.ToString(); var guidString = compositorReference?.Split(':').FirstOrDefault(); Guid.TryParse(guidString, out defaultCompositorId); // Figure out graphics profile; default is Level_10_0 (which is same as GraphicsCompositor default) var graphicsProfile = GraphicsProfile.Level_10_0; try { foreach (var mapping in gameSettingsYaml.DynamicRootNode.Defaults) { if (mapping.Node.Tag == "!Xenko.Graphics.RenderingSettings,Xenko.Graphics") { if (mapping.DefaultGraphicsProfile != null) { Enum.TryParse((string)mapping.DefaultGraphicsProfile, out graphicsProfile); } break; } } } catch { // If something goes wrong, keep going with the default value } // store the camera slot of the default graphics compositor, because the one from the project will be empty since upgrade relies on reconcile with base, which happens after defaultGraphicsCompositorCameraSlot = graphicsProfile >= GraphicsProfile.Level_10_0 ? DefaultGraphicsCompositorLevel10CameraSlot : DefaultGraphicsCompositorLevel9CameraSlot; } } // Step two: add an Guid for each item in the SceneCameraSlotCollection of each graphics compositor Dictionary <int, Guid> slotIds = new Dictionary <int, Guid>(); // This upgrades a projects that already had a graphics compositor before (ie. a project created with public 1.10) // In this case, the compositor that has been created above is empty, and the upgrade relies on reconciliation with base // to fill it properly, which means that for now we have no camera slot. Fortunately, we know the camera slot id from the archetype. slotIds.Add(0, defaultGraphicsCompositorCameraSlot); var graphicsCompositorAssets = assetFiles.Where(f => f.FilePath.GetFileExtension() == ".xkgfxcomp"); foreach (var graphicsCompositorAsset in graphicsCompositorAssets) { using (var yamlAsset = graphicsCompositorAsset.AsYamlAsset()) { dynamic asset = yamlAsset.DynamicRootNode; int i = 0; var localSlotIds = new Dictionary <int, Guid>(); if (asset.Cameras != null) { // This upgrades a projects that already had a graphics compositor before (ie. an internal project created with 1.11) foreach (dynamic cameraSlot in asset.Cameras) { var guid = Guid.NewGuid(); Guid assetId; if (Guid.TryParse(asset.Id.ToString(), out assetId) && assetId == defaultCompositorId) { slotIds[i] = guid; } localSlotIds.Add(i, guid); cameraSlot.Value.Id = guid; ++i; } var indexString = asset.Game?.Camera?.Index?.ToString(); int index; int.TryParse(indexString, out index); if (localSlotIds.ContainsKey(index) && asset.Game?.Camera != null) { asset.Game.Camera = $"ref!! {localSlotIds[index]}"; } } else { asset.Cameras = new YamlMappingNode(); asset.Cameras.de2e75c3b2b23e54162686363f3f138e = new YamlMappingNode(); asset.Cameras.de2e75c3b2b23e54162686363f3f138e.Id = defaultGraphicsCompositorCameraSlot; asset.Cameras.de2e75c3b2b23e54162686363f3f138e.Name = "Main"; } } } // Step three: patch every CameraComponent to reference the Guid instead of an index var entityHierarchyAssets = assetFiles.Where(f => f.FilePath.GetFileExtension() == ".xkscene" || f.FilePath.GetFileExtension() == ".xkprefab"); foreach (var entityHierarchyAsset in entityHierarchyAssets) { using (var yamlAsset = entityHierarchyAsset.AsYamlAsset()) { dynamic asset = yamlAsset.DynamicRootNode; foreach (var entity in asset.Hierarchy.Parts) { foreach (var component in entity.Entity.Components) { if (component.Value.Node.Tag == "!CameraComponent") { var indexString = component.Value.Slot?.Index?.ToString() ?? "0"; int index; if (int.TryParse(indexString, out index)) { if (slotIds.ContainsKey(index)) { component.Value.Slot = slotIds[index].ToString(); } else { component.Value.Slot = Guid.Empty.ToString(); } } } } } } } } #endif // Put any new upgrader after this #endif if (dependency.Version.MinVersion < new PackageVersion("2.2.0.1")) { foreach (var assetFile in assetFiles) { // Add new generic parameter to ShadowMapReceiverDirectional in effect log if (assetFile.FilePath.GetFileExtension() == ".xkeffectlog") { var assetContent = assetFile.AssetContent ?? File.ReadAllBytes(assetFile.FilePath.FullPath); var assetContentString = System.Text.Encoding.UTF8.GetString(assetContent); var newAssetContentString = System.Text.RegularExpressions.Regex.Replace(assetContentString, @"(\s*- ClassName: ShadowMapReceiverDirectional\r\n\s* GenericArguments: \[\w*, \w*, \w*, \w*, \w*)\]", "$1, false]"); newAssetContentString = newAssetContentString.Replace("EffectName: SkyboxShader\r\n", "EffectName: SkyboxShaderCubemap\r\n"); if (assetContentString != newAssetContentString) { // Need replacement, update with replaced text assetFile.AssetContent = System.Text.Encoding.UTF8.GetBytes(newAssetContentString); } } // Set BackgroundComponent.Is2D when necessary if (assetFile.FilePath.GetFileExtension() == ".xkscene" || assetFile.FilePath.GetFileExtension() == ".xkprefab") { using (var yamlAsset = assetFile.AsYamlAsset()) { dynamic asset = yamlAsset.DynamicRootNode; foreach (var entity in asset.Hierarchy.Parts) { foreach (var component in entity.Entity.Components) { if (component.Value.Node.Tag == "!BackgroundComponent" && component.Value.Texture != null) { if (!AssetReference.TryParse((string)component.Value.Texture, out var textureReference)) { continue; } // Find texture var textureAssetFile = assetFiles.FirstOrDefault(x => x.AssetLocation == textureReference.Location); if (textureAssetFile == null) { continue; } // Get texture source try { using (var yamlTextureAsset = textureAssetFile.AsYamlAsset()) { dynamic textureAsset = yamlTextureAsset.DynamicRootNode; if (textureAsset.Source == null) { continue; } var textureSource = UFile.Combine(textureAssetFile.FilePath.GetFullDirectory(), new UFile((string)textureAsset.Source)); if (!File.Exists(textureSource)) { continue; } var texTool = new TextureTool(); var image = texTool.Load(textureSource, false); if (image != null) { if (image.Dimension != TexImage.TextureDimension.TextureCube) { // We have a texture which is not a cubemap, mark background as 2D component.Value.Is2D = true; } image.Dispose(); } texTool.Dispose(); } } catch { // If something goes wrong, keep default value (assume cubemap) } } } } } } } } if (dependency.Version.MinVersion < new PackageVersion("3.0.0.0")) { // Delete EffectLogAsset foreach (var assetFile in assetFiles) { var assetContent = assetFile.AssetContent ?? File.ReadAllBytes(assetFile.FilePath.FullPath); var assetContentString = System.Text.Encoding.UTF8.GetString(assetContent); var newAssetContentString = RemoveSiliconStudioNamespaces(assetContentString); if (assetContentString != newAssetContentString) { // Need replacement, update with replaced text assetFile.AssetContent = System.Text.Encoding.UTF8.GetBytes(newAssetContentString); } } } return(true); }
private static async void Startup(UFile initialSessionPath) { try { InitializeLanguageSettings(); var serviceProvider = InitializeServiceProvider(); 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; await serviceProvider.Get <IEditorDialogService>().MessageBox(message, Core.Presentation.Services.MessageBoxButton.OK, Core.Presentation.Services.MessageBoxImage.Error); app.Shutdown(); return; } // Running first time? If yes, create nuget redirect package. var packageVersion = new PackageVersion(XenkoVersion.NuGetVersion); if (PackageStore.Instance.IsDevelopmentStore) { await PackageStore.Instance.CheckDeveloperTargetRedirects("Xenko", packageVersion, PackageStore.Instance.InstallationPath); } // We use a MRU that contains the older version projects to display in the editor var mru = new MostRecentlyUsedFileCollection(InternalSettings.LoadProfileCopy, InternalSettings.MostRecentlyUsedSessions, InternalSettings.WriteFile, XenkoGameStudio.EditorVersionMajor, true); mru.LoadFromSettings(); var editor = new GameStudioViewModel(serviceProvider, mru); AssetsPlugin.RegisterPlugin(typeof(XenkoDefaultAssetsPlugin)); AssetsPlugin.RegisterPlugin(typeof(XenkoEditorPlugin)); // Attempt to load the startup session, if available if (!UPath.IsNullOrEmpty(initialSessionPath)) { var sessionLoaded = await editor.OpenInitialSession(initialSessionPath); if (sessionLoaded == true) { var mainWindow = new GameStudioWindow(editor); Application.Current.MainWindow = mainWindow; WindowManager.ShowMainWindow(mainWindow); return; } } // No session successfully loaded, open the new/open project window bool?completed; // The user might cancel after chosing a template to instantiate, in this case we'll reopen the window var startupWindow = new ProjectSelectionWindow { WindowStartupLocation = WindowStartupLocation.CenterScreen, ShowInTaskbar = true, }; var viewModel = new NewOrOpenSessionTemplateCollectionViewModel(serviceProvider, startupWindow); startupWindow.Templates = viewModel; startupWindow.ShowDialog(); // The user selected a template to instantiate if (startupWindow.NewSessionParameters != null) { // Clean existing entry in the MRU data var directory = startupWindow.NewSessionParameters.OutputDirectory; var name = startupWindow.NewSessionParameters.OutputName; var mruData = new MRUAdditionalDataCollection(InternalSettings.LoadProfileCopy, GameStudioInternalSettings.MostRecentlyUsedSessionsData, InternalSettings.WriteFile); mruData.RemoveFile(UFile.Combine(UDirectory.Combine(directory, name), new UFile(name + SessionViewModel.SolutionExtension))); completed = await editor.NewSession(startupWindow.NewSessionParameters); } // The user selected a path to open else if (startupWindow.ExistingSessionPath != null) { completed = await editor.OpenSession(startupWindow.ExistingSessionPath); } // The user cancelled from the new/open project window, so exit the application else { completed = true; } if (completed != true) { var windowsClosed = new List <Task>(); foreach (var window in Application.Current.Windows.Cast <Window>().Where(x => x.IsLoaded)) { var tcs = new TaskCompletionSource <int>(); window.Unloaded += (s, e) => tcs.SetResult(0); windowsClosed.Add(tcs.Task); } await Task.WhenAll(windowsClosed); // When a project has been partially loaded, it might already have initialized some plugin that could conflict with // the next attempt to start something. Better start the application again. var commandLine = string.Join(" ", Environment.GetCommandLineArgs().Skip(1).Select(x => $"\"{x}\"")); var process = new Process { StartInfo = new ProcessStartInfo(typeof(Program).Assembly.Location, commandLine) }; process.Start(); app.Shutdown(); return; } if (editor.Session != null) { // If a session was correctly loaded, show the main window var mainWindow = new GameStudioWindow(editor); Application.Current.MainWindow = mainWindow; WindowManager.ShowMainWindow(mainWindow); } else { // Otherwise, exit. app.Shutdown(); } } catch (Exception) { app.Shutdown(); } }