Example #1
0
        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()));
        }
Example #2
0
        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);
        }
Example #3
0
        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);
            }
        }
Example #4
0
        protected void WriteGitIgnore(SessionTemplateGeneratorParameters parameters)
        {
            var fileName = UFile.Combine(parameters.OutputDirectory, ".gitignore");

            File.WriteAllText(fileName.ToWindowsPath(), GitIgnore);
        }
Example #5
0
        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);
        }
Example #6
0
        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();
            }
        }