Internal: moved script compilation logic to appropriate DataReaders.

This commit is contained in:
MaxED 2016-05-12 13:56:25 +00:00
parent b67ecc63ce
commit 65861d1e03
13 changed files with 566 additions and 501 deletions

View file

@ -17,12 +17,14 @@
#region ================== Namespaces
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using CodeImp.DoomBuilder.Config;
using System.Windows.Forms;
using System.Text.RegularExpressions;
using CodeImp.DoomBuilder.Data;
using CodeImp.DoomBuilder.ZDoom.Scripting;
#endregion
@ -37,9 +39,18 @@ namespace CodeImp.DoomBuilder.Compilers
#endregion
#region ================== Variables
private AcsParserSE parser; //mxd
#endregion
#region ================== Properties
public bool SourceIsMapScriptsLump; //mxd
internal AcsParserSE Parser { get { return parser; } } //mxd
#endregion
#region ================== Constructor
// Constructor
@ -71,31 +82,80 @@ namespace CodeImp.DoomBuilder.Compilers
int line = 0;
string sourcedir = Path.GetDirectoryName(sourcefile);
// Preprocess the file
parser = new AcsParserSE
{
OnInclude = delegate(AcsParserSE se, string includefile, AcsParserSE.IncludeType includetype)
{
TextResourceData data = General.Map.Data.GetTextResourceData(includefile);
if(data == null)
{
// Fial
ReportError(new CompilerError("Unable to find include file \"" + includefile + "\""));
}
else
{
se.Parse(data, true, includetype, false);
}
}
};
string inputfilepath = Path.Combine(this.tempdir.FullName, inputfile);
using(FileStream stream = File.OpenRead(inputfilepath))
{
DataLocation dl = new DataLocation(DataLocation.RESOURCE_DIRECTORY, Path.GetDirectoryName(inputfile), false, false, false);
TextResourceData data = new TextResourceData(stream, dl, inputfile, false);
if(!parser.Parse(data, info.Files, true, AcsParserSE.IncludeType.NONE, false))
{
// Check for errors
if(parser.HasError) ReportError(new CompilerError(parser.ErrorDescription, parser.ErrorSource, parser.ErrorLine));
return true;
}
}
//mxd. External lumps should be libraries
if(!SourceIsMapScriptsLump && !parser.IsLibrary)
{
ReportError(new CompilerError("External ACS files can only be compiled as libraries!", sourcefile));
return true;
}
//mxd. SCRIPTS lump can't be library
if(SourceIsMapScriptsLump && parser.IsLibrary)
{
ReportError(new CompilerError("SCRIPTS lump can't be compiled as library!", sourcefile));
return true;
}
//mxd. Update script names if we are compiling the map SCRIPTS lump
if(SourceIsMapScriptsLump)
{
General.Map.UpdateScriptNames(parser);
}
//xabis
// Copy includes from the resources into the compiler's folder, preserving relative pathing and naming
if(CopyIncludesToWorkingDirectory) //mxd
HashSet<string> includes = parser.GetIncludes(); //mxd
foreach(string include in includes)
{
foreach(string include in includes)
// Grab the script text from the resources
TextResourceData data = General.Map.Data.GetTextResourceData(include);
if(data != null && data.Stream != null)
{
// Grab the script text from the resources
TextResourceData data = General.Map.Data.GetTextResourceData(include);
if(data != null && data.Stream != null)
// Pull the pk3 or directory sub folder out if applicable
FileInfo fi = new FileInfo(Path.Combine(this.tempdir.FullName, include));
// Do not allow files to be overwritten, either accidentally or maliciously
if(!fi.Exists)
{
// Pull the pk3 or directory sub folder out if applicable
FileInfo fi = new FileInfo(Path.Combine(this.tempdir.FullName, include));
General.WriteLogLine("Copying script include: " + include);
// Do not allow files to be overwritten, either accidentally or maliciously
if(!fi.Exists)
{
General.WriteLogLine("Copying script include: " + include);
// Create the directory path as needed
if(!string.IsNullOrEmpty(fi.DirectoryName)) Directory.CreateDirectory(fi.DirectoryName);
// Create the directory path as needed
if(!string.IsNullOrEmpty(fi.DirectoryName)) Directory.CreateDirectory(fi.DirectoryName);
// Dump the script into the target file
BinaryReader reader = new BinaryReader(data.Stream);
File.WriteAllBytes(fi.FullName, reader.ReadBytes((int)data.Stream.Length));
}
// Dump the script into the target file
BinaryReader reader = new BinaryReader(data.Stream);
File.WriteAllBytes(fi.FullName, reader.ReadBytes((int)data.Stream.Length));
}
}
}
@ -112,7 +172,6 @@ namespace CodeImp.DoomBuilder.Compilers
// Setup process info
ProcessStartInfo processinfo = new ProcessStartInfo();
processinfo.Arguments = args;
//processinfo.FileName = Path.Combine(this.tempdir.FullName, info.ProgramFile);
processinfo.FileName = Path.Combine(info.Path, info.ProgramFile); //mxd
processinfo.CreateNoWindow = false;
processinfo.ErrorDialog = false;
@ -228,5 +287,4 @@ namespace CodeImp.DoomBuilder.Compilers
#endregion
}
}
}

View file

