public void Save(IEnumerable<string> removeMasters)
{
Log.Info("Saving plugin " + fileName);
byte thisPluginNumber = context.Plugins.GetPluginNumber(this);
// Collect all masters (Always add the main plugin as master)
HashSet<byte> collectedMasters = new HashSet<byte>() { 0 };
// Collect all referenced form IDs
HashSet<uint> referencedFormIds = GetReferencedFormIds();
foreach (var id in referencedFormIds)
{
if (!context.Forms.Contains(id))
{
//Log.Warning("Unable to determine the master of unresolved reference [0x{0:X8}].", id);
// Skip unresolved references, a warning will be issued while writing
// Handle unresolved references as best as possible, derive plugin number from formId and add it as a master
byte assumedPluginNumber = (byte)(id >> 24);
if (assumedPluginNumber != thisPluginNumber)
if (!collectedMasters.Contains(assumedPluginNumber))
collectedMasters.Add(assumedPluginNumber);
Log.Warning("Assumed unresolved form {0:X8} plugin {1}.", id, context.Plugins[assumedPluginNumber].FileName);
}
else
{
var form = context.Forms[id];
// Find the original form
// to add the original plugin which adds it as the master and not the last plugin which edits the referenced form
while (form.OverridesForm != null)
form = form.OverridesForm;
// Add if not of the current plugin
if (form.PluginNumber != thisPluginNumber)
if (!collectedMasters.Contains(form.PluginNumber))
collectedMasters.Add(form.PluginNumber);
}
}
// Form IDs this plugin is overriding
var overridenForms = Forms.Where(f => f.IsOverriding);
foreach (var form in overridenForms)
{
// Go through all overriden forms until the original form
var overridenForm = form.OverridesForm;
while (overridenForm != null)
{
if (!collectedMasters.Contains(overridenForm.PluginNumber))
collectedMasters.Add(overridenForm.PluginNumber);
// Next overriden form by this form
overridenForm = overridenForm.OverridesForm;
}
}
// Add masters (will be sorted by pluginNumber)
foreach (var number in collectedMasters.OrderBy(i => i))
{
var masterFileName = context.Plugins[number].FileName;
// Force remove masters
if (removeMasters != null && removeMasters.Contains(masterFileName))
continue;
// Already added (when appending)
if (header.GetMasterFiles().Contains(masterFileName))
continue;
header.AddMasterFile(masterFileName);
Log.Fine("Added master: {0}", masterFileName);
}
//// Make a backup of existing file
//string backupPath = null;
//if (File.Exists(path))
//{
// backupPath = path + "-" + (ulong)DateTime.Now.ToUniversalTime().Subtract(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds;
// File.Move(path, backupPath);
//}
if (!Forms.Any())
{
Log.Warning("No forms to write. Empty plugin will be generated.");
}
int count = 0;
long total = Forms.Count();
using (var progress = Display.StartProgress("Saving plugin"))
{
// Save plugin to memory stream
using (var stream = new MemoryStream())
{
using (var writer = context.CreateWriter(stream))
{
// Prepare reference mapper
writer.ReferenceMapper = new PluginReferenceMapper(this);
// Write header
header.PluginVersion = context.GetLatestPluginVersion();
writer.WriteHeader(header);
Log.Fine("Written header record");
// Write forms by type
foreach (var type in context.Forms.GetFormKinds())
{
var formOfType = Forms.Where(f => f.FormKind == type);
if (formOfType.Any())
Log.Fine("Writting {0}", type);
foreach (var form in formOfType)
{
writer.WriteRecord(form.Record, form.FormId);
count++;
progress.Update(count, total, "{0}:{1}", FileName, type);
}
}
Log.Fine("Written {0} form(s)", count);
writer.Close();
// Write memory stream to file
// only if changed
stream.Position = 0;
var file = context.DataFileProvider.GetDataFile(FileMode.Create, fileName);
if (!file.CopyFrom(stream, true))
{
Log.Info("New plugin content is the same as that of the existing plugin.");
}
}
}
}
Log.Info("Plugin saved");
}