diff --git a/Source/Core/Compilers/AccCompiler.cs b/Source/Core/Compilers/AccCompiler.cs index 152a04f3..3e5f8788 100644 --- a/Source/Core/Compilers/AccCompiler.cs +++ b/Source/Core/Compilers/AccCompiler.cs @@ -66,7 +66,6 @@ namespace CodeImp.DoomBuilder.Compilers // This runs the compiler public override bool Run() { - ProcessStartInfo processinfo; Process process; TimeSpan deltatime; int line = 0; @@ -74,24 +73,23 @@ namespace CodeImp.DoomBuilder.Compilers //xabis // Copy includes from the resources into the compiler's folder, preserving relative pathing and naming - foreach (string include in General.Map.ScriptIncludes) + foreach(string include in General.Map.ScriptIncludes) { //grab the script text from the resources MemoryStream s = General.Map.Data.LoadFile(include); - if (s != null) + if(s != 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) + if(!fi.Exists) { General.WriteLogLine("Copying script include: " + include); //create the directory path as needed - if (fi.DirectoryName != "") - Directory.CreateDirectory(fi.DirectoryName); + if(!string.IsNullOrEmpty(fi.DirectoryName)) Directory.CreateDirectory(fi.DirectoryName); //dump the script into the target file BinaryReader reader = new BinaryReader(s); @@ -110,7 +108,7 @@ namespace CodeImp.DoomBuilder.Compilers args = args.Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); //mxd. This fixes include path when the map is in a root directory // Setup process info - processinfo = new ProcessStartInfo(); + 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 diff --git a/Source/Core/Controls/ScriptDocumentTab.cs b/Source/Core/Controls/ScriptDocumentTab.cs index b280b018..a05dcf38 100644 --- a/Source/Core/Controls/ScriptDocumentTab.cs +++ b/Source/Core/Controls/ScriptDocumentTab.cs @@ -425,10 +425,12 @@ namespace CodeImp.DoomBuilder.Controls navigator.Items.Clear(); AcsParserSE parser = new AcsParserSE(); - parser.Parse(stream, "ACS"); - navigator.Items.AddRange(parser.NamedScripts.ToArray()); - navigator.Items.AddRange(parser.NumberedScripts.ToArray()); - navigator.Items.AddRange(parser.Functions.ToArray()); + if(parser.Parse(stream, "ACS")) + { + navigator.Items.AddRange(parser.NamedScripts.ToArray()); + navigator.Items.AddRange(parser.NumberedScripts.ToArray()); + navigator.Items.AddRange(parser.Functions.ToArray()); + } } //mxd diff --git a/Source/Core/Controls/ScriptFileDocumentTab.cs b/Source/Core/Controls/ScriptFileDocumentTab.cs index 53164bd0..43efeea7 100644 --- a/Source/Core/Controls/ScriptFileDocumentTab.cs +++ b/Source/Core/Controls/ScriptFileDocumentTab.cs @@ -22,7 +22,6 @@ using System.Windows.Forms; using CodeImp.DoomBuilder.Config; using System.IO; using CodeImp.DoomBuilder.Compilers; -using CodeImp.DoomBuilder.GZBuilder.Data; //mxd #endregion @@ -72,12 +71,19 @@ namespace CodeImp.DoomBuilder.Controls // This compiles the script file public override void Compile() { - string inputfile, outputfile; + //mxd. List of errors. UpdateScriptNames can return errors and also updates acs includes list + List errors = (config.ScriptType == ScriptType.ACS ? General.Map.UpdateScriptNames() : new List()); + + //mxd. Errors already?.. + if(errors.Count > 0) + { + // Feed errors to panel + panel.ShowErrors(errors); + return; + } + Compiler compiler; - // List of errors - List errors = new List(); - try { // Initialize compiler @@ -91,11 +97,11 @@ namespace CodeImp.DoomBuilder.Controls } // Copy the source file into the temporary directory - inputfile = Path.Combine(compiler.Location, Path.GetFileName(filepathname)); + string inputfile = Path.Combine(compiler.Location, Path.GetFileName(filepathname)); File.Copy(filepathname, inputfile); // Make random output filename - outputfile = General.MakeTempFilename(compiler.Location, "tmp"); + string outputfile = General.MakeTempFilename(compiler.Location, "tmp"); // Run compiler compiler.Parameters = config.Parameters; @@ -117,15 +123,13 @@ namespace CodeImp.DoomBuilder.Controls errors.Add(newerr); } - - //mxd. Should be called only if current script is compiled successfully - if (compiler.Errors.Length == 0 && config.ScriptType == ScriptType.ACS) - General.Map.UpdateScriptNames(); - UpdateNavigator(); } // Dispose compiler compiler.Dispose(); + + //mxd. Update script navigator + UpdateNavigator(); // Feed errors to panel panel.ShowErrors(errors); diff --git a/Source/Core/Controls/ScriptLumpDocumentTab.cs b/Source/Core/Controls/ScriptLumpDocumentTab.cs index ad34db98..da2c7c0f 100644 --- a/Source/Core/Controls/ScriptLumpDocumentTab.cs +++ b/Source/Core/Controls/ScriptLumpDocumentTab.cs @@ -16,10 +16,10 @@ #region ================== Namespaces +using System.Collections.Generic; using CodeImp.DoomBuilder.Config; using System.IO; using CodeImp.DoomBuilder.Compilers; -using CodeImp.DoomBuilder.GZBuilder.Data; //mxd #endregion @@ -33,8 +33,8 @@ namespace CodeImp.DoomBuilder.Controls #region ================== Variables - private string lumpname; - private bool ismapheader; + private readonly string lumpname; + private readonly bool ismapheader; #endregion @@ -87,16 +87,21 @@ namespace CodeImp.DoomBuilder.Controls // Compile script public override void Compile() { - bool success; //mxd + //mxd. List of errors. UpdateScriptNames can return errors and also updates acs includes list + List errors = (config.ScriptType == ScriptType.ACS ? General.Map.UpdateScriptNames() : new List()); + + //mxd. Errors already?.. + if(errors.Count > 0) + { + // Feed errors to panel + panel.ShowErrors(errors); + return; + } // Compile - if(ismapheader) - success = General.Map.CompileLump(MapManager.CONFIG_MAP_HEADER, true); - else - success = General.Map.CompileLump(lumpname, true); - - //mxd. Update script names cache and script navigator - if(success && config.ScriptType == ScriptType.ACS) General.Map.UpdateScriptNames(); + General.Map.CompileLump((ismapheader ? MapManager.CONFIG_MAP_HEADER : lumpname), true); + + //mxd. Update script navigator UpdateNavigator(); // Feed errors to panel diff --git a/Source/Core/GZBuilder/GZDoom/AcsParserSE.cs b/Source/Core/GZBuilder/GZDoom/AcsParserSE.cs index 5895ecd4..6f062cea 100644 --- a/Source/Core/GZBuilder/GZDoom/AcsParserSE.cs +++ b/Source/Core/GZBuilder/GZDoom/AcsParserSE.cs @@ -12,8 +12,9 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom internal delegate void IncludeDelegate(AcsParserSE parser, string includefile); internal IncludeDelegate OnInclude; - private readonly List parsedlumps; - private readonly List includes; + private readonly HashSet parsedlumps; + private readonly HashSet includes; + private List includestoskip; private readonly List namedscripts; private readonly List numberedscripts; @@ -29,24 +30,37 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom namedscripts = new List(); numberedscripts = new List(); functions = new List(); - parsedlumps = new List(); - includes = new List(); + parsedlumps = new HashSet(); + includes = new HashSet(); + includestoskip = new List(); specialtokens += "(,)"; } public override bool Parse(Stream stream, string sourcefilename) { - return Parse(stream, sourcefilename, false, false); + return Parse(stream, sourcefilename, new List(), false, false); } - public bool Parse(Stream stream, string sourcefilename, bool processincludes, bool isinclude) + public bool Parse(Stream stream, string sourcefilename, bool processincludes, bool isinclude) { + return Parse(stream, sourcefilename, includestoskip, processincludes, isinclude); + } + + public bool Parse(Stream stream, string sourcefilename, List configincludes, bool processincludes, bool isinclude) + { + if(stream == null || stream.Length == 0) + { + ReportError("Unable to load " + (isinclude ? "include" : "") + " file '" + sourcefilename + "'!"); + return false; + } + base.Parse(stream, sourcefilename); - //already parsed this? - if (parsedlumps.Contains(sourcefilename)) return false; + // Already parsed this? + if(parsedlumps.Contains(sourcefilename)) return false; parsedlumps.Add(sourcefilename); - if (isinclude) includes.Add(sourcefilename); + if(isinclude && !includes.Contains(sourcefilename)) includes.Add(sourcefilename); + includestoskip = configincludes; int bracelevel = 0; // Keep local data @@ -55,7 +69,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom BinaryReader localreader = datareader; // Continue until at the end of the stream - while (SkipWhitespace(true)) + while(SkipWhitespace(true)) { string token = ReadToken(); if(string.IsNullOrEmpty(token)) continue; @@ -65,7 +79,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom if(token == "}") { bracelevel--; continue; } if(bracelevel > 0) continue; - switch (token.ToLowerInvariant()) + switch(token.ToLowerInvariant()) { case "script": { @@ -74,7 +88,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom token = ReadToken(); //is it named script? - if (token.IndexOf('"') != -1) + if(token.IndexOf('"') != -1) { startpos += 1; string scriptname = StripTokenQuotes(token); @@ -90,7 +104,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom else //should be numbered script { int n; - if (int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out n)) + if(int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out n)) { // Try to parse argument names List> args = ParseArgs(); @@ -106,10 +120,10 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom string name = ""; bracelevel = 1; - if (!string.IsNullOrEmpty(token)) + if(!string.IsNullOrEmpty(token)) { int commentstart = token.IndexOf("//"); - if (commentstart != -1) //found comment + if(commentstart != -1) //found comment { commentstart += 2; name = token.Substring(commentstart, token.Length - commentstart).Trim(); @@ -148,20 +162,18 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom break; default: - if (processincludes && (token == "#include" || token == "#import")) + if(processincludes && (token == "#include" || token == "#import")) { SkipWhitespace(true); string includelump = StripTokenQuotes(ReadToken()).ToLowerInvariant(); - if (!string.IsNullOrEmpty(includelump)) + if(!string.IsNullOrEmpty(includelump)) { string includename = Path.GetFileName(includelump); - - if (includename == "zcommon.acs" || includename == "common.acs" || includes.Contains(includename)) - continue; + if(includestoskip.Contains(includename) || includes.Contains(includename)) continue; // Callback to parse this file - if (OnInclude != null) OnInclude(this, includelump.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar)); + if(OnInclude != null) OnInclude(this, includelump.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar)); // Set our buffers back to continue parsing datastream = localstream; @@ -170,7 +182,8 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom } else { - General.ErrorLogger.Add(ErrorType.Error, "Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": got #include directive without include path!"); + ReportError("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": got #include directive without include path!"); + return false; } } break; diff --git a/Source/Core/General/MapManager.cs b/Source/Core/General/MapManager.cs index ad56ddfb..34a3cbc1 100644 --- a/Source/Core/General/MapManager.cs +++ b/Source/Core/General/MapManager.cs @@ -87,7 +87,7 @@ namespace CodeImp.DoomBuilder //mxd private Dictionary namedscripts; private Dictionary numberedscripts; - private List scriptincludes; + private readonly HashSet scriptincludes; // Disposing private bool isdisposed; @@ -130,7 +130,7 @@ namespace CodeImp.DoomBuilder //mxd. Scripts internal Dictionary NamedScripts { get { return namedscripts; } } internal Dictionary NumberedScripts { get { return numberedscripts; } } - internal List ScriptIncludes { get { return scriptincludes; } } + internal HashSet ScriptIncludes { get { return scriptincludes; } } public ViewMode ViewMode { get { return renderer2d.ViewMode; } } @@ -160,7 +160,7 @@ namespace CodeImp.DoomBuilder //mxd numberedscripts = new Dictionary(); namedscripts = new Dictionary(); - scriptincludes = new List(); + scriptincludes = new HashSet(); } // Disposer @@ -437,8 +437,8 @@ namespace CodeImp.DoomBuilder map.Update(); thingsfilter.Update(); - //mxd. check script names - UpdateScriptNames(); + //mxd. Update includes list and script names + UpdateScriptNames(true); //mxd. Restore selection groups options.ReadSelectionGroups(); @@ -527,8 +527,8 @@ namespace CodeImp.DoomBuilder //mxd. Sector textures may've been changed data.UpdateUsedTextures(); - //mxd. check script names - UpdateScriptNames(); + //mxd. Update includes list and script names + UpdateScriptNames(true); //mxd. Restore selection groups options.ReadSelectionGroups(); @@ -1746,7 +1746,7 @@ namespace CodeImp.DoomBuilder { scriptconfig = config.MapLumps[lumpname].Script; } - if (scriptconfig.Compiler == null) return true; + if(scriptconfig.Compiler == null) return true; // Find the lump if(lumpname == CONFIG_MAP_HEADER) reallumpname = TEMP_MAP_HEADER; @@ -1757,7 +1757,7 @@ namespace CodeImp.DoomBuilder string sourcefile = (filepathname.Length > 0 ? filepathname : tempwad.Filename); // New list of errors - if (clearerrors) errors.Clear(); + if(clearerrors) errors.Clear(); // Determine the script configuration to use try @@ -1862,11 +1862,29 @@ namespace CodeImp.DoomBuilder errors.Clear(); }*/ - //mxd - internal void UpdateScriptNames() + //mxd. Update includes list and script names + internal List UpdateScriptNames(bool logerrors) + { + List compilererrors = UpdateScriptNames(); + if(logerrors && compilererrors.Count > 0) + { + foreach(CompilerError error in compilererrors) + { + General.ErrorLogger.Add(ErrorType.Error, "ACS error in '" + error.filename + + "', line " + error.linenumber + ". " + error.description + "."); + } + } + + return compilererrors; + } + + //mxd. Update includes list and script names + internal List UpdateScriptNames() { List namedscriptslist = new List(); List numberedscriptslist = new List(); + List scripincludeslist = new List(); + List compilererrors = new List(); // Load the script lumps foreach(MapLumpInfo maplumpinfo in config.MapLumps.Values) @@ -1874,48 +1892,78 @@ namespace CodeImp.DoomBuilder // Is this a script lump? if((maplumpinfo.ScriptBuild || maplumpinfo.Script != null) && maplumpinfo.Name == "SCRIPTS") { + ScriptConfiguration scriptconfig; + if(maplumpinfo.ScriptBuild) + { + //mxd. More boilderplate + if(!General.CompiledScriptConfigs.ContainsKey(General.Map.Options.ScriptCompiler)) + { + compilererrors.Add(new CompilerError("Unable to compile lump '" + maplumpinfo.Name + "'. Unable to find required script compiler configuration ('" + General.Map.Options.ScriptCompiler + "').")); + return compilererrors; + } + + scriptconfig = General.CompiledScriptConfigs[General.Map.Options.ScriptCompiler]; + } + else + { + scriptconfig = maplumpinfo.Script; + } + // Load the lump data MemoryStream stream = GetLumpData(maplumpinfo.Name); - if(stream != null) + if(stream != null && scriptconfig != null && scriptconfig.Compiler != null) { // Get script names - AcsParserSE parser = new AcsParserSE(); - parser.OnInclude = UpdateScriptsFromLocation; - parser.Parse(stream, "SCRIPTS", true, false); - - // Add them to arrays - namedscriptslist.AddRange(parser.NamedScripts); - numberedscriptslist.AddRange(parser.NumberedScripts); - scriptincludes.AddRange(parser.Includes); + AcsParserSE parser = new AcsParserSE { OnInclude = UpdateScriptsFromLocation }; + if(parser.Parse(stream, "SCRIPTS", scriptconfig.Compiler.Files, true, false)) + { + // Add them to arrays + namedscriptslist.AddRange(parser.NamedScripts); + numberedscriptslist.AddRange(parser.NumberedScripts); + scripincludeslist.AddRange(parser.Includes); + } + // Check for errors + else if(parser.HasError) + { + compilererrors.Add(new CompilerError(parser.ErrorDescription, parser.ErrorSource, parser.ErrorLine)); + break; + } } } } - // Sort script names - namedscriptslist.Sort(ScriptItem.SortByName); - numberedscriptslist.Sort(ScriptItem.SortByIndex); - // Add to collections - namedscripts = new Dictionary(namedscriptslist.Count); - numberedscripts = new Dictionary(numberedscriptslist.Count); + scriptincludes.Clear(); + if(compilererrors.Count == 0) + { + namedscripts = new Dictionary(namedscriptslist.Count); + numberedscripts = new Dictionary(numberedscriptslist.Count); - foreach (ScriptItem item in namedscriptslist) - { - if(!namedscripts.ContainsKey(item.Name.ToLowerInvariant())) - namedscripts.Add(item.Name.ToLowerInvariant(), item); + // 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); } - foreach(ScriptItem item in numberedscriptslist) + else { - if(!numberedscripts.ContainsKey(item.Index)) - numberedscripts.Add(item.Index, item); + // Clear collections + namedscripts.Clear(); + numberedscripts.Clear(); } + + return compilererrors; } //mxd private static void UpdateScriptsFromLocation(AcsParserSE parser, string path) { - MemoryStream s = General.Map.Data.LoadFile(path); - if(s != null && s.Length > 0) parser.Parse(s, path, true, true); + parser.Parse(General.Map.Data.LoadFile(path), path, true, true); } #endregion @@ -2071,8 +2119,8 @@ namespace CodeImp.DoomBuilder General.MainWindow.DisplayStatus(oldstatus); Cursor.Current = oldcursor; - //mxd - UpdateScriptNames(); + //mxd. Update includes list and script names + UpdateScriptNames(true); } // Game Configuration action @@ -2146,7 +2194,6 @@ namespace CodeImp.DoomBuilder // Reload resources ReloadResources(); - UpdateScriptNames(); //mxd //mxd. Translate texture names bool nameschanged = map.TranslateTextureNames(config.UseLongTextureNames, false); diff --git a/Source/Plugins/BuilderModes/VisualModes/BaseVisualThing.cs b/Source/Plugins/BuilderModes/VisualModes/BaseVisualThing.cs index eea28b5f..5caa6cba 100644 --- a/Source/Plugins/BuilderModes/VisualModes/BaseVisualThing.cs +++ b/Source/Plugins/BuilderModes/VisualModes/BaseVisualThing.cs @@ -165,8 +165,8 @@ namespace CodeImp.DoomBuilder.BuilderModes } } - // Don't bother when alpha is unchanged - if(alpha == 255) RenderPass = RenderPass.Mask; + // Don't bother when alpha is unchanged, unless Additive RenderStyle is used + if(RenderPass != RenderPass.Additive && alpha == 255) RenderPass = RenderPass.Mask; int sectorcolor = new PixelColor(alpha, 255, 255, 255).ToInt(); fogfactor = 0f; //mxd