Skip to content

Commit

Permalink
Switch to custom settings file/serialization.
Browse files Browse the repository at this point in the history
The built-in .NET settings system works fine for regular builds, but keeps changing the directory path used for published builds even if the assembly info hasn't changed.

Updates the Settings system to use a JSON file in the app directory, same as where autosaves, logs, etc. go.

Updates the minor version number, as recent updates have made significant changes and can no longer be considered a hotfix.
  • Loading branch information
focustense committed Jun 20, 2021
1 parent 14bd801 commit 5e17bdb
Show file tree
Hide file tree
Showing 11 changed files with 94 additions and 152 deletions.
9 changes: 1 addition & 8 deletions Focus.Apps.EasyNpc/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,9 @@ public partial class App : Application
{
private void Application_Startup(object sender, StartupEventArgs e)
{
if (BundlerSettings.Default.UpgradeRequired)
{
BundlerSettings.Default.Upgrade();
BundlerSettings.Default.UpgradeRequired = false;
BundlerSettings.Default.Save();
}

var isFirstLaunch =
e.Args.Contains("/forceintro", StringComparer.OrdinalIgnoreCase) ||
(string.IsNullOrEmpty(BundlerSettings.Default.ModRootDirectory) &&
(string.IsNullOrEmpty(Settings.Default.ModRootDirectory) &&
!File.Exists(ProgramData.ProfileLogFileName));
var debugMode = e.Args.Contains("/debug", StringComparer.OrdinalIgnoreCase);
var mainViewModel = new MainViewModel(isFirstLaunch, debugMode);
Expand Down
20 changes: 6 additions & 14 deletions Focus.Apps.EasyNpc/Build/BuildViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public async void BeginBuild()
Progress = new BuildProgressViewModel(log);
await Task.Run(() =>
{
OutputDirectory = Path.Combine(BundlerSettings.Default.ModRootDirectory, OutputModName);
OutputDirectory = Path.Combine(Settings.Default.ModRootDirectory, OutputModName);
Directory.CreateDirectory(OutputDirectory);
var buildSettings = new BuildSettings<TKey>
{
Expand Down Expand Up @@ -278,7 +278,7 @@ private IEnumerable<BuildWarning> CheckModPluginConsistency(
WarningMessages.FaceModPluginMismatch(npc.EditorId, npc.Name, npc.FaceModName, npc.FacePluginName));
var faceMeshFileName = FileStructure.GetFaceMeshFileName(npc.BasePluginName, npc.LocalFormIdHex);
var hasLooseFacegen = File.Exists(
Path.Combine(BundlerSettings.Default.ModRootDirectory, npc.FaceModName, faceMeshFileName));
Path.Combine(Settings.Default.ModRootDirectory, npc.FaceModName, faceMeshFileName));
var hasArchiveFacegen = modPluginMap.GetArchivesForMod(npc.FaceModName)
.Select(f => archiveFileMap.ContainsFile(f, faceMeshFileName))
.Any(exists => exists);
Expand All @@ -305,7 +305,7 @@ private IEnumerable<BuildWarning> CheckModPluginConsistency(

private IEnumerable<BuildWarning> CheckModSettings()
{
var modRootDirectory = BundlerSettings.Default.ModRootDirectory;
var modRootDirectory = Settings.Default.ModRootDirectory;
if (string.IsNullOrWhiteSpace(modRootDirectory))
yield return new BuildWarning(
BuildWarningId.ModDirectoryNotSpecified,
Expand Down Expand Up @@ -343,22 +343,14 @@ private IEnumerable<BuildWarning> CheckWigs()

private static ILookup<string, BuildWarningId> GetBuildWarningSuppressions()
{
return BundlerSettings.Default.BuildWarningWhitelist
.Cast<string>()
.Select(s => s.Split('='))
.Where(items => items.Length == 2)
.Select(items => new
{
Plugin = items[0],
Warnings = BuildWarningSuppressions.ParseWarnings(items[1])
})
.SelectMany(x => x.Warnings.Select(id => new { Plugin = x.Plugin, Id = id }))
return Settings.Default.BuildWarningWhitelist
.SelectMany(x => x.IgnoredWarnings.Select(id => new { Plugin = x.PluginName, Id = id }))
.ToLookup(x => x.Plugin, x => x.Id);
}

private static bool ModDirectoryIsNotEmpty(string modName)
{
var modRootDirectory = BundlerSettings.Default.ModRootDirectory;
var modRootDirectory = Settings.Default.ModRootDirectory;
var modDirectory = Path.Combine(modRootDirectory, modName);
return Directory.Exists(modDirectory) && Directory.EnumerateFiles(modDirectory).Any();
}
Expand Down
4 changes: 2 additions & 2 deletions Focus.Apps.EasyNpc/Build/MergedFolder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public static void Build<TKey>(
{
var log = logger.ForContext("Type", "MergedFolder");

var modRootDirectory = BundlerSettings.Default.ModRootDirectory;
var modRootDirectory = Settings.Default.ModRootDirectory;
if (string.IsNullOrEmpty(modRootDirectory))
{
progress.ErrorMessage = "No mod directory specified; cannot build merged mod.";
Expand All @@ -42,7 +42,7 @@ public static void Build<TKey>(
// - Facegen meshes/textures: 50%

progress.StartStage("Creating merge output directory");
var outDir = Path.Combine(BundlerSettings.Default.ModRootDirectory, buildSettings.OutputModName);
var outDir = Path.Combine(Settings.Default.ModRootDirectory, buildSettings.OutputModName);
Directory.CreateDirectory(outDir);
log.Information("Merge folder is ready at {MergeDirectoryName}", outDir);

Expand Down
75 changes: 0 additions & 75 deletions Focus.Apps.EasyNpc/Configuration/BundlerSettings.Designer.cs

This file was deleted.

19 changes: 0 additions & 19 deletions Focus.Apps.EasyNpc/Configuration/BundlerSettings.settings

This file was deleted.

5 changes: 3 additions & 2 deletions Focus.Apps.EasyNpc/Configuration/ProgramData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ namespace Focus.Apps.EasyNpc.Configuration
{
static class ProgramData
{
public static string ConfiguredMugshotsPath => !string.IsNullOrEmpty(BundlerSettings.Default.MugshotsDirectory) ?
BundlerSettings.Default.MugshotsDirectory : DefaultMugshotsPath;
public static string ConfiguredMugshotsPath => !string.IsNullOrEmpty(Settings.Default.MugshotsDirectory) ?
Settings.Default.MugshotsDirectory : DefaultMugshotsPath;

public static readonly string DefaultMugshotsPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Mugshots");
public static readonly string DirectoryPath = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), AssemblyProperties.Name);
public static readonly string LogFileName =
Path.Combine(DirectoryPath, $"Log_{DateTime.Now:yyyyMMdd_HHmmss_fffffff}.txt");
public static readonly string ProfileLogFileName = Path.Combine(DirectoryPath, "Profile.log");
public static readonly string SettingsPath = Path.Combine(DirectoryPath, "Settings.json");
}
}
74 changes: 74 additions & 0 deletions Focus.Apps.EasyNpc/Configuration/Settings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
using Focus.Apps.EasyNpc.Build;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;

namespace Focus.Apps.EasyNpc.Configuration
{
public class Settings
{
// This needs to be first (contrary to default sorting rules) so that it can be used in the Default
// construction.
private static readonly JsonSerializer Serializer = new()
{
ContractResolver = new DefaultContractResolver
{
NamingStrategy = new CamelCaseNamingStrategy(),
},
Formatting = Formatting.Indented,
};

public static Settings Default = new(ProgramData.SettingsPath);

public List<BuildWarningSuppression> BuildWarningWhitelist { get; set; } = new();
public string ModRootDirectory { get; set; }
public string MugshotsDirectory { get; set; }

private readonly string path;

public Settings(string path)
{
this.path = path;
Load();
}

public void Save()
{
using var fs = File.Create(path);
using var streamWriter = new StreamWriter(fs);
using var jsonWriter = new JsonTextWriter(streamWriter);
Serializer.Serialize(jsonWriter, this);
}

private void Load()
{
if (!File.Exists(path))
return;
using var fs = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
using var streamReader = new StreamReader(fs);
using var jsonReader = new JsonTextReader(streamReader);
Serializer.Populate(jsonReader, this);
}
}

public class BuildWarningSuppression
{
public string PluginName { get; set; }
[JsonProperty(ItemConverterType = typeof(StringEnumConverter))]
public List<BuildWarningId> IgnoredWarnings { get; set; } = new();

public BuildWarningSuppression()
{
}

public BuildWarningSuppression(string pluginName, IEnumerable<BuildWarningId> ignoredWarnings)
{
PluginName = pluginName;
IgnoredWarnings = ignoredWarnings.ToList();
}
}
}
22 changes: 5 additions & 17 deletions Focus.Apps.EasyNpc/Configuration/SettingsViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace Focus.Apps.EasyNpc.Configuration
{
public class SettingsViewModel : INotifyPropertyChanged
{
private static readonly BundlerSettings Settings = BundlerSettings.Default;
private static readonly Settings Settings = Settings.Default;

public event PropertyChangedEventHandler PropertyChanged;
public event EventHandler WelcomeAcked;
Expand All @@ -25,10 +25,7 @@ public class SettingsViewModel : INotifyPropertyChanged
public SettingsViewModel()
{
var entries = Settings.BuildWarningWhitelist
.Cast<string>()
.Select(s => s.Split('='))
.Where(items => items.Length == 2)
.Select(items => new BuildWarningSuppressions(items[0], BuildWarningSuppressions.ParseWarnings(items[1])));
.Select(x => new BuildWarningSuppressions(x.PluginName, x.IgnoredWarnings));
BuildWarningWhitelist = new(entries);
BuildWarningWhitelist.CollectionChanged += BuildWarningWhitelist_CollectionChanged;
foreach (var entry in BuildWarningWhitelist)
Expand Down Expand Up @@ -104,18 +101,9 @@ private void BuildWarningWhitelist_CollectionChanged(object sender, NotifyCollec

private void SaveBuildWarningSuppressions()
{
// As suppressions are currently stored as a single serialized collection, we have to regenerate the whole
// value each time. This probably won't make much of a difference in practice - there's no reason any user
// should be adding suppressions for hundreds of plugins.
while (Settings.BuildWarningWhitelist.Count > BuildWarningWhitelist.Count)
Settings.BuildWarningWhitelist.RemoveAt(Settings.BuildWarningWhitelist.Count - 1);
while (Settings.BuildWarningWhitelist.Count < BuildWarningWhitelist.Count)
Settings.BuildWarningWhitelist.Add(null);
for (int i = 0; i < BuildWarningWhitelist.Count; i++)
{
var suppressions = BuildWarningWhitelist[i];
Settings.BuildWarningWhitelist[i] = $"{suppressions.PluginName}={suppressions.SerializeWarnings()}";
}
Settings.BuildWarningWhitelist = BuildWarningWhitelist
.Select(x => new BuildWarningSuppression(x.PluginName, x.SelectedWarnings))
.ToList();
Settings.Save();
}

Expand Down
14 changes: 1 addition & 13 deletions Focus.Apps.EasyNpc/Focus.Apps.EasyNpc.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<AssemblyName>EasyNPC</AssemblyName>
<AssemblyTitle>Easy NPC</AssemblyTitle>
<Product>EasyMod</Product>
<Version>0.1.1</Version>
<Version>0.2.0</Version>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
Expand Down Expand Up @@ -56,23 +56,11 @@
</ItemGroup>

<ItemGroup>
<Compile Update="Configuration\BundlerSettings.Designer.cs">
<DesignTimeSharedInput>True</DesignTimeSharedInput>
<AutoGen>True</AutoGen>
<DependentUpon>BundlerSettings.settings</DependentUpon>
</Compile>
<Compile Update="Configuration\SettingsPage.xaml.cs">
<SubType>Code</SubType>
</Compile>
</ItemGroup>

<ItemGroup>
<None Update="Configuration\BundlerSettings.settings">
<Generator>PublicSettingsSingleFileGenerator</Generator>
<LastGenOutput>BundlerSettings.Designer.cs</LastGenOutput>
</None>
</ItemGroup>

<ItemGroup>
<Page Update="Configuration\SettingsPage.xaml">
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
Expand Down
2 changes: 1 addition & 1 deletion Focus.Apps.EasyNpc/GameData/Files/IModPluginMapFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public static class ModPluginMapFactoryExtensions
{
public static ModPluginMap DefaultMap(this IModPluginMapFactory modPluginMapFactory)
{
return modPluginMapFactory.CreateForDirectory(BundlerSettings.Default.ModRootDirectory);
return modPluginMapFactory.CreateForDirectory(Settings.Default.ModRootDirectory);
}
}
}
2 changes: 1 addition & 1 deletion Focus.Apps.EasyNpc/Mutagen/MutagenMergedPluginBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ public MergedPluginResult Build(
progress.StartStage("Saving");
progress.JumpTo(0.99f);
var outFilePath = Path.Combine(
BundlerSettings.Default.ModRootDirectory, buildSettings.OutputModName, MergeFileName);
Settings.Default.ModRootDirectory, buildSettings.OutputModName, MergeFileName);
mergedMod.WriteToBinaryParallel(outFilePath);

progress.StartStage("Done");
Expand Down

0 comments on commit 5e17bdb

Please sign in to comment.