@ -24,7 +24,6 @@ using System.Reflection;
using System.IO;
using CodeImp.DoomBuilder.Config;
#endregion
namespace CodeImp.DoomBuilder.Compilers
@ -40,7 +39,6 @@ namespace CodeImp.DoomBuilder.Compilers
protected string sourcefile;
protected string outputfile;
protected string inputfile;
protected HashSet<string> includes; //mxd
// Files
protected readonly DirectoryInfo tempdir;
@ -61,8 +59,6 @@ namespace CodeImp.DoomBuilder.Compilers
public string InputFile { get { return inputfile; } set { inputfile = value; } }
public string OutputFile { get { return outputfile; } set { outputfile = value; } }
public string Location { get { return tempdir.FullName; } }
public HashSet<string> Includes { get { return includes; } set { includes = value; } } //mxd
public bool CopyIncludesToWorkingDirectory; //mxd
public bool IsDisposed { get { return isdisposed; } }
public CompilerError[] Errors { get { return errors.ToArray(); } }
@ -76,7 +72,6 @@ namespace CodeImp.DoomBuilder.Compilers
// Initialize
this.info = info;
this.errors = new List<CompilerError>();
this.includes = new HashSet<string>(StringComparer.OrdinalIgnoreCase); //mxd
General.WriteLogLine("Creating compiler \"" + info.Name + "\" on interface \"" + this.GetType().Name + "\"...");

View file

@ -207,7 +207,7 @@ namespace CodeImp.DoomBuilder.Controls
config = newconfig; //mxd
editor.SetupStyles(newconfig); //mxd
List<CompilerError> errors = UpdateNavigator(); //mxd
if(panel.ActiveTab == this) panel.ShowErrors(errors); //mxd
if(panel.ActiveTab == this) panel.ShowErrors(errors, true); //mxd
}
// Call this to set the tab title
@ -296,7 +296,7 @@ namespace CodeImp.DoomBuilder.Controls
}
if(parser.HasError)
panel.ShowErrors(new List<CompilerError> { new CompilerError(parser.ErrorDescription, parser.ErrorSource, parser.ErrorLine) });
panel.ShowErrors(new List<CompilerError> { new CompilerError(parser.ErrorDescription, parser.ErrorSource, parser.ErrorLine) }, true);
return ScriptType.UNKNOWN;
}
@ -436,7 +436,7 @@ namespace CodeImp.DoomBuilder.Controls
//mxd
private void functionbar_DropDown(object sender, EventArgs e)
{
if(editor.IsChanged) panel.ShowErrors(UpdateNavigator());
if(editor.IsChanged) panel.ShowErrors(UpdateNavigator(), true);
}
//mxd

View file

