mirror of
https://git.do.srb2.org/STJr/UltimateZoneBuilder.git
synced 2024-11-23 12:22:35 +00:00
540 lines
No EOL
15 KiB
C#
Executable file
540 lines
No EOL
15 KiB
C#
Executable file
|
||
#region ================== Copyright (c) 2007 Pascal vd Heiden
|
||
|
||
/*
|
||
* Copyright (c) 2007 Pascal vd Heiden, www.codeimp.com
|
||
* This program is released under GNU General Public License
|
||
*
|
||
* This program is distributed in the hope that it will be useful,
|
||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
* GNU General Public License for more details.
|
||
*
|
||
*/
|
||
|
||
#endregion
|
||
|
||
#region ================== Namespaces
|
||
|
||
using System;
|
||
using System.Windows.Forms;
|
||
using System.IO;
|
||
using CodeImp.DoomBuilder.Data;
|
||
using CodeImp.DoomBuilder.Config;
|
||
using System.Collections.Generic;
|
||
using System.ComponentModel;
|
||
using System.Threading.Tasks;
|
||
using CodeImp.DoomBuilder.ZDoom;
|
||
using System.Threading;
|
||
|
||
#endregion
|
||
|
||
namespace CodeImp.DoomBuilder.Windows
|
||
{
|
||
internal partial class ResourceOptionsForm : DelayedForm
|
||
{
|
||
// Variables
|
||
private DataLocation res;
|
||
private string startPath;
|
||
private Controls.FolderSelectDialog dirdialog;
|
||
private List<string> requiredarchives;
|
||
|
||
// Properties
|
||
public DataLocation ResourceLocation { get { return res; } }
|
||
public GameConfiguration GameConfiguration { get; set; }
|
||
|
||
//
|
||
private bool _ischeckingrequiredarchives = false;
|
||
private bool IsCheckingRequiredArchives
|
||
{
|
||
get
|
||
{
|
||
return _ischeckingrequiredarchives;
|
||
}
|
||
set
|
||
{
|
||
if (value)
|
||
{
|
||
apply.Enabled = false;
|
||
cancel.Enabled = false;
|
||
notfortesting.Enabled = false;
|
||
dir_textures.Enabled = false;
|
||
dir_flats.Enabled = false;
|
||
ControlBox = false;
|
||
checkingloader.Visible = true;
|
||
}
|
||
else
|
||
{
|
||
apply.Enabled = true;
|
||
cancel.Enabled = true;
|
||
notfortesting.Enabled = true;
|
||
dir_textures.Enabled = true;
|
||
dir_flats.Enabled = true;
|
||
ControlBox = true;
|
||
checkingloader.Visible = false;
|
||
}
|
||
_ischeckingrequiredarchives = value;
|
||
}
|
||
}
|
||
|
||
// Constructor
|
||
public ResourceOptionsForm(DataLocation settings, string caption, string startPath) //mxd. added startPath
|
||
{
|
||
// Initialize
|
||
InitializeComponent();
|
||
|
||
#if NO_WIN32
|
||
// No easy way to have case-insesitivity for non-Windows platforms
|
||
wadfiledialog.Filter = "Doom WAD Files (*.wad)|*.wad;*.Wad;*.wAd;*.WAd;*.waD;*.WaD;*.wAD;*.WAD";
|
||
pk3filedialog.Filter = "Doom PK3/PKE/PK7 Files (*.pk3;*.pke;*.pk7;*.ipk3;*.ipk7)|" +
|
||
"*.pk3;*.Pk3;*.pK3;*.PK3;" +
|
||
"*.pke;*.Pke;*.pKe;*.PKe;*.pkE;*.PkE;*.pKE;*.PKE;" +
|
||
"*.pk7;*.Pk7;*.pK7;*.PK7;" +
|
||
"*.ipk3;*.iPk3;*.ipK3;*.iPK3;*.Ipk3;*.IPk3;*.IpK3;*.IPK3;" +
|
||
"*.ipk7;*.iPk7;*.ipK7;*.iPK7;*.Ipk7;*.IPk7;*.IpK7;*.IPK7";
|
||
#endif
|
||
|
||
// Set caption
|
||
this.Text = caption;
|
||
|
||
//
|
||
this.requiredarchives = new List<string>();
|
||
|
||
// Apply settings from ResourceLocation
|
||
this.res = settings;
|
||
switch(res.type)
|
||
{
|
||
// Setup for WAD File
|
||
case DataLocation.RESOURCE_WAD:
|
||
wadlocation.Text = res.location;
|
||
strictpatches.Checked = res.option1;
|
||
break;
|
||
|
||
// Setup for Directory
|
||
case DataLocation.RESOURCE_DIRECTORY:
|
||
dirlocation.Text = res.location;
|
||
dir_textures.Checked = res.option1;
|
||
dir_flats.Checked = res.option2;
|
||
break;
|
||
|
||
// Setup for PK3 File
|
||
case DataLocation.RESOURCE_PK3:
|
||
pk3location.Text = res.location;
|
||
break;
|
||
}
|
||
|
||
// Select appropriate tab
|
||
tabs.SelectedIndex = res.type;
|
||
|
||
// Checkbox
|
||
notfortesting.Checked = res.notfortesting;
|
||
|
||
this.startPath = startPath;
|
||
}
|
||
|
||
protected override void OnClosing(CancelEventArgs e)
|
||
{
|
||
base.OnClosing(e);
|
||
if (IsCheckingRequiredArchives) e.Cancel = true;
|
||
}
|
||
|
||
public static List<string> CheckRequiredArchives(GameConfiguration config, DataLocation loc, CancellationToken token)
|
||
{
|
||
#if DEBUG
|
||
General.WriteLogLine(string.Format("CheckRequiredArchives (Config = {0})", config?.Name));
|
||
#endif
|
||
|
||
if (config == null)
|
||
return new List<string>();
|
||
|
||
try
|
||
{
|
||
DataReader dr = null;
|
||
List<string> requiredarchives = new List<string>();
|
||
HashSet<string> classes = null;
|
||
|
||
switch (loc.type)
|
||
{
|
||
case DataLocation.RESOURCE_WAD:
|
||
dr = new WADReader(loc, config, true) { Silent = true };
|
||
break;
|
||
|
||
case DataLocation.RESOURCE_DIRECTORY:
|
||
dr = new DirectoryReader(loc, config, true) { Silent = true };
|
||
break;
|
||
|
||
case DataLocation.RESOURCE_PK3:
|
||
dr = new PK3Reader(loc, config, true) { Silent = true };
|
||
break;
|
||
}
|
||
|
||
token.ThrowIfCancellationRequested();
|
||
|
||
foreach (var arc in config.RequiredArchives)
|
||
{
|
||
bool found = true;
|
||
|
||
token.ThrowIfCancellationRequested();
|
||
|
||
foreach (RequiredArchiveEntry e in arc.Entries)
|
||
{
|
||
token.ThrowIfCancellationRequested();
|
||
|
||
if (e.Class != null)
|
||
{
|
||
if (classes == null)
|
||
{
|
||
classes = new HashSet<string>();
|
||
|
||
// load ZScript
|
||
var zscript = new ZScriptParser {
|
||
NoWarnings = true,
|
||
OnInclude = (parser, location) => {
|
||
IEnumerable<TextResourceData> includeStreams = dr.GetZScriptData(location);
|
||
foreach (TextResourceData data in includeStreams)
|
||
{
|
||
// Parse this data
|
||
parser.Parse(data, false);
|
||
|
||
//mxd. DECORATE lumps are interdepandable. Can't carry on...
|
||
if (parser.HasError)
|
||
break;
|
||
}
|
||
}
|
||
};
|
||
|
||
foreach (TextResourceData data in dr.GetZScriptData("ZSCRIPT"))
|
||
{
|
||
// Parse the data
|
||
data.Stream.Seek(0, SeekOrigin.Begin);
|
||
zscript.Parse(data, true);
|
||
|
||
if (zscript.HasError)
|
||
break;
|
||
|
||
foreach (string cls in zscript.LastClasses)
|
||
classes.Add(cls.ToLowerInvariant());
|
||
}
|
||
|
||
#if DEBUG
|
||
if (zscript.HasError)
|
||
General.WriteLogLine(string.Format("CRA({0}): ZScript error: {1}", loc.location, zscript.ErrorDescription));
|
||
#endif
|
||
|
||
// load DECORATE
|
||
var decorate = new DecorateParser(zscript.AllActorsByClass) {
|
||
NoWarnings = true,
|
||
OnInclude = (parser, location) => {
|
||
IEnumerable<TextResourceData> includeStreams = dr.GetDecorateData(location);
|
||
foreach (TextResourceData data in includeStreams)
|
||
{
|
||
// Parse this data
|
||
parser.Parse(data, false);
|
||
|
||
//mxd. DECORATE lumps are interdepandable. Can't carry on...
|
||
if (parser.HasError)
|
||
break;
|
||
}
|
||
}
|
||
};
|
||
|
||
foreach (TextResourceData data in dr.GetDecorateData("DECORATE"))
|
||
{
|
||
// Parse the data
|
||
data.Stream.Seek(0, SeekOrigin.Begin);
|
||
decorate.Parse(data, true);
|
||
|
||
if (decorate.HasError)
|
||
break;
|
||
|
||
foreach (string cls in decorate.LastClasses)
|
||
classes.Add(cls.ToLowerInvariant());
|
||
}
|
||
|
||
#if DEBUG
|
||
if (decorate.HasError)
|
||
General.WriteLogLine(string.Format("CRA({0}): DECORATE error: {1}", loc.location, decorate.ErrorDescription));
|
||
#endif
|
||
}
|
||
|
||
if (!classes.Contains(e.Class.ToLowerInvariant()))
|
||
{
|
||
#if DEBUG
|
||
General.WriteLogLine(string.Format("CRA({2}): Does not contain class: {1} <- {0}", string.Join(",", classes), e.Class, loc.location));
|
||
#endif
|
||
found = false;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (e.Lump != null && !dr.FileExists(e.Lump))
|
||
{
|
||
#if DEBUG
|
||
General.WriteLogLine(string.Format("CRA({1}): Does not contain lump: {0}", e.Lump, loc.location));
|
||
#endif
|
||
found = false;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (found)
|
||
{
|
||
requiredarchives.Add(arc.ID);
|
||
}
|
||
}
|
||
|
||
dr.Dispose();
|
||
|
||
return requiredarchives;
|
||
}
|
||
catch (OperationCanceledException)
|
||
{
|
||
throw;
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
General.WriteLogLine(e.ToString());
|
||
return new List<string>();
|
||
}
|
||
}
|
||
|
||
private List<string> RunCheckRequiredArchives()
|
||
{
|
||
// thanks ms for making this a struct
|
||
CancellationTokenSource dummySource = new CancellationTokenSource();
|
||
List<string> output = CheckRequiredArchives(GameConfiguration, ToDataLocation(), dummySource.Token);
|
||
dummySource.Dispose();
|
||
return output;
|
||
}
|
||
|
||
private async void StartRequiredArchivesCheck()
|
||
{
|
||
IsCheckingRequiredArchives = true;
|
||
|
||
try
|
||
{
|
||
requiredarchives = await Task.Run(() => RunCheckRequiredArchives());
|
||
}
|
||
catch
|
||
{
|
||
requiredarchives = new List<string>();
|
||
}
|
||
|
||
ApplyDefaultRequiredArchivesSetting();
|
||
|
||
IsCheckingRequiredArchives = false;
|
||
}
|
||
|
||
private void ApplyDefaultRequiredArchivesSetting()
|
||
{
|
||
dir_textures.Checked = false;
|
||
dir_flats.Checked = false;
|
||
notfortesting.Checked = false;
|
||
// if any of the detected required archives implies "not for testing" <20> disable it by default
|
||
foreach (var arc in GameConfiguration.RequiredArchives)
|
||
{
|
||
if (requiredarchives.Contains(arc.ID) && arc.ExcludeFromTesting)
|
||
notfortesting.Checked = true;
|
||
}
|
||
}
|
||
|
||
private DataLocation ToDataLocation()
|
||
{
|
||
DataLocation res = new DataLocation();
|
||
res.location = "";
|
||
res.requiredarchives = requiredarchives;
|
||
|
||
// Apply settings to ResourceLocation
|
||
switch (tabs.SelectedIndex)
|
||
{
|
||
// Setup WAD File
|
||
case DataLocation.RESOURCE_WAD:
|
||
|
||
// Check if file is specified
|
||
if ((wadlocation.Text.Length == 0) ||
|
||
(!File.Exists(wadlocation.Text)))
|
||
{
|
||
break;
|
||
}
|
||
else
|
||
{
|
||
// Apply settings
|
||
res.type = DataLocation.RESOURCE_WAD;
|
||
res.location = wadlocation.Text;
|
||
res.option1 = strictpatches.Checked;
|
||
res.option2 = false;
|
||
res.notfortesting = notfortesting.Checked;
|
||
}
|
||
break;
|
||
|
||
// Setup Directory
|
||
case DataLocation.RESOURCE_DIRECTORY:
|
||
|
||
// Check if directory is specified
|
||
if ((dirlocation.Text.Length == 0) ||
|
||
(!Directory.Exists(dirlocation.Text)))
|
||
{
|
||
break;
|
||
}
|
||
else
|
||
{
|
||
// Apply settings
|
||
res.type = DataLocation.RESOURCE_DIRECTORY;
|
||
res.location = dirlocation.Text;
|
||
res.option1 = dir_textures.Checked;
|
||
res.option2 = dir_flats.Checked;
|
||
res.notfortesting = notfortesting.Checked;
|
||
}
|
||
break;
|
||
|
||
// Setup PK3 File
|
||
case DataLocation.RESOURCE_PK3:
|
||
|
||
// Check if file is specified
|
||
if ((pk3location.Text.Length == 0) ||
|
||
(!File.Exists(pk3location.Text)))
|
||
{
|
||
break;
|
||
}
|
||
else
|
||
{
|
||
// Apply settings
|
||
res.type = DataLocation.RESOURCE_PK3;
|
||
res.location = pk3location.Text;
|
||
res.option1 = false;
|
||
res.option2 = false;
|
||
res.notfortesting = notfortesting.Checked;
|
||
}
|
||
break;
|
||
}
|
||
|
||
return res;
|
||
}
|
||
|
||
// OK clicked
|
||
private void apply_Click(object sender, EventArgs e)
|
||
{
|
||
res = ToDataLocation();
|
||
if (res.location == "")
|
||
{
|
||
switch (tabs.SelectedIndex)
|
||
{
|
||
case DataLocation.RESOURCE_WAD:
|
||
MessageBox.Show(this, "Please select a valid WAD File resource.", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||
break;
|
||
|
||
case DataLocation.RESOURCE_PK3:
|
||
MessageBox.Show(this, "Please select a valid PK3, PKE, or PK7 File resource.", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||
break;
|
||
|
||
case DataLocation.RESOURCE_DIRECTORY:
|
||
MessageBox.Show(this, "Please select a valid directory resource.", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||
break;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
this.DialogResult = DialogResult.OK;
|
||
this.Close();
|
||
}
|
||
}
|
||
|
||
// Cancel clicked
|
||
private void cancel_Click(object sender, EventArgs e)
|
||
{
|
||
// Just hide
|
||
this.DialogResult = DialogResult.Cancel;
|
||
this.Close();
|
||
}
|
||
|
||
// Browse WAD File clicked
|
||
private void browsewad_Click(object sender, EventArgs e)
|
||
{
|
||
// Browse for WAD File
|
||
if(wadfiledialog.ShowDialog(this) == DialogResult.OK)
|
||
{
|
||
// Use this file
|
||
wadlocation.Text = wadfiledialog.FileName;
|
||
StartRequiredArchivesCheck();
|
||
}
|
||
}
|
||
|
||
// Browse Directory clicked
|
||
private void browsedir_Click(object sender, EventArgs e)
|
||
{
|
||
// Browse for Directory
|
||
dirdialog = new Controls.FolderSelectDialog();
|
||
dirdialog.Title = "Select Resource Folder";
|
||
|
||
if (string.IsNullOrEmpty(dirlocation.Text) || !Directory.Exists(dirlocation.Text))
|
||
{
|
||
//mxd
|
||
if (!string.IsNullOrEmpty(startPath))
|
||
{
|
||
string startDir = Path.GetDirectoryName(startPath);
|
||
if (Directory.Exists(startDir)) dirdialog.InitialDirectory = startDir + '\\';
|
||
}
|
||
}
|
||
else
|
||
{
|
||
dirdialog.InitialDirectory = dirlocation.Text;
|
||
}
|
||
|
||
if (dirdialog.ShowDialog(this.Handle))
|
||
{
|
||
// Use this directory
|
||
dirlocation.Text = dirdialog.FileName;
|
||
StartRequiredArchivesCheck();
|
||
dirdialog = null;
|
||
}
|
||
}
|
||
|
||
// Browse PK3 File clicked
|
||
private void browsepk3_Click(object sender, EventArgs e)
|
||
{
|
||
// Browse for PK3 File
|
||
if(pk3filedialog.ShowDialog(this) == DialogResult.OK)
|
||
{
|
||
// Use this file
|
||
pk3location.Text = pk3filedialog.FileName;
|
||
StartRequiredArchivesCheck();
|
||
}
|
||
}
|
||
|
||
// Link clicked
|
||
private void pk3_link_Click(object sender, LinkLabelLinkClickedEventArgs e)
|
||
{
|
||
General.OpenWebsite("http://www.zdoom.org/wiki/Using_ZIPs_as_WAD_replacement");
|
||
}
|
||
|
||
private void pke_link_Click(object sender, LinkLabelLinkClickedEventArgs e)
|
||
{
|
||
General.OpenWebsite("https://eternity.youfailit.net/wiki/ZIP");
|
||
}
|
||
|
||
// Help
|
||
private void ResourceOptionsForm_HelpRequested(object sender, HelpEventArgs hlpevent)
|
||
{
|
||
General.ShowHelp("w_resourceoptions.html");
|
||
hlpevent.Handled = true;
|
||
}
|
||
|
||
private void wadlocation_Enter(object sender, EventArgs e)
|
||
{
|
||
// Stop textbox control from getting focus
|
||
browsewad.Focus();
|
||
}
|
||
|
||
private void dirlocation_Enter(object sender, EventArgs e)
|
||
{
|
||
// Stop textbox control from getting focus
|
||
browsedir.Focus();
|
||
}
|
||
|
||
private void pk3location_Enter(object sender, EventArgs e)
|
||
{
|
||
// Stop textbox control from getting focus
|
||
browsepk3.Focus();
|
||
}
|
||
}
|
||
} |