/
UpdatePlatformsTemplateGenerator.cs
225 lines (184 loc) · 10.6 KB
/
UpdatePlatformsTemplateGenerator.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
// Copyright (c) Xenko contributors (https://xenko.com) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Xml.Linq;
using Xenko.Core.Assets;
using Xenko.Core.Assets.Templates;
using Xenko.Core;
using Xenko.Core.Diagnostics;
using Xenko.Core.Extensions;
using Xenko.Core.IO;
using Xenko.Core.Presentation.Services;
using Xenko.Core.Presentation.Windows;
using Xenko.Core.ProjectTemplating;
using Xenko.Assets.Templates;
using Xenko.Graphics;
namespace Xenko.Assets.Presentation.Templates
{
/// <summary>
/// This generator will update the platforms of a given package.
/// </summary>
public class UpdatePlatformsTemplateGenerator : TemplateGeneratorBase<PackageTemplateGeneratorParameters>
{
private static readonly PropertyKey<List<SelectedSolutionPlatform>> PlatformsKey = new PropertyKey<List<SelectedSolutionPlatform>>("Platforms", typeof(UpdatePlatformsTemplateGenerator));
private static readonly PropertyKey<bool> ForcePlatformRegenerationKey = new PropertyKey<bool>("ForcePlatformRegeneration", typeof(UpdatePlatformsTemplateGenerator));
private static readonly PropertyKey<DisplayOrientation> OrientationKey = new PropertyKey<DisplayOrientation>("Orientation", typeof(UpdatePlatformsTemplateGenerator));
public static readonly UpdatePlatformsTemplateGenerator Default = new UpdatePlatformsTemplateGenerator();
public static readonly Guid TemplateId = new Guid("446B52D3-A6A8-4274-A357-736ADEA87321");
public override bool IsSupportingTemplate(TemplateDescription templateDescription)
{
if (templateDescription == null) throw new ArgumentNullException(nameof(templateDescription));
return templateDescription.Id == TemplateId;
}
public static void SetPlatforms(PackageTemplateGeneratorParameters parameters, IEnumerable<SelectedSolutionPlatform> platforms) => parameters.SetTag(PlatformsKey, new List<SelectedSolutionPlatform>(platforms));
public static void SetForcePlatformRegeneration(PackageTemplateGeneratorParameters parameters, bool value) => parameters.SetTag(ForcePlatformRegenerationKey, value);
public static void SetOrientation(PackageTemplateGeneratorParameters parameters, DisplayOrientation displayOrientation) => parameters.SetTag(OrientationKey, displayOrientation);
public override async Task<bool> PrepareForRun(PackageTemplateGeneratorParameters parameters)
{
if (parameters == null) throw new ArgumentNullException(nameof(parameters));
parameters.Validate();
var package = parameters.Package;
var gameSettingsAsset = package.GetGameSettingsAsset();
if (gameSettingsAsset == null)
{
parameters.Logger.Error($"Could not find game settings asset at location [{GameSettingsAsset.GameSettingsLocation}]");
return false;
}
// TODO CSPROJ=XKPKG
// If there are no executable/shared projects in this package, we can't work on it
/*var sharedProfile = package.Profile;
var existingPlatformTypesWithExe = new HashSet<PlatformType>(package.Profiles.Where(profile => profile.Platform != PlatformType.Shared && profile.ProjectReferences.Any(projectRef => projectRef.Type == ProjectType.Executable)).Select(item => item.Platform));
if (sharedProfile == null || existingPlatformTypesWithExe.Count == 0)
{
parameters.Logger.Error("The selected package does not contain a shared profile with executable projects");
return false;
}
var defaultNamespace = GetDefaultNamespace(parameters);
if (parameters.Unattended)
{
if (!parameters.HasTag(PlatformsKey))
throw new InvalidOperationException("The platforms must be set with SetPlatforms before calling PrepareForRun if DontAskForPlatforms is true.");
parameters.SetTag(ForcePlatformRegenerationKey, true);
}
else
{
var window = new UpdatePlatformsWindow(existingPlatformTypesWithExe)
{
ForcePlatformRegenerationVisible = parameters.TryGetTag(ForcePlatformRegenerationKey)
};
await window.ShowModal();
if (window.Result == DialogResult.Cancel)
return false;
parameters.SetTag(PlatformsKey, new List<SelectedSolutionPlatform>(window.SelectedPlatforms));
parameters.SetTag(ForcePlatformRegenerationKey, window.ForcePlatformRegeneration);
}
parameters.SetTag(OrientationKey, (DisplayOrientation)gameSettingsAsset.GetOrCreate<RenderingSettings>().DisplayOrientation);
parameters.Namespace = defaultNamespace;*/
return true;
}
public sealed override bool Run(PackageTemplateGeneratorParameters parameters)
{
if (parameters == null) throw new ArgumentNullException(nameof(parameters));
var logger = parameters.Logger;
var name = parameters.Name;
var package = parameters.Package;
// Generate executable projects for each platform
var sharedProfile = package.Profile;
// TODO: this is not a safe way to get a game project see PDX-1128
var gameProject = package.Container as SolutionProject;
if (gameProject == null)
{
return false;
}
// We need to patch the previous game project in order to regenerate property groups
var templateGameLibrary = PrepareTemplate(parameters, "ProjectLibrary.Game/ProjectLibrary.Game.ttproj", PlatformType.Shared, null, null, ProjectType.Library);
var options = ProjectTemplateGeneratorHelper.GetOptions(parameters);
var newGameTargetFrameworks = templateGameLibrary.GeneratePart(@"..\Common.TargetFrameworks.targets.t4", logger, options);
PatchGameProject(newGameTargetFrameworks, gameProject.FullPath.ToWindowsPath());
// Generate missing platforms
bool forceGenerating = parameters.GetTag(ForcePlatformRegenerationKey);
ProjectTemplateGeneratorHelper.UpdatePackagePlatforms(parameters, parameters.GetTag(PlatformsKey), parameters.GetTag(OrientationKey), package.Id, name, package, forceGenerating);
// Save the session after the update
// FIXME: Saving like this is not supported anymore - let's not save for now be we should provide a proper way to save!
//var result = package.Session.Save();
//result.CopyTo(logger);
// Log done
ProjectTemplateGeneratorHelper.Progress(logger, "Done", 1, 1);
return true;
}
private static string GetDefaultNamespace(PackageTemplateGeneratorParameters parameters)
{
var logger = parameters.Logger;
var package = parameters.Package;
var defaultNamespace = package.Meta.RootNamespace;
if (string.IsNullOrWhiteSpace(defaultNamespace))
{
// Get the shared profile
var sharedProfile = package.Profile;
// Get the game project
var gameProjectRef = (package.Container as SolutionProject)?.FullPath;
if (gameProjectRef != null)
{
try
{
var project = VSProjectHelper.LoadProject(gameProjectRef);
defaultNamespace = project.GetPropertyValue("RootNamespace");
}
catch (Exception e)
{
e.Ignore();
}
}
}
if (string.IsNullOrWhiteSpace(defaultNamespace))
{
defaultNamespace = parameters.Name.Replace(' ', '_');
}
return defaultNamespace;
}
private static ProjectTemplate PrepareTemplate(PackageTemplateGeneratorParameters parameters, UFile templateRelativePath, PlatformType platformType, string currentProfile, GraphicsPlatform? graphicsPlatform, ProjectType projectType)
{
ProjectTemplateGeneratorHelper.AddOption(parameters, "Platforms", parameters.GetTag(PlatformsKey).Select(x => x.Platform).ToList());
ProjectTemplateGeneratorHelper.AddOption(parameters, "CurrentPlatform", platformType);
ProjectTemplateGeneratorHelper.AddOption(parameters, "CurrentProfile", currentProfile);
ProjectTemplateGeneratorHelper.AddOption(parameters, "Orientation", parameters.GetTag(OrientationKey));
var package = parameters.Package;
return ProjectTemplateGeneratorHelper.PrepareTemplate(parameters, package, templateRelativePath, platformType, graphicsPlatform, projectType);
}
private static bool MatchPropertyGroup(XElement element)
{
return element.Name.LocalName == "PropertyGroup";
}
private static void PatchGameProject(string partialContent, string filePath)
{
bool TargetFrameworkFilter(XElement x) => x.Name == "TargetFramework" || x.Name == "TargetFrameworks";
var content = "<Project><PropertyGroup>" +
partialContent + "</PropertyGroup></Project>";
var docPatch = XDocument.Load(new StringReader(content));
var docToModify = XDocument.Load(new StringReader(File.ReadAllText(filePath)));
var newPropertyGroups = docPatch.Root.Elements().Where(MatchPropertyGroup).ToList();
var currentPropertyGroups = docToModify.Root.Elements().Where(MatchPropertyGroup).ToList();
var targetFrameworkReplaced = false;
foreach (var property in currentPropertyGroups.SelectMany(x => x.Elements()).ToList())
{
if (TargetFrameworkFilter(property))
{
if (!targetFrameworkReplaced)
{
property.ReplaceWith(newPropertyGroups.Elements().Where(TargetFrameworkFilter));
targetFrameworkReplaced = true;
}
else
{
property.Remove();
}
}
}
docToModify.Save(filePath);
}
}
}