@ -121,8 +121,15 @@ namespace CodeImp.DoomBuilder.Controls
// Is this a script lump?
if(maplumpinfo.ScriptBuild) //mxd
{
ScriptConfiguration config = General.GetScriptConfiguration(ScriptType.ACS);
if(config == null)
{
General.ErrorLogger.Add(ErrorType.Warning, "Unable to find script configuration for \"" + ScriptType.ACS + "\" script type. Using plain text configuration.");
config = new ScriptConfiguration();
}
// Load this!
ScriptLumpDocumentTab t = new ScriptLumpDocumentTab(this, maplumpinfo.Name, General.CompiledScriptConfigs[General.Map.Options.ScriptCompiler]);
ScriptLumpDocumentTab t = new ScriptLumpDocumentTab(this, maplumpinfo.Name, config);
//mxd. Apply stored settings?
if(General.Map.Options.ScriptLumpSettings.ContainsKey(maplumpinfo.Name))
@ -198,7 +205,7 @@ namespace CodeImp.DoomBuilder.Controls
if(activetab != null)
{
List<CompilerError> errors = (General.Map.Errors.Count > 0 ? General.Map.Errors : activetab.UpdateNavigator());
if(errors.Count > 0) ShowErrors(errors);
if(errors.Count > 0) ShowErrors(errors, false);
else ClearErrors();
}
else
@ -421,13 +428,35 @@ namespace CodeImp.DoomBuilder.Controls
// This shows the errors panel with the given errors
// Also updates the scripts with markers for the given errors
public void ShowErrors(IEnumerable<CompilerError> errors)
public void ShowErrors(IEnumerable<CompilerError> errors, bool combine)
{
// Copy list
if(errors != null)
compilererrors = new List<CompilerError>(errors);
if(combine) //mxd
{
if(compilererrors == null) compilererrors = new List<CompilerError>();
if(errors != null)
{
// Combine 2 error lists...
foreach(CompilerError err in errors)
{
bool alreadyadded = false;
foreach(CompilerError compilererror in compilererrors)
{
if(compilererror.Equals(err))
{
alreadyadded = true;
break;
}
}
if(!alreadyadded) compilererrors.Add(err);
}
}
}
else
compilererrors = new List<CompilerError>();
{
compilererrors = (errors != null ? new List<CompilerError>(errors) : new List<CompilerError>());
}
// Fill list
errorlist.BeginUpdate();
@ -991,26 +1020,8 @@ namespace CodeImp.DoomBuilder.Controls
ScriptDocumentTab tab = e.TabPage as ScriptDocumentTab;
if(tab != null)
{
List<CompilerError> errors = tab.UpdateNavigator();
// Combine 2 error lists...
foreach(CompilerError navigatorerror in errors)
{
bool alreadyadded = false;
foreach(CompilerError compilererror in compilererrors)
{
if(compilererror.Equals(navigatorerror))
{
alreadyadded = true;
break;
}
}
if(!alreadyadded) compilererrors.Add(navigatorerror);
}
// Show all errors...
ShowErrors(compilererrors);
ShowErrors(tab.UpdateNavigator(), true);
}
UpdateToolbar(true);

View file

@ -23,7 +23,6 @@ using System.Windows.Forms;
using CodeImp.DoomBuilder.Compilers;
using CodeImp.DoomBuilder.Config;
using CodeImp.DoomBuilder.Data;
using CodeImp.DoomBuilder.ZDoom.Scripting;
#endregion
@ -69,214 +68,16 @@ namespace CodeImp.DoomBuilder.Controls
// This compiles the script file
public override void Compile()
{
//mxd. ACS requires special handling...
if(config.ScriptType == ScriptType.ACS)
{
CompileACS();
return;
}
Compiler compiler;
//mxd. Compile
List<CompilerError> errors = new List<CompilerError>();
try
if(DirectoryReader.CompileScriptLump(filepathname, config, errors))
{
// Initialize compiler
compiler = config.Compiler.Create();
//mxd. Update script navigator
errors.AddRange(UpdateNavigator());
}
catch(Exception e)
{
// Fail
errors.Add(new CompilerError("Unable to initialize compiler. " + e.GetType().Name + ": " + e.Message));
panel.ShowErrors(errors); //mxd
return;
}
// Copy the source file into the temporary directory
string inputfile = Path.Combine(compiler.Location, Path.GetFileName(filepathname));
File.Copy(filepathname, inputfile);
// Make random output filename
string outputfile = General.MakeTempFilename(compiler.Location, "tmp");
// Run compiler
compiler.Parameters = config.Parameters;
compiler.InputFile = Path.GetFileName(inputfile);
compiler.OutputFile = Path.GetFileName(outputfile);
compiler.SourceFile = filepathname;
compiler.WorkingDirectory = Path.GetDirectoryName(inputfile);
if(compiler.Run())
{
// Fetch errors
foreach(CompilerError e in compiler.Errors)
{
CompilerError newerr = e;
// If the error's filename equals our temporary file,
// replace it with the original source filename
if(string.Compare(e.filename, inputfile, true) == 0)
newerr.filename = filepathname;
errors.Add(newerr);
}
}
// Dispose compiler
compiler.Dispose();
//mxd. Update script navigator
errors.AddRange(UpdateNavigator());
// Feed errors to panel
panel.ShowErrors(errors);
}
//mxd. ACS requires special handling...
private void CompileACS()
{
Compiler compiler;
List<CompilerError> errors = new List<CompilerError>();
string inputfile = Path.GetFileName(filepathname);
// Which compiler to use?
ScriptConfiguration scriptconfig;
if(!string.IsNullOrEmpty(General.Map.Options.ScriptCompiler))
{
// Boilderplate
if(!General.CompiledScriptConfigs.ContainsKey(General.Map.Options.ScriptCompiler))
{
General.ShowErrorMessage("Unable to compile \"" + inputfile + "\". Unable to find required script compiler configuration (\"" + General.Map.Options.ScriptCompiler + "\").", MessageBoxButtons.OK);
return;
}
scriptconfig = General.CompiledScriptConfigs[General.Map.Options.ScriptCompiler];
}
else
{
scriptconfig = config;
}
// Initialize compiler
try
{
compiler = scriptconfig.Compiler.Create();
}
catch(Exception e)
{
// Fail
errors.Add(new CompilerError("Unable to initialize compiler. " + e.GetType().Name + ": " + e.Message));
panel.ShowErrors(errors);
return;
}
// Preprocess the file
AcsParserSE parser = new AcsParserSE
{
OnInclude = delegate(AcsParserSE se, string includefile, AcsParserSE.IncludeType includetype)
{
TextResourceData data = General.Map.Data.GetTextResourceData(includefile);
if(data == null)
{
// Fial
errors.Add(new CompilerError("Unable to find include file \"" + includefile + "\""));
panel.ShowErrors(errors);
}
else
{
se.Parse(data, true, includetype, false);
}
}
};
using(FileStream stream = File.OpenRead(filepathname))
{
TextResourceData data = new TextResourceData(stream, new DataLocation(), filepathname, false);
if(!parser.Parse(data, scriptconfig.Compiler.Files, true, AcsParserSE.IncludeType.NONE, false))
{
// Check for errors
if(parser.HasError)
{
errors.Add(new CompilerError(parser.ErrorDescription, parser.ErrorSource, parser.ErrorLine));
panel.ShowErrors(errors);
}
compiler.Dispose();
return;
}
}
//mxd. Only works for libraries
if(!parser.IsLibrary)
{
errors.Add(new CompilerError("External ACS files can only be compiled as libraries!", filepathname));
panel.ShowErrors(errors);
compiler.Dispose();
return;
}
// Make random output filename
string outputfile = General.MakeTempFilename(compiler.Location, "tmp");
// Run compiler
compiler.Parameters = config.Parameters;
compiler.InputFile = inputfile;
compiler.OutputFile = outputfile;
compiler.SourceFile = filepathname;
compiler.WorkingDirectory = Path.GetDirectoryName(filepathname);
compiler.Includes = parser.GetIncludes();
compiler.CopyIncludesToWorkingDirectory = false;
if(compiler.Run())
{
// Fetch errors
foreach(CompilerError e in compiler.Errors)
{
CompilerError newerr = e;
// If the error's filename equals our temporary file,
// replace it with the original source filename
if(string.Compare(e.filename, inputfile, true) == 0)
newerr.filename = filepathname;
errors.Add(newerr);
}
// No errors and output file exists?
if(compiler.Errors.Length == 0)
{
// Output file exists?
if(!File.Exists(outputfile))
{
// Fail
compiler.Dispose();
errors.Add(new CompilerError("Output file \"" + outputfile + "\" doesn't exist."));
panel.ShowErrors(errors);
return;
}
// Rename and copy to source file directory
string targetfilename = Path.Combine(Path.GetDirectoryName(filepathname), parser.LibraryName + ".o");
try
{
File.Copy(outputfile, targetfilename, true);
}
catch(Exception e)
{
// Fail
compiler.Dispose();
errors.Add(new CompilerError("Unable to create library file \"" + targetfilename + "\". " + e.GetType().Name + ": " + e.Message));
panel.ShowErrors(errors);
return;
}
}
}
// Dispose compiler
compiler.Dispose();
// Update script navigator
errors.AddRange(UpdateNavigator());
// Feed errors to panel
panel.ShowErrors(errors);
panel.ShowErrors(errors, false);
}
// This checks if a script error applies to this script
@ -348,7 +149,7 @@ namespace CodeImp.DoomBuilder.Controls
this.filepathname = filepathname;
editor.ClearUndoRedo();
SetTitle(Path.GetFileName(filepathname));
panel.ShowErrors(UpdateNavigator()); //mxd
panel.ShowErrors(UpdateNavigator(), true); //mxd
return true;
}

View file

@ -18,6 +18,7 @@
using System.Collections.Generic;
using System.IO;
using System.Windows.Forms;
using CodeImp.DoomBuilder.Compilers;
using CodeImp.DoomBuilder.Config;
@ -84,25 +85,23 @@ namespace CodeImp.DoomBuilder.Controls
// Compile script
public override void Compile()
{
//mxd. List of errors. UpdateScriptNames can return errors and also updates acs includes list
List<CompilerError> errors = (config.ScriptType == ScriptType.ACS ? General.Map.UpdateScriptNames(false) : new List<CompilerError>());
//mxd. Errors already?..
if(errors.Count > 0)
//mxd. Boilerplate
if(!General.Map.Config.MapLumps.ContainsKey(lumpname))
{
// Feed errors to panel
panel.ShowErrors(errors);
General.ShowErrorMessage("Unable to compile lump \"" + lumpname + "\". This lump is not defined in the current game configuration.", MessageBoxButtons.OK);
return;
}
// Compile
General.Map.CompileLump((ismapheader ? MapManager.CONFIG_MAP_HEADER : lumpname), true);
//mxd. Update script navigator
errors = UpdateNavigator();
List<CompilerError> errors = new List<CompilerError>();
if(General.Map.TemporaryMapFile.CompileLump((ismapheader ? MapManager.CONFIG_MAP_HEADER : lumpname), config, errors))
{
//mxd. Update script navigator
errors.AddRange(UpdateNavigator());
}
// Feed errors to panel
panel.ShowErrors(General.Map.Errors.Count > 0 ? General.Map.Errors : errors);
panel.ShowErrors(errors, false);
}
// Implicit save

View file

@ -275,8 +275,8 @@ namespace CodeImp.DoomBuilder.Data
#region ================== Compiling (mxd)
internal abstract bool CompileLump(string lumpname, out List<CompilerError> errors);
internal abstract bool CompileLump(string lumpname, int lumpindex, out List<CompilerError> errors);
internal abstract bool CompileLump(string lumpname, ScriptConfiguration scriptconfig, List<CompilerError> errors);
internal abstract bool CompileLump(string lumpname, int lumpindex, ScriptConfiguration scriptconfig, List<CompilerError> errors);
#endregion
}

View file

@ -20,6 +20,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using CodeImp.DoomBuilder.Compilers;
using CodeImp.DoomBuilder.Config;
using CodeImp.DoomBuilder.IO;
#endregion
@ -513,10 +514,111 @@ namespace CodeImp.DoomBuilder.Data
// This compiles a script lump and returns any errors that may have occurred
// Returns true when our code worked properly (even when the compiler returned errors)
internal override bool CompileLump(string filename, int unused, out List<CompilerError> errors) { return CompileLump(filename, out errors); }
internal override bool CompileLump(string lumpname, out List<CompilerError> errors)
internal override bool CompileLump(string filepathname, int unused, ScriptConfiguration scriptconfig, List<CompilerError> errors) { return CompileLump(filepathname, scriptconfig, errors); }
internal override bool CompileLump(string filepathname, ScriptConfiguration scriptconfig, List<CompilerError> errors)
{
throw new NotImplementedException();
return CompileScriptLump(filepathname, scriptconfig, errors);
}
internal static bool CompileScriptLump(string filepathname, ScriptConfiguration scriptconfig, List<CompilerError> errors)
{
// No compiling required
if(scriptconfig.Compiler == null) return true;
// Initialize compiler
Compiler compiler;
try
{
compiler = scriptconfig.Compiler.Create();
}
catch(Exception e)
{
// Fail
errors.Add(new CompilerError("Unable to initialize compiler. " + e.GetType().Name + ": " + e.Message));
return false;
}
// Copy the source file into the temporary directory
string inputfile = Path.Combine(compiler.Location, Path.GetFileName(filepathname));
File.Copy(filepathname, inputfile);
// Make random output filename
string outputfile = General.MakeTempFilename(compiler.Location, "tmp");
// Run compiler
compiler.Parameters = scriptconfig.Parameters;
compiler.InputFile = inputfile;
compiler.OutputFile = Path.GetFileName(outputfile);
compiler.SourceFile = filepathname;
compiler.WorkingDirectory = Path.GetDirectoryName(inputfile);
if(compiler.Run())
{
// Fetch errors
foreach(CompilerError e in compiler.Errors)
{
CompilerError newerr = e;
// If the error's filename equals our temporary file, replace it with the original source filename
if(String.Compare(e.filename, inputfile, true) == 0) newerr.filename = filepathname;
errors.Add(newerr);
}
// No errors and output file exists?
if(compiler.Errors.Length == 0)
{
// Output file exists?
if(!File.Exists(outputfile))
{
// Fail
compiler.Dispose();
errors.Add(new CompilerError("Output file \"" + outputfile + "\" doesn't exist."));
return false;
}
//mxd. Move and rename the result file
string targetfilename;
if(compiler is AccCompiler)
{
AccCompiler acccompiler = (AccCompiler)compiler;
targetfilename = Path.Combine(Path.GetDirectoryName(filepathname), acccompiler.Parser.LibraryName + ".o");
}
else
{
//mxd. No can't do...
if(String.IsNullOrEmpty(scriptconfig.ResultLump))
{
// Fail
compiler.Dispose();
errors.Add(new CompilerError("Unable to create target file: unable to determine target filename. Make sure \"ResultLump\" property is set in the \"" + scriptconfig + "\" script configuration."));
return false;
}
targetfilename = Path.Combine(Path.GetDirectoryName(filepathname), scriptconfig.ResultLump);
}
// Rename and copy to source file directory
try
{
File.Copy(outputfile, targetfilename, true);
}
catch(Exception e)
{
// Fail
compiler.Dispose();
errors.Add(new CompilerError("Unable to create library file \"" + targetfilename + "\". " + e.GetType().Name + ": " + e.Message));
return false;
}
}
// Done
compiler.Dispose();
return true;
}
// Fail
compiler.Dispose();
return false;
}
#endregion

View file

@ -20,6 +20,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using CodeImp.DoomBuilder.Compilers;
using CodeImp.DoomBuilder.Config;
using CodeImp.DoomBuilder.IO;
using SharpCompress.Archive; //mxd
using SharpCompress.Archive.Zip;
@ -580,10 +581,114 @@ namespace CodeImp.DoomBuilder.Data
// This compiles a script lump and returns any errors that may have occurred
// Returns true when our code worked properly (even when the compiler returned errors)
internal override bool CompileLump(string filename, int unused, out List<CompilerError> errors) { return CompileLump(filename, out errors); }
internal override bool CompileLump(string filename, out List<CompilerError> errors)
internal override bool CompileLump(string filename, int unused, ScriptConfiguration scriptconfig, List<CompilerError> errors) { return CompileLump(filename, scriptconfig, errors); }
internal override bool CompileLump(string filename, ScriptConfiguration scriptconfig, List<CompilerError> errors)
{
throw new NotImplementedException();
// No compiling required
if(scriptconfig.Compiler == null) return true;
// Initialize compiler
Compiler compiler;
try
{
compiler = scriptconfig.Compiler.Create();
}
catch(Exception e)
{
// Fail
errors.Add(new CompilerError("Unable to initialize compiler. " + e.GetType().Name + ": " + e.Message));
return false;
}
// Extract the source file into the temporary directory
string inputfile = Path.Combine(compiler.Location, Path.GetFileName(filename));
using(MemoryStream stream = LoadFile(filename))
{
File.WriteAllBytes(inputfile, stream.ToArray());
}
// Make random output filename
string outputfile = General.MakeTempFilename(compiler.Location, "tmp");
// Run compiler
compiler.Parameters = scriptconfig.Parameters;
compiler.InputFile = inputfile;
compiler.OutputFile = Path.GetFileName(outputfile);
compiler.SourceFile = inputfile;
compiler.WorkingDirectory = Path.GetDirectoryName(inputfile);
if(compiler.Run())
{
// Fetch errors
foreach(CompilerError e in compiler.Errors)
{
CompilerError newerr = e;
// If the error's filename equals our temporary file, // replace it with the original source filename
if(String.Compare(e.filename, inputfile, true) == 0) newerr.filename = filename;
errors.Add(newerr);
}
// No errors and output file exists?
if(compiler.Errors.Length == 0)
{
// Output file exists?
if(!File.Exists(outputfile))
{
// Fail
compiler.Dispose();
errors.Add(new CompilerError("Output file \"" + outputfile + "\" doesn't exist."));
return false;
}
//mxd. Move and rename the result file
string targetfilename;
if(compiler is AccCompiler)
{
AccCompiler acccompiler = (AccCompiler)compiler;
targetfilename = Path.Combine(Path.GetDirectoryName(filename), acccompiler.Parser.LibraryName + ".o");
}
else
{
//mxd. No can't do...
if(String.IsNullOrEmpty(scriptconfig.ResultLump))
{
// Fail
compiler.Dispose();
errors.Add(new CompilerError("Unable to create target file: unable to determine target filename. Make sure \"ResultLump\" property is set in the \"" + scriptconfig + "\" script configuration."));
return false;
}
targetfilename = Path.Combine(Path.GetDirectoryName(filename), scriptconfig.ResultLump);
}
// Rename and add to source archive
try
{
byte[] buffer = File.ReadAllBytes(outputfile);
using(MemoryStream stream = new MemoryStream(buffer.Length))
{
stream.Write(buffer, 0, buffer.Length);
SaveFile(stream, targetfilename);
}
}
catch(Exception e)
{
// Fail
compiler.Dispose();
errors.Add(new CompilerError("Unable to create library file \"" + targetfilename + "\". " + e.GetType().Name + ": " + e.Message));
return false;
}
}
// Done
compiler.Dispose();
return true;
}
// Fail
compiler.Dispose();
return false;
}
#endregion

View file

@ -25,7 +25,8 @@ namespace CodeImp.DoomBuilder.Data.Scripting
target.Items.Clear();
AcsParserSE parser = new AcsParserSE { AddArgumentsToScriptNames = true, IsMapScriptsLump = tab is ScriptLumpDocumentTab, IgnoreErrors = true };
TextResourceData data = new TextResourceData(stream, new DataLocation(), (parser.IsMapScriptsLump ? "?SCRIPTS" : tab.Filename), false);
DataLocation dl = new DataLocation(DataLocation.RESOURCE_DIRECTORY, Path.GetDirectoryName(tab.Filename), false, false, false);
TextResourceData data = new TextResourceData(stream, dl, (parser.IsMapScriptsLump ? "?SCRIPTS" : tab.Filename), false);
if(parser.Parse(data, false))
{

View file

@ -22,6 +22,7 @@ using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using CodeImp.DoomBuilder.Compilers;
using CodeImp.DoomBuilder.Config;
using CodeImp.DoomBuilder.GZBuilder.Data;
using CodeImp.DoomBuilder.IO;
using CodeImp.DoomBuilder.ZDoom;
@ -1191,30 +1192,139 @@ namespace CodeImp.DoomBuilder.Data
// This compiles a script lump and returns any errors that may have occurred
// Returns true when our code worked properly (even when the compiler returned errors)
internal override bool CompileLump(string lumpname, out List<CompilerError> errors)
internal override bool CompileLump(string lumpname, ScriptConfiguration scriptconfig, List<CompilerError> errors)
{
int index = file.FindLumpIndex(lumpname);
if(index == -1)
{
errors = new List<CompilerError>
{
new CompilerError
{
description = "Lump \"" + lumpname + "\" does not exist",
filename = this.location.GetDisplayName()
}
};
errors.Add(new CompilerError { description = "Lump \"" + lumpname + "\" does not exist", filename = this.location.GetDisplayName() });
return false;
}
return CompileLump(lumpname, index, out errors);
return CompileLump(lumpname, index, scriptconfig, errors);
}
// This compiles a script lump and returns any errors that may have occurred
// Returns true when our code worked properly (even when the compiler returned errors)
internal override bool CompileLump(string lumpname, int lumpindex, out List<CompilerError> errors)
internal override bool CompileLump(string lumpname, int lumpindex, ScriptConfiguration scriptconfig, List<CompilerError> errors)
{
throw new NotImplementedException();
// No compiling required
if(scriptconfig.Compiler == null) return true;
string inputfile;
Compiler compiler;
string reallumpname = lumpname;
// Find the lump
if(lumpname == MapManager.CONFIG_MAP_HEADER) reallumpname = MapManager.TEMP_MAP_HEADER;
Lump lump = file.FindLump(reallumpname);
if(lump == null)
throw new Exception("Unable to find lump \"" + reallumpname + "\" to compile in \"" + location.GetDisplayName() + "\".");
// Determine source file
string sourcefile = (General.Map.FilePathName.Length > 0 ? General.Map.FilePathName : file.Filename);
// Initialize compiler
try
{
compiler = scriptconfig.Compiler.Create();
}
catch(Exception e)
{
// Fail
errors.Add(new CompilerError("Unable to initialize compiler. " + e.GetType().Name + ": " + e.Message));
return false;
}
try
{
// Write lump data to temp script file in compiler's temp directory
inputfile = General.MakeTempFilename(compiler.Location, "tmp");
lump.Stream.Seek(0, SeekOrigin.Begin);
BinaryReader reader = new BinaryReader(lump.Stream);
File.WriteAllBytes(inputfile, reader.ReadBytes((int)lump.Stream.Length));
}
catch(Exception e)
{
// Fail
compiler.Dispose();
errors.Add(new CompilerError("Unable to write script to working file. " + e.GetType().Name + ": " + e.Message));
return false;
}
// Make random output filename
string outputfile = General.MakeTempFilename(compiler.Location, "tmp");
// Run compiler
compiler.Parameters = scriptconfig.Parameters;
compiler.InputFile = Path.GetFileName(inputfile);
compiler.OutputFile = Path.GetFileName(outputfile);
compiler.SourceFile = sourcefile;
compiler.WorkingDirectory = Path.GetDirectoryName(inputfile);
//mxd. AccCompiler requires some additional settings...
if(scriptconfig.ScriptType == ScriptType.ACS)
{
AccCompiler acccompiler = compiler as AccCompiler;
if(acccompiler != null)
{
acccompiler.SourceIsMapScriptsLump = (this == General.Map.TemporaryMapFile && lumpname == "SCRIPTS");
}
}
if(compiler.Run())
{
// Process errors
foreach(CompilerError e in compiler.Errors)
{
CompilerError newerror = e;
// If the error's filename equals our temporary file, use the lump name instead and prefix it with ?
if(string.Compare(e.filename, inputfile, true) == 0) newerror.filename = "?" + reallumpname;
errors.Add(newerror);
}
// No errors?
if(compiler.Errors.Length == 0)
{
// Output file exists?
if(File.Exists(outputfile))
{
// Copy output file data into a lump?
if(!string.IsNullOrEmpty(scriptconfig.ResultLump))
{
// Do that now then
byte[] filedata;
try
{
filedata = File.ReadAllBytes(outputfile);
}
catch(Exception e)
{
// Fail
compiler.Dispose();
errors.Add(new CompilerError("Unable to read compiler output file. " + e.GetType().Name + ": " + e.Message));
return false;
}
// Store data
SaveFile(new MemoryStream(filedata), scriptconfig.ResultLump);
}
}
}
// Clean up
compiler.Dispose();
// Done
return true;
}
// Fail
compiler.Dispose();
return false;
}
#endregion

View file

@ -2075,6 +2075,30 @@ namespace CodeImp.DoomBuilder
GetShortPathName(longpath, shortname, maxlen);
return shortname.ToString();
}
//mxd
internal static ScriptConfiguration GetScriptConfiguration(ScriptType type)
{
if(type == ScriptType.ACS)
{
// Return map-defined compiler
string compiler = (!string.IsNullOrEmpty(Map.Options.ScriptCompiler) ? Map.Options.ScriptCompiler : Map.ConfigSettings.DefaultScriptCompiler);
foreach(KeyValuePair<string, ScriptConfiguration> group in scriptconfigs)
{
if(group.Key == compiler) return group.Value;
}
}
else
{
// Just pick the first one from the list
foreach(ScriptConfiguration cfg in scriptconfigs.Values)
{
if(cfg.ScriptType == type) return cfg;
}
}
return null;
}
#endregion

View file

@ -88,7 +88,6 @@ namespace CodeImp.DoomBuilder
//mxd
private Dictionary<string, ScriptItem> namedscripts;
private Dictionary<int, ScriptItem> numberedscripts;
private readonly HashSet<string> scriptincludes;
// Disposing
private bool isdisposed;
@ -161,7 +160,6 @@ namespace CodeImp.DoomBuilder
//mxd
numberedscripts = new Dictionary<int, ScriptItem>();
namedscripts = new Dictionary<string, ScriptItem>(StringComparer.OrdinalIgnoreCase);
scriptincludes = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
}
// Disposer
@ -275,6 +273,19 @@ namespace CodeImp.DoomBuilder
configinfo.ApplyDefaults(config);
General.Editing.UpdateCurrentEditModes();
//mxd. Check if default script compiler is required
if(string.IsNullOrEmpty(configinfo.DefaultScriptCompiler))
{
foreach(MapLumpInfo info in config.MapLumps.Values)
{
if(info.ScriptBuild)
{
General.ErrorLogger.Add(ErrorType.Error, "\"DefaultScriptCompiler\" property is not set in \"" + configinfo + "\" game configuration. The editor may fail to compile ACC scripts.");
break;
}
}
}
// Create map data
map = new MapSet();
@ -425,8 +436,8 @@ namespace CodeImp.DoomBuilder
map.Update();
thingsfilter.Update();
//mxd. Update includes list and script names
UpdateScriptNames(true);
//mxd. Update script names
UpdateScriptNames();
//mxd. Restore selection groups
options.ReadSelectionGroups();
@ -517,8 +528,8 @@ namespace CodeImp.DoomBuilder
// Skybox may've been changed
data.SetupSkybox();
// Update includes list and script names
UpdateScriptNames(true);
// Update script names
UpdateScriptNames();
// Restore selection groups
options.ReadSelectionGroups();
@ -752,7 +763,7 @@ namespace CodeImp.DoomBuilder
// Show script window if there are any errors and we are going to test the map
// and always update the errors on the scripts window.
if((errors.Count > 0) && (scriptwindow == null) && (purpose == SavePurpose.Testing)) ShowScriptEditor();
if(scriptwindow != null) scriptwindow.Editor.ShowErrors(errors);
if(scriptwindow != null) scriptwindow.Editor.ShowErrors(errors, false);
// Only write the map and rebuild nodes when the actual map has changed
// (not when only scripts have changed)
@ -1960,179 +1971,19 @@ namespace CodeImp.DoomBuilder
if(lumpinfo.Script != null || lumpinfo.ScriptBuild)
{
// Compile it now
success &= CompileLump(lumpinfo.Name, false);
success &= tempwadreader.CompileLump(lumpinfo.Name, lumpinfo.Script, errors);
}
}
return success;
}
// This compiles a script lump and returns any errors that may have occurred
// Returns true when our code worked properly (even when the compiler returned errors)
internal bool CompileLump(string lumpname, bool clearerrors)
//mxd. Update script numbers and names
private void UpdateScriptNames()
{
//mxd. Boilerplate
if(!config.MapLumps.ContainsKey(lumpname))
{
General.ShowErrorMessage("Unable to compile lump \"" + lumpname + "\". This lump is not defined in the current game configuration.", MessageBoxButtons.OK);
return false;
}
string inputfile;
Compiler compiler;
string reallumpname = lumpname;
//mxd. Does lump require compiling?
ScriptConfiguration scriptconfig;
if(config.MapLumps[lumpname].ScriptBuild)
{
//mxd. More boilderplate
if(!General.CompiledScriptConfigs.ContainsKey(General.Map.Options.ScriptCompiler))
{
General.ShowErrorMessage("Unable to compile lump \"" + lumpname + "\". Unable to find required script compiler configuration (\"" + General.Map.Options.ScriptCompiler + "\").", MessageBoxButtons.OK);
return false;
}
scriptconfig = General.CompiledScriptConfigs[General.Map.Options.ScriptCompiler];
}
else
{
scriptconfig = config.MapLumps[lumpname].Script;
}
if(scriptconfig.Compiler == null) return true;
// Find the lump
if(lumpname == CONFIG_MAP_HEADER) reallumpname = TEMP_MAP_HEADER;
Lump lump = tempwadreader.WadFile.FindLump(reallumpname);
if(lump == null) throw new Exception("No such lump in temporary wad file \"" + reallumpname + "\".");
// Determine source file
string sourcefile = (filepathname.Length > 0 ? filepathname : tempwadreader.WadFile.Filename);
// New list of errors
if(clearerrors) errors.Clear();
// Determine the script configuration to use
try
{
// Initialize compiler
compiler = scriptconfig.Compiler.Create();
}
catch(Exception e)
{
// Fail
errors.Add(new CompilerError("Unable to initialize compiler. " + e.GetType().Name + ": " + e.Message));
return false;
}
try
{
// Write lump data to temp script file in compiler's temp directory
inputfile = General.MakeTempFilename(compiler.Location, "tmp");
lump.Stream.Seek(0, SeekOrigin.Begin);
BinaryReader reader = new BinaryReader(lump.Stream);
File.WriteAllBytes(inputfile, reader.ReadBytes((int)lump.Stream.Length));
}
catch(Exception e)
{
// Fail
compiler.Dispose();
errors.Add(new CompilerError("Unable to write script to working file. " + e.GetType().Name + ": " + e.Message));
return false;
}
// Make random output filename
string outputfile = General.MakeTempFilename(compiler.Location, "tmp");
// Run compiler
compiler.Parameters = scriptconfig.Parameters;
compiler.InputFile = Path.GetFileName(inputfile);
compiler.OutputFile = Path.GetFileName(outputfile);
compiler.SourceFile = sourcefile;
compiler.WorkingDirectory = Path.GetDirectoryName(inputfile);
//mxd
if(scriptconfig.ScriptType == ScriptType.ACS)
{
compiler.Includes = scriptincludes;
compiler.CopyIncludesToWorkingDirectory = true;
}
if(compiler.Run())
{
// Process errors
foreach(CompilerError e in compiler.Errors)
{
CompilerError newerror = e;
// If the error's filename equals our temporary file,
// use the lump name instead and prefix it with ?
if(string.Compare(e.filename, inputfile, true) == 0)
newerror.filename = "?" + reallumpname;
errors.Add(newerror);
}
// No errors?
if(compiler.Errors.Length == 0)
{
// Output file exists?
if(File.Exists(outputfile))
{
// Copy output file data into a lump?
if(!string.IsNullOrEmpty(scriptconfig.ResultLump))
{
// Do that now then
byte[] filedata;
try
{
filedata = File.ReadAllBytes(outputfile);
}
catch(Exception e)
{
// Fail
compiler.Dispose();
errors.Add(new CompilerError("Unable to read compiler output file. " + e.GetType().Name + ": " + e.Message));
return false;
}
// Store data
MemoryStream stream = new MemoryStream(filedata);
SetLumpData(scriptconfig.ResultLump, stream);
}
}
}
// Clean up
compiler.Dispose();
// Done
return true;
}
// Fail
compiler.Dispose();
errors.Clear(); //mxd
return false;
}
// This clears all compiler errors
/*internal void ClearCompilerErrors()
{
errors.Clear();
}*/
//mxd. Update includes list and script names
internal List<CompilerError> UpdateScriptNames(bool logerrors)
{
List<ScriptItem> namedscriptslist = new List<ScriptItem>();
List<ScriptItem> numberedscriptslist = new List<ScriptItem>();
List<string> scripincludeslist = new List<string>();
List<CompilerError> compilererrors = new List<CompilerError>();
General.Map.Data.TextResources[ScriptType.ACS] = new HashSet<TextResource>();
// Load the script lumps
// Find SCRIPTS lump and parse it
foreach(MapLumpInfo maplumpinfo in config.MapLumps.Values)
{
// Is this a script lump?
@ -2147,9 +1998,9 @@ namespace CodeImp.DoomBuilder
string error = "Unable to compile lump \"" + maplumpinfo.Name +
"\". Unable to find required script compiler configuration (\"" +
General.Map.Options.ScriptCompiler + "\").";
compilererrors.Add(new CompilerError(error));
if(logerrors) General.ErrorLogger.Add(ErrorType.Error, error);
return compilererrors;
General.ErrorLogger.Add(ErrorType.Error, error);
return;
}
scriptconfig = General.CompiledScriptConfigs[General.Map.Options.ScriptCompiler];
@ -2161,7 +2012,7 @@ namespace CodeImp.DoomBuilder
// Load the lump data
MemoryStream stream = GetLumpData(maplumpinfo.Name);
if(stream != null && stream.Length > 0 && scriptconfig != null && scriptconfig.Compiler != null)
if(stream != null && stream.Length > 0 && scriptconfig != null && scriptconfig.Compiler != null && scriptconfig.ScriptType == ScriptType.ACS)
{
// Get script names
AcsParserSE parser = new AcsParserSE
@ -2188,52 +2039,60 @@ namespace CodeImp.DoomBuilder
TextResourceData data = new TextResourceData(stream, location, "?SCRIPTS", false);
if(parser.Parse(data, scriptconfig.Compiler.Files, true, AcsParserSE.IncludeType.NONE, false))
{
// Add them to arrays
namedscriptslist.AddRange(parser.NamedScripts);
numberedscriptslist.AddRange(parser.NumberedScripts);
scripincludeslist.AddRange(parser.GetIncludes());
// Add to text resource list
General.Map.Data.TextResources[parser.ScriptType].UnionWith(parser.TextResources.Values);
// Update the names
UpdateScriptNames(parser);
}
// Check for errors
if(parser.HasError)
else
{
compilererrors.Add(new CompilerError(parser.ErrorDescription, parser.ErrorSource, parser.ErrorLine));
if(logerrors) parser.LogError();
break;
// Clear collections
namedscripts.Clear();
numberedscripts.Clear();
}
// Log errors, if any
if(parser.HasError) parser.LogError();
// Done here
return;
}
}
}
}
// Add to collections
scriptincludes.Clear();
if(compilererrors.Count == 0)
{
namedscripts = new Dictionary<string, ScriptItem>(namedscriptslist.Count);
numberedscripts = new Dictionary<int, ScriptItem>(numberedscriptslist.Count);
// Sort script names
namedscriptslist.Sort(ScriptItem.SortByName);
numberedscriptslist.Sort(ScriptItem.SortByIndex);
foreach(ScriptItem item in namedscriptslist)
if(!namedscripts.ContainsKey(item.Name.ToLowerInvariant())) namedscripts.Add(item.Name.ToLowerInvariant(), item);
foreach(ScriptItem item in numberedscriptslist)
if(!numberedscripts.ContainsKey(item.Index)) numberedscripts.Add(item.Index, item);
foreach(string include in scripincludeslist)
if(!scriptincludes.Contains(include)) scriptincludes.Add(include);
}
else
//mxd
internal void UpdateScriptNames(AcsParserSE parser)
{
if(parser.HasError)
{
// Clear collections
namedscripts.Clear();
numberedscripts.Clear();
}
else
{
// Add to collections
namedscripts = new Dictionary<string, ScriptItem>(parser.NamedScripts.Count);
numberedscripts = new Dictionary<int, ScriptItem>(parser.NumberedScripts.Count);
return compilererrors;
// Sort script names
parser.NamedScripts.Sort(ScriptItem.SortByName);
parser.NumberedScripts.Sort(ScriptItem.SortByIndex);
foreach(ScriptItem item in parser.NamedScripts)
{
if(!namedscripts.ContainsKey(item.Name.ToLowerInvariant()))
namedscripts.Add(item.Name.ToLowerInvariant(), item);
}
foreach(ScriptItem item in parser.NumberedScripts)
{
if(!numberedscripts.ContainsKey(item.Index))
numberedscripts.Add(item.Index, item);
}
}
}
#endregion
@ -2389,8 +2248,8 @@ namespace CodeImp.DoomBuilder
General.MainWindow.DisplayStatus(oldstatus);
Cursor.Current = oldcursor;
//mxd. Update includes list and script names
UpdateScriptNames(true);
//mxd. Update script names
UpdateScriptNames();
}
// Game Configuration action