Fixed, Script Editor: file was marked as changed when changing script configurations.

Fixed, Script Editor: in some cases clicking on an error in the errors list didn't navigate to the error location.
Fixed, Script Editor: in some cases incorrect error line number was shown.
Fixed, Text lump parsers: fixed a crash when trying to get a filename from a quoted string with missing closing quote.
Fixed, Text lump parsers: in several cases parsing errors were ignored by overlaying data structures.
Fixed: in some cases Thing Filter thing flags were cleared when switching game configurations in the "Game Configurations" window.
Changed, PK3 reader: loading of files with invalid path chars is now skipped instead of skipping loading of the whole resource. Also more helpful warning message is now displayed.
Updated SharpCompress library to v.0.11.2.0.
This commit is contained in:
MaxED 2015-12-17 10:07:28 +00:00
parent a35a336527
commit dbcc57b7a6
40 changed files with 1117 additions and 894 deletions

View file

@ -9,5 +9,7 @@ compilers
{
interface = "AccCompiler";
program = "bcc.exe";
zcommon = "zcommon.acs";
std = "std.acs";
}
}

View file

@ -9,5 +9,9 @@ compilers
{
interface = "AccCompiler";
program = "acc.exe";
zcommon = "common.acs";
zdefs = "defs.acs";
zspecial = "specials.acs";
zwvars = "wvars.acs";
}
}

View file

@ -9,5 +9,9 @@ compilers
{
interface = "AccCompiler";
program = "acc.exe";
zcommon = "zcommon.acs";
zdefs = "zdefs.acs";
zspecial = "zspecial.acs";
zwvars = "zwvars.acs";
}
}

View file

@ -9,5 +9,9 @@ compilers
{
interface = "AccCompiler";
program = "acc.exe";
zcommon = "zcommon.acs";
zdefs = "zdefs.acs";
zspecial = "zspecial.acs";
zwvars = "zwvars.acs";
}
}

Binary file not shown.

View file

@ -533,7 +533,9 @@
</ItemGroup>
<ItemGroup>
<Reference Include="JetBrains.Profiler.Core.Api, Version=1.3.1661.20096, Culture=neutral, PublicKeyToken=1010a0d8d6380325" Condition=" '$(Configuration)|$(Platform)' == 'Debug + Profiler|x86' Or '$(Configuration)|$(Platform)' == 'Release + Profiler|x86' " />
<Reference Include="SharpCompress.3.5, Version=0.11.1.0, Culture=neutral, processorArchitecture=x86" />
<Reference Include="SharpCompress.3.5, Version=0.11.2.0, Culture=neutral, processorArchitecture=x86">
<Private>False</Private>
</Reference>
<Reference Include="SlimDX, Version=2.0.13.43, Culture=neutral, PublicKeyToken=b1b0c32fd1ffe4f9, processorArchitecture=x86" />
<Reference Include="System" />
<Reference Include="System.Core">
@ -860,7 +862,6 @@
<Compile Include="GZBuilder\Data\ModelLoadState.cs" />
<Compile Include="GZBuilder\Data\ScriptItem.cs" />
<Compile Include="GZBuilder\Data\SharpCompressHelper.cs" />
<Compile Include="GZBuilder\Data\TextureData.cs" />
<Compile Include="GZBuilder\Rendering\SizelessVisualThingCage.cs" />
<Compile Include="GZBuilder\Rendering\ThingBoundingBox.cs" />
<Compile Include="GZBuilder\Data\ThingCopyData.cs" />

View file

@ -17,7 +17,6 @@
#region ================== Namespaces
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using CodeImp.DoomBuilder.Config;
@ -44,7 +43,7 @@ namespace CodeImp.DoomBuilder.Compilers
#region ================== Constructor
// Constructor
public AccCompiler(CompilerInfo info) : base(info)
public AccCompiler(CompilerInfo info) : base(info, false)
{
}

View file

@ -71,7 +71,7 @@ namespace CodeImp.DoomBuilder.Compilers
#region ================== Constructor / Disposer
// Constructor
protected Compiler(CompilerInfo info)
protected Compiler(CompilerInfo info, bool copyrequiredfiles)
{
// Initialize
this.info = info;
@ -83,10 +83,15 @@ namespace CodeImp.DoomBuilder.Compilers
// Create temporary directory
tempdir = Directory.CreateDirectory(General.MakeTempDirname());
workingdir = tempdir.FullName;
// Copy required files to the temp directory
General.WriteLogLine("Copying required files for compiler...");
CopyRequiredFiles();
//mxd. ACC compiler itself is not copied to tempdir anymore, so we don't need to move it's include files
//but we still need tempdir to compile SCRIPTS lump.
if(copyrequiredfiles)
{
// Copy required files to the temp directory
General.WriteLogLine("Copying required files for compiler...");
CopyRequiredFiles();
}
}
// Disposer

View file

@ -43,7 +43,7 @@ namespace CodeImp.DoomBuilder.Compilers
#region ================== Constructor / Disposer
// Constructor
public NodesCompiler(CompilerInfo info) : base(info)
public NodesCompiler(CompilerInfo info) : base(info, true)
{
// Initialize

View file

@ -454,13 +454,14 @@ namespace CodeImp.DoomBuilder.Config
{
// Copy the things filters from game configuration
foreach(ThingsFilter f in gameconfig.ThingsFilters)
{
thingsfilters.Add(new ThingsFilter(f));
}
}
//mxd. Validate filters
foreach(ThingsFilter f in thingsfilters) f.Validate();
//mxd. Validate filters. Do it only for currently used ConfigInfo
if(General.Map != null && General.Map.ConfigSettings == this)
{
foreach(ThingsFilter f in thingsfilters) f.Validate();
}
}
// Go for all available editing modes

View file

@ -410,6 +410,7 @@ namespace CodeImp.DoomBuilder.Controls
}
// Put some text in the navigator (but don't actually trigger selection event)
navigator.Enabled = (navigator.Items.Count > 0);
if(navigator.Items.Count > 0)
{
preventchanges = true;
@ -421,32 +422,43 @@ namespace CodeImp.DoomBuilder.Controls
//mxd
private void UpdateNavigatorDecorate(MemoryStream stream)
{
if (stream == null) return;
if(stream == null) return;
navigator.Items.Clear();
DecorateParserSE parser = new DecorateParserSE();
parser.Parse(stream, "DECORATE");
navigator.Items.AddRange(parser.Actors.ToArray());
if(parser.Parse(stream, "DECORATE"))
{
navigator.Items.AddRange(parser.Actors.ToArray());
}
if(parser.HasError)
{
panel.ShowErrors(new List<CompilerError> { new CompilerError(parser.ErrorDescription, parser.ErrorSource, parser.ErrorLine) });
}
}
//mxd
private void UpdateNavigatorModeldef(MemoryStream stream)
{
if (stream == null) return;
if(stream == null) return;
navigator.Items.Clear();
ModeldefParserSE parser = new ModeldefParserSE();
parser.Parse(stream, "MODELDEF");
navigator.Items.AddRange(parser.Models.ToArray());
if(parser.Parse(stream, "MODELDEF"))
{
navigator.Items.AddRange(parser.Models.ToArray());
}
if(parser.HasError)
{
panel.ShowErrors(new List<CompilerError> { new CompilerError(parser.ErrorDescription, parser.ErrorSource, parser.ErrorLine) });
}
}
//mxd
private void UpdateNavigatorAcs(MemoryStream stream)
{
if (stream == null) return;
if(stream == null) return;
navigator.Items.Clear();
AcsParserSE parser = new AcsParserSE { AddArgumentsToScriptNames = true, IsMapScriptsLump = this is ScriptLumpDocumentTab };
@ -456,17 +468,28 @@ namespace CodeImp.DoomBuilder.Controls
navigator.Items.AddRange(parser.NumberedScripts.ToArray());
navigator.Items.AddRange(parser.Functions.ToArray());
}
if(parser.HasError)
{
panel.ShowErrors(new List<CompilerError> { new CompilerError(parser.ErrorDescription, parser.ErrorSource, parser.ErrorLine) });
}
}
//mxd
internal ScriptType VerifyScriptType()
{
ScriptTypeParserSE parser = new ScriptTypeParserSE();
if (parser.Parse(new MemoryStream(editor.GetText()), config.Description))
if(parser.Parse(new MemoryStream(editor.GetText()), config.Description))
{
if (parser.ScriptType != ScriptType.UNKNOWN && config.ScriptType != parser.ScriptType)
if(parser.ScriptType != ScriptType.UNKNOWN && config.ScriptType != parser.ScriptType)
return parser.ScriptType;
}
if(parser.HasError)
{
panel.ShowErrors(new List<CompilerError> { new CompilerError(parser.ErrorDescription, parser.ErrorSource, parser.ErrorLine) });
}
return ScriptType.UNKNOWN;
}

View file

@ -250,8 +250,6 @@ namespace CodeImp.DoomBuilder.Controls
// This sets up the script editor with a script configuration
public void SetupStyles(ScriptConfiguration config)
{
Stream lexersdata;
StreamReader lexersreader;
Configuration lexercfg = new Configuration();
// Make collections
@ -259,7 +257,7 @@ namespace CodeImp.DoomBuilder.Controls
SortedList<string, string> autocompletelist = new SortedList<string, string>(StringComparer.Ordinal);
// Keep script configuration
if(scriptconfig != config) scriptconfig = config;
scriptconfig = config;
// Find a resource named Lexers.cfg
string[] resnames = General.ThisAssembly.GetManifestResourceNames();
@ -269,8 +267,8 @@ namespace CodeImp.DoomBuilder.Controls
if(rn.EndsWith(LEXERS_RESOURCE, StringComparison.InvariantCultureIgnoreCase))
{
// Get a stream from the resource
lexersdata = General.ThisAssembly.GetManifestResourceStream(rn);
lexersreader = new StreamReader(lexersdata, Encoding.ASCII);
Stream lexersdata = General.ThisAssembly.GetManifestResourceStream(rn);
StreamReader lexersreader = new StreamReader(lexersdata, Encoding.ASCII);
// Load configuration from stream
lexercfg.InputConfiguration(lexersreader.ReadToEnd());
@ -426,8 +424,10 @@ namespace CodeImp.DoomBuilder.Controls
functionbar.Visible = (scriptconfig.FunctionRegEx.Length > 0);
// Rearrange the layout
bool ischanged = changed; //mxd. Don't want the "changed" status to change when changing text styles
scriptedit.ClearDocumentStyle();
scriptedit.SetText(scriptedit.GetText(scriptedit.TextSize));
changed = ischanged; //mxd
this.PerformLayout();
}

View file

@ -175,23 +175,24 @@ namespace CodeImp.DoomBuilder.Controls
AcsParserSE parser = new AcsParserSE { OnInclude = (se, path) => se.Parse(General.Map.Data.LoadFile(path), path, true, true) };
using(FileStream stream = File.OpenRead(filepathname))
{
if(!parser.Parse(stream, inputfile, scriptconfig.Compiler.Files, true, false))
if(!parser.Parse(stream, filepathname, scriptconfig.Compiler.Files, true, false))
{
// Check for errors
if(parser.HasError)
{
errors.Add(new CompilerError(parser.ErrorDescription, parser.ErrorSource, parser.ErrorLine));
panel.ShowErrors(errors);
compiler.Dispose();
return;
}
compiler.Dispose();
return;
}
}
// Only works for libraries
//mxd. Only works for libraries
if(!parser.IsLibrary)
{
errors.Add(new CompilerError("External ACS files can only be compiled as libraries!", inputfile));
errors.Add(new CompilerError("External ACS files can only be compiled as libraries!", filepathname));
panel.ShowErrors(errors);
compiler.Dispose();
return;
@ -349,6 +350,10 @@ namespace CodeImp.DoomBuilder.Controls
string ext = (config.Extensions.Length > 0 ? "." + config.Extensions[0] : "");
SetTitle("Untitled" + ext);
}
else
{
UpdateTitle(); //mxd
}
//mxd
base.ChangeScriptConfig(newconfig);

View file

@ -1404,9 +1404,8 @@ namespace CodeImp.DoomBuilder.Data
char[] catsplitter = new[] {Path.AltDirectorySeparatorChar}; //mxd
// Create new parser
decorate = new DecorateParser();
decorate.OnInclude = LoadDecorateFromLocation;
decorate = new DecorateParser { OnInclude = LoadDecorateFromLocation };
// Only load these when the game configuration supports the use of decorate
if(!string.IsNullOrEmpty(General.Map.Config.DecorateGames))
{
@ -1423,12 +1422,11 @@ namespace CodeImp.DoomBuilder.Data
group.Value.Seek(0, SeekOrigin.Begin);
decorate.Parse(group.Value, group.Key, true);
// Check for errors
//mxd. DECORATE lumps are interdepandable. Can't carry on...
if(decorate.HasError)
{
General.ErrorLogger.Add(ErrorType.Error, "DECORATE error in '" + decorate.ErrorSource
+ (decorate.ErrorLine != CompilerError.NO_LINE_NUMBER ? "', line " + decorate.ErrorLine : "'") + ". " + decorate.ErrorDescription + ".");
break;
decorate.LogError(); //mxd
return counter;
}
}
}
@ -1823,6 +1821,13 @@ namespace CodeImp.DoomBuilder.Data
}
}
}
// Modeldefs are independable, so parsing fail in one file should not affect the others
if(parser.HasError)
{
parser.LogError();
parser.ClearError();
}
}
}
@ -1895,19 +1900,29 @@ namespace CodeImp.DoomBuilder.Data
currentreader = dr;
KeyValuePair<string, Stream> group = dr.GetVoxeldefData();
if(group.Value != null && parser.Parse(group.Value, group.Key))
if(group.Value != null)
{
foreach(KeyValuePair<string, ModelData> entry in parser.Entries)
if(parser.Parse(group.Value, group.Key))
{
foreach(KeyValuePair<string, List<int>> sc in sprites)
foreach(KeyValuePair<string, ModelData> entry in parser.Entries)
{
if(sc.Key.Contains(entry.Key))
foreach(KeyValuePair<string, List<int>> sc in sprites)
{
foreach(int id in sc.Value) modeldefentries[id] = entry.Value;
processed.Add(entry.Key, false);
if(sc.Key.Contains(entry.Key))
{
foreach(int id in sc.Value) modeldefentries[id] = entry.Value;
processed.Add(entry.Key, false);
}
}
}
}
// Report errors?
if(parser.HasError)
{
parser.LogError();
parser.ClearError();
}
}
}
@ -1939,7 +1954,7 @@ namespace CodeImp.DoomBuilder.Data
GldefsParser parser = new GldefsParser { OnInclude = ParseFromLocation };
//load gldefs from resources
// Load gldefs from resources
foreach(DataReader dr in containers)
{
currentreader = dr;
@ -1947,7 +1962,16 @@ namespace CodeImp.DoomBuilder.Data
Dictionary<string, Stream> streams = dr.GetGldefsData(General.Map.Config.GameType);
foreach(KeyValuePair<string, Stream> group in streams)
{
parser.Parse(group.Value, group.Key);
// Gldefs can be interdependable. Can't carry on
if(parser.HasError)
{
parser.LogError();
return;
}
}
}
//create gldefsEntries dictionary
@ -1957,12 +1981,7 @@ namespace CodeImp.DoomBuilder.Data
if(actorsByClass.ContainsKey(e.Key) && parser.LightsByName.ContainsKey(e.Value))
{
foreach(int i in actorsByClass[e.Key])
{
if(gldefsentries.ContainsKey(i))
gldefsentries[i] = parser.LightsByName[e.Value];
else
gldefsentries.Add(i, parser.LightsByName[e.Value]);
}
gldefsentries[i] = parser.LightsByName[e.Value];
}
else if(!decorate.AllActorsByClass.ContainsKey(e.Key))
{
@ -1978,7 +1997,7 @@ namespace CodeImp.DoomBuilder.Data
private void LoadMapInfo(out Dictionary<int, string> spawnnums, out Dictionary<int, string> doomednums)
{
MapinfoParser parser = new MapinfoParser { OnInclude = ParseFromLocation };
foreach(DataReader dr in containers)
{
currentreader = dr;
@ -1987,7 +2006,20 @@ namespace CodeImp.DoomBuilder.Data
foreach(KeyValuePair<string, Stream> group in streams)
{
// Parse the data
parser.Parse(group.Value, Path.Combine(currentreader.Location.location, group.Key), General.Map.Options.LevelName);
parser.Parse(group.Value, Path.Combine(currentreader.Location.location, group.Key), General.Map.Options.LevelName);
//MAPINFO lumps are interdependable. Can't carry on...
if(parser.HasError)
{
parser.LogError();
// No nulls allowed!
spawnnums = new Dictionary<int, string>();
doomednums = new Dictionary<int, string>();
mapinfo = new MapInfo();
return;
}
}
}
@ -2024,6 +2056,13 @@ namespace CodeImp.DoomBuilder.Data
{
// Parse the data
parser.Parse(group.Value, group.Key);
// Report errors?
if(parser.HasError)
{
parser.LogError();
parser.ClearError();
}
}
}
@ -2049,6 +2088,13 @@ namespace CodeImp.DoomBuilder.Data
foreach(Stream s in streams)
{
if(s != null) parser.Parse(s, "SNDSEQ");
// Report errors?
if(parser.HasError)
{
parser.LogError();
parser.ClearError();
}
}
}

View file

@ -71,7 +71,7 @@ namespace CodeImp.DoomBuilder.Data
IReader reader = archive.ExtractAllEntries();
while(reader.MoveToNextEntry())
{
if(reader.Entry.IsDirectory) continue;
if(reader.Entry.IsDirectory || !CheckInvalidPathChars(reader.Entry.Key)) continue;
MemoryStream s = new MemoryStream();
reader.WriteEntryTo(s);
@ -83,8 +83,8 @@ namespace CodeImp.DoomBuilder.Data
{
foreach(IArchiveEntry entry in archive.Entries)
{
if(entry.IsDirectory) continue;
fileentries.Add(new DirectoryFileEntry(entry.Key));
if(!entry.IsDirectory && CheckInvalidPathChars(entry.Key))
fileentries.Add(new DirectoryFileEntry(entry.Key));
}
}
@ -415,18 +415,18 @@ namespace CodeImp.DoomBuilder.Data
string fn = filename.Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); //mxd
//mxd. This works waaaaaay faster with 7z archive
if (archivetype == ArchiveType.SevenZip)
if(archivetype == ArchiveType.SevenZip)
{
fn = fn.ToLowerInvariant();
if (sevenzipentries.ContainsKey(fn)) filedata = new MemoryStream(sevenzipentries[fn]);
}
else
{
lock (this)
lock(this)
{
UpdateArchive(true);
foreach (var entry in archive.Entries)
foreach(var entry in archive.Entries)
{
if(entry.IsDirectory) continue;
@ -444,7 +444,7 @@ namespace CodeImp.DoomBuilder.Data
}
// Nothing found?
if (filedata == null)
if(filedata == null)
{
//mxd
General.ErrorLogger.Add(ErrorType.Error, "Cannot find the file '" + filename + "' in archive '" + location.location + "'.");
@ -466,7 +466,31 @@ namespace CodeImp.DoomBuilder.Data
filedata.Dispose();
return tempfile;
}
//mxd. This replicates System.IO.Path.CheckInvalidPathChars() internal function
private bool CheckInvalidPathChars(string path)
{
foreach(char c in path)
{
int num = c;
switch(num)
{
case 34:
case 60:
case 62:
case 124:
General.ErrorLogger.Add(ErrorType.Error, "Error in \"" + location.location + "\": unsupported character \"" + c + "\" in path \"" + path + "\". File loading was skipped.");
return false;
default:
if(num >= 32) continue;
else goto case 34;
}
}
return true;
}
#endregion
}
}

View file

@ -408,21 +408,14 @@ namespace CodeImp.DoomBuilder.Data
// Parse the data
TexturesParser parser = new TexturesParser();
parser.Parse(stream, filename);
if(parser.HasError) parser.LogError(); //mxd
// Make the textures
foreach(TextureStructure t in parser.Textures)
{
if(t.Name.Length > 0)
{
// Add the texture
ImageData img = t.MakeImage();
images.Add(img);
}
else
{
// Can't load image without name
General.ErrorLogger.Add(ErrorType.Error, "Can't load an unnamed texture from \"" + filename + "\". Please consider giving names to your resources.");
}
// Add the texture
ImageData img = t.MakeImage();
images.Add(img);
}
}
@ -655,21 +648,14 @@ namespace CodeImp.DoomBuilder.Data
// Parse the data
TexturesParser parser = new TexturesParser();
parser.Parse(stream, filename);
if(parser.HasError) parser.LogError(); //mxd
// Make the textures
foreach(TextureStructure t in parser.Flats)
{
if(t.Name.Length > 0)
{
// Add the texture
ImageData img = t.MakeImage();
images.Add(img);
}
else
{
// Can't load image without name
General.ErrorLogger.Add(ErrorType.Error, "Can't load an unnamed flat from \"" + filename + "\". Please consider giving names to your resources.");
}
// Add the texture
ImageData img = t.MakeImage();
images.Add(img);
}
}
@ -725,21 +711,14 @@ namespace CodeImp.DoomBuilder.Data
// Parse the data
TexturesParser parser = new TexturesParser();
parser.Parse(stream, filename);
if(parser.HasError) parser.LogError(); //mxd
// Make the textures
foreach(TextureStructure t in parser.Sprites)
{
if(t.Name.Length > 0)
{
// Add the sprite
ImageData img = t.MakeImage();
images.Add(img);
}
else
{
// Can't load image without name
General.ErrorLogger.Add(ErrorType.Error, "Can't load an unnamed sprite from \"" + filename + "\". Please consider giving names to your resources.");
}
// Add the sprite
ImageData img = t.MakeImage();
images.Add(img);
}
}

View file

@ -236,36 +236,6 @@ namespace CodeImp.DoomBuilder.Editing
for(int i = 0; i < Thing.NUM_ARGS; i++) thingargs[i] = -1;
}
if(!General.Map.FormatInterface.HasCustomFields) customfields.Clear();
//mxd. We don't want to keep unknown flags (like flags from different map format)
if(General.Map.Config != null && General.Map.Config.ThingFlags != null)
{
List<String> unknownfields = new List<string>();
foreach(String s in forbiddenfields)
{
if(!General.Map.Config.ThingFlags.ContainsKey(s))
unknownfields.Add(s);
}
if(unknownfields.Count > 0)
{
foreach(String s in unknownfields)
forbiddenfields.Remove(s);
}
unknownfields = new List<string>();
foreach(String s in requiredfields)
{
if(!General.Map.Config.ThingFlags.ContainsKey(s))
unknownfields.Add(s);
}
if(unknownfields.Count > 0)
{
foreach(String s in unknownfields)
requiredfields.Remove(s);
}
}
}
}
@ -274,6 +244,32 @@ namespace CodeImp.DoomBuilder.Editing
{
AdjustForMapFormat();
//mxd. We don't want to keep unknown flags (like flags from different map format)
if(General.Map.Config != null && General.Map.Config.ThingFlags != null)
{
List<String> unknownfields = new List<string>();
foreach(String s in forbiddenfields)
{
if(!General.Map.Config.ThingFlags.ContainsKey(s)) unknownfields.Add(s);
}
if(unknownfields.Count > 0)
{
foreach(String s in unknownfields) forbiddenfields.Remove(s);
}
unknownfields.Clear();
foreach(String s in requiredfields)
{
if(!General.Map.Config.ThingFlags.ContainsKey(s)) unknownfields.Add(s);
}
if(unknownfields.Count > 0)
{
foreach(String s in unknownfields) requiredfields.Remove(s);
}
}
//Integrity check
if(!IsValid())
General.ErrorLogger.Add(ErrorType.Warning, "Things filter '" + name + "' has invalid properties. Configure the thing filter to fix this!");
@ -298,8 +294,7 @@ namespace CodeImp.DoomBuilder.Editing
/// </summary>
public bool IsThingVisible(Thing t)
{
if (t.IsDisposed) return false; //mxd
return thingsvisiblestate[t];
return (!t.IsDisposed && thingsvisiblestate[t]);
}
// This writes the filter to configuration

View file

@ -12,6 +12,12 @@ namespace CodeImp.DoomBuilder.GZBuilder.Data
{
internal sealed class ModelData
{
#region ================== Constants
public static readonly string[] SUPPORTED_TEXTURE_EXTENSIONS = { ".jpg", ".tga", ".png", ".dds", ".pcx" };
#endregion
#region ================== Variables
private ModelLoadState loadstate;

View file

@ -1,6 +0,0 @@
namespace CodeImp.DoomBuilder.GZBuilder.Data {
public struct TextureData {
public const string INVALID_TEXTURE = "**invalid_texture**";
public static string[] SUPPORTED_TEXTURE_EXTENSIONS = { ".jpg", ".tga", ".png", ".dds", ".pcx" };
}
}

View file

@ -63,8 +63,6 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
base.Parse(stream, sourcefilename);
// Already parsed this?
if(parsedlumps.Contains(sourcefilename)) return false;
parsedlumps.Add(sourcefilename);
if(isinclude && !includes.Contains(sourcefilename)) includes.Add(sourcefilename);
includestoskip = configincludes;
@ -180,46 +178,68 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
case "#library":
if(IsMapScriptsLump)
{
ReportError("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": SCRIPTS lump can not be compiled as library!");
ReportError("SCRIPTS lump can not be compiled as a library");
return false;
}
SkipWhitespace(true);
libraryname = ReadToken();
libraryname = ReadToken(false); // Don't skip newline
if(string.IsNullOrEmpty(libraryname) || !libraryname.StartsWith("\"") || !libraryname.EndsWith("\""))
if(!libraryname.StartsWith("\"") || !libraryname.EndsWith("\""))
{
ReportError("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": invalid #library directive!");
ReportError("#library name should be quoted");
return false;
}
libraryname = StripTokenQuotes(libraryname);
if(string.IsNullOrEmpty(libraryname))
{
ReportError("Expected library name");
return false;
}
break;
default:
if(processincludes && (token == "#include" || token == "#import"))
{
SkipWhitespace(true);
string includelump = StripTokenQuotes(ReadToken()).ToLowerInvariant();
string includelump = ReadToken(false); // Don't skip newline
if(!string.IsNullOrEmpty(includelump))
if(!includelump.StartsWith("\"") || !includelump.EndsWith("\""))
{
string includename = Path.GetFileName(includelump);
if(includestoskip.Contains(includename) || includes.Contains(includename)) continue;
// Callback to parse this file
if(OnInclude != null) OnInclude(this, includelump.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar));
// Set our buffers back to continue parsing
datastream = localstream;
datareader = localreader;
sourcename = localsourcename;
}
else
{
ReportError("Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": got #include directive without include path!");
ReportError(token + " filename should be quoted");
return false;
}
includelump = StripTokenQuotes(includelump).ToLowerInvariant();
if(string.IsNullOrEmpty(includelump))
{
ReportError("Expected file name to " + token);
return false;
}
string includename = Path.GetFileName(includelump);
// Compiler files?
if(includestoskip.Contains(includename)) continue;
// Already parsed this?
if(includes.Contains(includename))
{
ReportError("already parsed '" + includename + "'. Check your #include directives");
return false;
}
// Callback to parse this file
if(OnInclude != null) OnInclude(this, includelump.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar));
// Set our buffers back to continue parsing
datastream = localstream;
datareader = localreader;
sourcename = localsourcename;
}
break;
}
@ -276,5 +296,10 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
return "(void)";
}
protected override string GetLanguageType()
{
return "ACS";
}
}
}

View file

@ -4,6 +4,7 @@ using CodeImp.DoomBuilder.ZDoom;
using CodeImp.DoomBuilder.GZBuilder.Data;
//mxd. Decorate parser used to create ScriptItems for use in script editor's navigator
//Should be able to parse actor definitions even from invalid DECORATE and should never fail parsing
namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
{
internal sealed class DecorateParserSE : ZDTextParser
@ -21,38 +22,35 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
base.Parse(stream, sourcefilename);
// Continue until at the end of the stream
while (SkipWhitespace(true))
while(SkipWhitespace(true))
{
string token = ReadToken();
if(string.IsNullOrEmpty(token) || token.ToUpperInvariant() != "ACTOR") continue;
if (!string.IsNullOrEmpty(token))
SkipWhitespace(true);
int startpos = (int)stream.Position;
List<string> definition = new List<string>();
do
{
token = token.ToLowerInvariant();
token = ReadToken(false); // Don't skip newline
if(string.IsNullOrEmpty(token) || token == "{" || token == "}") break;
definition.Add(token);
} while(SkipWhitespace(false)); // Don't skip newline
if (token == "actor")
{
SkipWhitespace(true);
int startPos = (int)stream.Position;
List<string> definition = new List<string>();
do
{
token = ReadToken();
if(string.IsNullOrEmpty(token) || token == "{") break;
definition.Add(token);
} while(SkipWhitespace(true));
string name = "";
foreach (string s in definition) name += s + " ";
actors.Add(new ScriptItem(name.TrimEnd(), startPos, false));
}
}
string name = string.Join(" ", definition.ToArray());
if(!string.IsNullOrEmpty(name)) actors.Add(new ScriptItem(name, startpos, false));
}
//sort nodes
// Sort nodes
actors.Sort(ScriptItem.SortByName);
return true;
}
protected override string GetLanguageType()
{
return "DECORATE";
}
}
}

View file

@ -16,7 +16,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
{
internal sealed class GldefsParser : ZDTextParser
{
#region ================== Structs
#region ================== Constants
private const int DEFAULT_GLOW_HEIGHT = 64;
@ -82,12 +82,6 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
public override bool Parse(Stream stream, string sourcefilename)
{
base.Parse(stream, sourcefilename);
if (parsedlumps.IndexOf(sourcefilename) != -1)
{
General.ErrorLogger.Add(ErrorType.Error, "already parsed '" + sourcefilename + "'. Check your #include directives!");
return false;
}
parsedlumps.Add(sourcefilename);
// Keep local data
@ -96,18 +90,17 @@ 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))
if(!string.IsNullOrEmpty(token))
{
token = StripTokenQuotes(token.ToLowerInvariant()); //Quotes can be anywhere! ANYWHERE!!! And GZDoom will still parse data correctly
//got light structure
if (token == GldefsLightType.POINT || token == GldefsLightType.PULSE || token == GldefsLightType.FLICKER
if(token == GldefsLightType.POINT || token == GldefsLightType.PULSE || token == GldefsLightType.FLICKER
|| token == GldefsLightType.FLICKER2 || token == GldefsLightType.SECTOR)
{
bool gotErrors = false;
string lightType = token;
DynamicLightData light = new DynamicLightData();
@ -117,41 +110,39 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
SkipWhitespace(true);
string lightName = StripTokenQuotes(ReadToken()).ToLowerInvariant();
if (!string.IsNullOrEmpty(lightName))
if(!string.IsNullOrEmpty(lightName))
{
//now find opening brace
if(!NextTokenIs("{")) continue;
//read gldefs light structure
while (SkipWhitespace(true))
while(SkipWhitespace(true))
{
token = ReadToken();
if (!string.IsNullOrEmpty(token))
if(!string.IsNullOrEmpty(token))
{
token = token.ToLowerInvariant();
//color
if (token == "color")
if(token == "color")
{
SkipWhitespace(true);
token = StripTokenQuotes(ReadToken());
if (!float.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out light.Color.Red))
if(!float.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out light.Color.Red))
{
// Not numeric!
General.ErrorLogger.Add(ErrorType.Error, "Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected Red Color value, but got '" + token + "'.");
gotErrors = true;
break;
ReportError("expected Red color value, but got '" + token + "'");
return false;
}
SkipWhitespace(true);
token = StripTokenQuotes(ReadToken());
if (!float.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out light.Color.Green))
if(!float.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out light.Color.Green))
{
// Not numeric!
General.ErrorLogger.Add(ErrorType.Error, "Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected Green Color value, but got '" + token + "'.");
gotErrors = true;
break;
ReportError("expected Green color value, but got '" + token + "'");
return false;
}
SkipWhitespace(true);
@ -160,128 +151,118 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
if (!float.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out light.Color.Blue))
{
// Not numeric!
General.ErrorLogger.Add(ErrorType.Error, "Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected Blue Color value, but got '" + token + "'.");
gotErrors = true;
break;
ReportError("expected Blue color value, but got '" + token + "'");
return false;
}
//size
}
else if (token == "size")
else if(token == "size")
{
if (lightType != GldefsLightType.SECTOR)
if(lightType != GldefsLightType.SECTOR)
{
SkipWhitespace(true);
token = StripTokenQuotes(ReadToken());
if (!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out light.PrimaryRadius))
if(!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out light.PrimaryRadius))
{
// Not numeric!
General.ErrorLogger.Add(ErrorType.Error, "Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected Size value, but got '" + token + "'.");
gotErrors = true;
break;
ReportError("expected Size value, but got '" + token + "'");
return false;
}
light.PrimaryRadius *= 2;
}
else
{
General.ErrorLogger.Add(ErrorType.Error, "Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": '" + token + "' is not valid property for " + lightType + ".");
gotErrors = true;
break;
ReportError("'" + token + "' is not valid property for " + lightType + ".");
return false;
}
//offset
}
else if (token == "offset")
else if(token == "offset")
{
SkipWhitespace(true);
token = StripTokenQuotes(ReadToken());
if (!ReadSignedFloat(token, ref light.Offset.X))
if(!ReadSignedFloat(token, ref light.Offset.X))
{
// Not numeric!
General.ErrorLogger.Add(ErrorType.Error, "Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected Offset X value, but got '" + token + "'.");
gotErrors = true;
break;
ReportError("expected Offset X value, but got '" + token + "'");
return false;
}
SkipWhitespace(true);
token = StripTokenQuotes(ReadToken());
if (!ReadSignedFloat(token, ref light.Offset.Z))
if(!ReadSignedFloat(token, ref light.Offset.Z))
{
// Not numeric!
General.ErrorLogger.Add(ErrorType.Error, "Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected Offset Y value, but got '" + token + "'");
gotErrors = true;
break;
ReportError("expected Offset Y value, but got '" + token + "'");
return false;
}
SkipWhitespace(true);
token = StripTokenQuotes(ReadToken());
if (!ReadSignedFloat(token, ref light.Offset.Y))
if(!ReadSignedFloat(token, ref light.Offset.Y))
{
// Not numeric!
General.ErrorLogger.Add(ErrorType.Error, "Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected Offset Z value, but got '" + token + "'.");
gotErrors = true;
break;
ReportError("expected Offset Z value, but got '" + token + "'");
return false;
}
//subtractive
}
else if (token == "subtractive")
else if(token == "subtractive")
{
SkipWhitespace(true);
token = StripTokenQuotes(ReadToken());
int i;
if (!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out i))
if(!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out i))
{
// Not numeric!
General.ErrorLogger.Add(ErrorType.Error, "Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected Subtractive value, but got '" + token + "'.");
gotErrors = true;
break;
ReportError("expected Subtractive value, but got '" + token + "'");
return false;
}
light.Subtractive = i == 1;
//dontlightself
}
else if (token == "dontlightself")
else if(token == "dontlightself")
{
SkipWhitespace(true);
token = StripTokenQuotes(ReadToken());
int i;
if (!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out i))
if(!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out i))
{
// Not numeric!
General.ErrorLogger.Add(ErrorType.Error, "Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected Dontlightself value, but got '" + token + "'.");
gotErrors = true;
break;
ReportError("expected Dontlightself value, but got '" + token + "'");
return false;
}
light.DontLightSelf = (i == 1);
//interval
}
else if (token == "interval")
else if(token == "interval")
{
if (lightType == GldefsLightType.PULSE || lightType == GldefsLightType.FLICKER2)
if(lightType == GldefsLightType.PULSE || lightType == GldefsLightType.FLICKER2)
{
SkipWhitespace(true);
token = StripTokenQuotes(ReadToken());
float interval;
if (!float.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out interval))
if(!float.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out interval))
{
// Not numeric!
General.ErrorLogger.Add(ErrorType.Error, "Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected Interval value, but got '" + token + "'.");
gotErrors = true;
break;
ReportError("expected Interval value, but got '" + token + "'");
return false;
}
if(interval == 0)
General.ErrorLogger.Add(ErrorType.Warning, "Warning in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": Interval value should be greater than zero.");
if(interval == 0) LogWarning("Interval value should be greater than zero");
//I wrote logic for dynamic lights animation first, so here I modify gldefs settings to fit in existing logic
if (lightType == GldefsLightType.PULSE)
if(lightType == GldefsLightType.PULSE)
{
light.Interval = (int)(interval * 35); //measured in tics (35 per second) in PointLightPulse, measured in seconds in gldefs' PulseLight
}
@ -292,50 +273,46 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
}
else
{
General.ErrorLogger.Add(ErrorType.Error, "Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": '" + token + "' is not valid property for " + lightType + ".");
gotErrors = true;
break;
ReportError("'" + token + "' is not valid property for " + lightType);
return false;
}
//secondarysize
}
else if (token == "secondarysize")
else if(token == "secondarysize")
{
if (lightType == GldefsLightType.PULSE || lightType == GldefsLightType.FLICKER || lightType == GldefsLightType.FLICKER2)
if(lightType == GldefsLightType.PULSE || lightType == GldefsLightType.FLICKER || lightType == GldefsLightType.FLICKER2)
{
SkipWhitespace(true);
token = StripTokenQuotes(ReadToken());
if (!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out light.SecondaryRadius))
if(!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out light.SecondaryRadius))
{
// Not numeric!
General.ErrorLogger.Add(ErrorType.Error, "Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected SecondarySize value, but got '" + token + "'.");
gotErrors = true;
break;
ReportError("expected SecondarySize value, but got '" + token + "'");
return false;
}
light.SecondaryRadius *= 2;
}
else
{
General.ErrorLogger.Add(ErrorType.Error, "Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": '" + token + "' is not valid property for " + lightType + ".");
gotErrors = true;
break;
ReportError("'" + token + "' is not valid property for " + lightType);
return false;
}
//chance
}
else if (token == "chance")
else if(token == "chance")
{
if (lightType == GldefsLightType.FLICKER)
if(lightType == GldefsLightType.FLICKER)
{
SkipWhitespace(true);
token = StripTokenQuotes(ReadToken());
float chance;
if (!float.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out chance))
if(!float.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out chance))
{
// Not numeric!
General.ErrorLogger.Add(ErrorType.Error, "Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected Chance value, but got '" + token + "'.");
gotErrors = true;
break;
ReportError("expected Chance value, but got '" + token + "'");
return false;
}
//transforming from 0.0 .. 1.0 to 0 .. 359 to fit in existing logic
@ -343,33 +320,30 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
}
else
{
General.ErrorLogger.Add(ErrorType.Error, "Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": '" + token + "' is not valid property for " + lightType + ".");
gotErrors = true;
break;
ReportError("'" + token + "' is not valid property for " + lightType);
return false;
}
//scale
}
else if (token == "scale")
else if(token == "scale")
{
if (lightType == GldefsLightType.SECTOR)
if(lightType == GldefsLightType.SECTOR)
{
SkipWhitespace(true);
token = StripTokenQuotes(ReadToken());
float scale;
if (!float.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out scale))
if(!float.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out scale))
{
// Not numeric!
General.ErrorLogger.Add(ErrorType.Error, "Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected Scale value, but got '" + token + "'.");
gotErrors = true;
break;
ReportError("expected Scale value, but got '" + token + "'");
return false;
}
if (scale > 1.0f)
if(scale > 1.0f)
{
General.ErrorLogger.Add(ErrorType.Error, "Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": scale must be in 0.0 - 1.0 range, but is " + scale + ".");
gotErrors = true;
break;
ReportError("scale must be in 0.0 - 1.0 range, but is " + scale);
return false;
}
//sector light doesn't have animation, so we will store it's size in Interval
@ -378,64 +352,59 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
}
else
{
General.ErrorLogger.Add(ErrorType.Error, "Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": '" + token + "' is not valid property for " + lightType + ".");
gotErrors = true;
break;
ReportError("'" + token + "' is not valid property for " + lightType);
return false;
}
}
//end of structure
else if (token == "}")
else if(token == "}")
{
if (!gotErrors)
bool skip = false;
//general checks
if(light.Color.Red == 0.0f && light.Color.Green == 0.0f && light.Color.Blue == 0.0f)
{
//general checks
if (light.Color.Red == 0.0f && light.Color.Green == 0.0f && light.Color.Blue == 0.0f)
{
General.ErrorLogger.Add(ErrorType.Warning, "'" + sourcefilename + "', line " + GetCurrentLineNumber() + ": light Color is " + light.Color.Red + "," + light.Color.Green + "," + light.Color.Blue + ". It won't be shown in GZDoom!");
gotErrors = true;
}
LogWarning("'" + lightName + "' light Color is " + light.Color.Red + "," + light.Color.Green + "," + light.Color.Blue + ". It won't be shown in GZDoom");
skip = true;
}
//light-type specific checks
if (light.Type == DynamicLightType.NORMAL && light.PrimaryRadius == 0)
{
General.ErrorLogger.Add(ErrorType.Warning, "'" + sourcefilename + "', line " + GetCurrentLineNumber() + ": light Size is 0. It won't be shown in GZDoom!");
gotErrors = true;
}
//light-type specific checks
if(light.Type == DynamicLightType.NORMAL && light.PrimaryRadius == 0)
{
LogWarning("'" + lightName + "' light Size is 0. It won't be shown in GZDoom");
skip = true;
}
if (light.Type == DynamicLightType.FLICKER || light.Type == DynamicLightType.PULSE || light.Type == DynamicLightType.RANDOM)
if(light.Type == DynamicLightType.FLICKER || light.Type == DynamicLightType.PULSE || light.Type == DynamicLightType.RANDOM)
{
if(light.PrimaryRadius == 0 && light.SecondaryRadius == 0)
{
if (light.PrimaryRadius == 0 && light.SecondaryRadius == 0)
{
General.ErrorLogger.Add(ErrorType.Warning, "'" + sourcefilename + "', line " + GetCurrentLineNumber() + ": 'Size' and 'SecondarySize' are 0. This light won't be shown in GZDoom!");
gotErrors = true;
}
}
//offset it slightly to avoid shading glitches
if (light.Offset.Z == 0.0f) light.Offset.Z = 0.1f;
if (!gotErrors)
{
if (lightsByName.ContainsKey(lightName))
lightsByName[lightName] = light;
else
lightsByName.Add(lightName, light);
LogWarning("'" + lightName + "' light Size and SecondarySize are 0. This light won't be shown in GZDoom");
skip = true;
}
}
break; //break out of this parsing loop
//offset it slightly to avoid shading glitches
if(light.Offset.Z == 0.0f) light.Offset.Z = 0.1f;
// Add to the collection?
if(!skip) lightsByName[lightName] = light;
//break out of this parsing loop
break;
}
}
}
}
}
else if (token == "object")
else if(token == "object")
{
SkipWhitespace(true);
//read object class
string objectClass = StripTokenQuotes(ReadToken()).ToLowerInvariant();
if (!string.IsNullOrEmpty(objectClass))
if(!string.IsNullOrEmpty(objectClass))
{
//now find opening brace
if(!NextTokenIs("{")) continue;
@ -445,10 +414,10 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
bool foundFrame = false;
//read frames structure
while (SkipWhitespace(true))
while(SkipWhitespace(true))
{
token = ReadToken();
if (!string.IsNullOrEmpty(token))
if(!string.IsNullOrEmpty(token))
{
token = StripTokenQuotes(token).ToLowerInvariant();
if(!foundLight && !foundFrame && token == "frame")
@ -464,29 +433,26 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
SkipWhitespace(true);
token = ReadToken().ToLowerInvariant(); //should be light name
if (!string.IsNullOrEmpty(token))
if(!string.IsNullOrEmpty(token))
{
if (lightsByName.ContainsKey(token))
if(lightsByName.ContainsKey(token))
{
if (objects.ContainsKey(objectClass))
objects[objectClass] = token;
else
objects.Add(objectClass, token);
objects[objectClass] = token;
foundLight = true;
}
else
{
General.ErrorLogger.Add(ErrorType.Warning, "Light declaration not found for light '" + token + "' ('" + sourcefilename + "', line " + GetCurrentLineNumber()+").");
LogWarning("Light declaration not found for light '" + token + "'");
}
}
}
else if (token == "{") //continue in this loop until object structure ends
else if(token == "{") //continue in this loop until object structure ends
{
bracesCount++;
}
else if (token == "}")
else if(token == "}")
{
if (--bracesCount < 1) break; //This was Cave Johnson. And we are done here.
if(--bracesCount < 1) break; //This was Cave Johnson. And we are done here.
}
}
}
@ -549,12 +515,12 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
int color;
int glowheight = DEFAULT_GLOW_HEIGHT;
bool subtractivetexture = (token == "subtexture");
string texturename = StripTokenQuotes(ReadToken());
string texturename = StripTokenQuotes(ReadToken(false));
if(string.IsNullOrEmpty(texturename))
{
General.ErrorLogger.Add(ErrorType.Error, "Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected a texture name.");
break;
ReportError("expected " + token + " name");
return false;
}
// Now we should find a comma
@ -574,8 +540,8 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
}
else
{
General.ErrorLogger.Add(ErrorType.Error, "Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected glow color value, but got '" + token + "'.");
break;
ReportError("expected glow color value, but got '" + token + "'");
return false;
}
}
@ -632,8 +598,8 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
if(!fullblack && !fullbright)
{
string expectedflags = (subtractivetexture ? "'fullbright'" : "'fullbright' or 'fullblack'");
General.ErrorLogger.Add(ErrorType.Error, "Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected " + expectedflags + " flag, but got '" + token + "'.");
break;
ReportError("expected " + expectedflags + " flag, but got '" + token + "'");
return false;
}
// Add glow data
@ -655,25 +621,43 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
if(string.IsNullOrEmpty(token) || token == "}") break;
}
}
else if (token == "#include")
else if(token == "#include")
{
SkipWhitespace(true);
string includeLump = StripTokenQuotes(ReadToken()).ToLowerInvariant();
if (!string.IsNullOrEmpty(includeLump))
{
// Callback to parse this file
if (OnInclude != null)
OnInclude(this, includeLump.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar));
string includelump = ReadToken(false); // Don't skip newline
// Set our buffers back to continue parsing
datastream = localstream;
datareader = localreader;
sourcename = localsourcename;
}
else
// Sanity checks
if(!includelump.StartsWith("\"") || !includelump.EndsWith("\""))
{
General.ErrorLogger.Add(ErrorType.Error, "Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": got #include directive with missing or incorrect path: '" + includeLump + "'.");
ReportError("#include filename should be quoted");
return false;
}
includelump = StripTokenQuotes(includelump).ToLowerInvariant();
// More sanity checks
if(string.IsNullOrEmpty(includelump))
{
ReportError("Expected file name to include");
return false;
}
includelump = includelump.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
// Already parsed?
if(parsedlumps.IndexOf(includelump) != -1)
{
ReportError("already parsed '" + includelump + "'. Check your #include directives");
return false;
}
// Callback to parse this file
if(OnInclude != null) OnInclude(this, includelump);
// Set our buffers back to continue parsing
datastream = localstream;
datareader = localreader;
sourcename = localsourcename;
}
else if(token == "$gzdb_skip") //mxd
{
@ -685,21 +669,21 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
string token2;
do
{
if (!SkipWhitespace(true)) break;
if(!SkipWhitespace(true)) break;
token2 = ReadToken();
if (string.IsNullOrEmpty(token2)) break;
if(string.IsNullOrEmpty(token2)) break;
}
while (token2 != "{");
int scopelevel = 1;
do
{
if (!SkipWhitespace(true)) break;
if(!SkipWhitespace(true)) break;
token2 = ReadToken();
if(string.IsNullOrEmpty(token2)) break;
if (token2 == "{") scopelevel++;
if (token2 == "}") scopelevel--;
if(token2 == "{") scopelevel++;
if(token2 == "}") scopelevel--;
}
while (scopelevel > 0);
while(scopelevel > 0);
}
}
}
@ -716,6 +700,11 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
parsedlumps.Clear();
}
protected override string GetLanguageType()
{
return "GLDEFS";
}
#endregion
}
}

View file

@ -28,6 +28,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
private string mapname;
private readonly Dictionary<int, string> spawnnums;
private readonly Dictionary<int, string> doomednums; // <DoomEdNum, <lowercase classname, List of default arguments>>
private readonly HashSet<string> parsedlumps;
#endregion
@ -50,6 +51,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
mapinfo = new MapInfo();
spawnnums = new Dictionary<int, string>();
doomednums = new Dictionary<int, string>();
parsedlumps = new HashSet<string>();
}
#endregion
@ -67,6 +69,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
{
base.Parse(stream, sourcefilename);
this.mapname = mapname.ToLowerInvariant();
parsedlumps.Add(sourcefilename);
while(SkipWhitespace(true))
{
@ -118,30 +121,30 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
int bracelevel = 0;
//search for required keys
while (SkipWhitespace(true))
while(SkipWhitespace(true))
{
token = ReadToken().ToLowerInvariant();
//sky1 or sky2
if (token == "sky1" || token == "sky2")
if(token == "sky1" || token == "sky2")
{
string skyType = token;
SkipWhitespace(true);
token = StripTokenQuotes(ReadToken()).ToLowerInvariant();
//new format
if (token == "=")
if(token == "=")
{
SkipWhitespace(true);
//should be sky texture name
token = StripTokenQuotes(ReadToken());
bool gotComma = (token.IndexOf(",") != -1);
if (gotComma) token = token.Replace(",", "");
if(gotComma) token = token.Replace(",", "");
string skyTexture = StripTokenQuotes(token).ToLowerInvariant();
if (!string.IsNullOrEmpty(skyTexture))
if(!string.IsNullOrEmpty(skyTexture))
{
if (skyType == "sky1")
if(skyType == "sky1")
mapinfo.Sky1 = skyTexture;
else
mapinfo.Sky2 = skyTexture;
@ -150,25 +153,24 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
SkipWhitespace(true);
token = StripTokenQuotes(ReadToken());
if (!gotComma && token == ",")
if(!gotComma && token == ",")
{
gotComma = true;
SkipWhitespace(true);
token = ReadToken();
}
if (gotComma)
if(gotComma)
{
float scrollSpeed = 0;
if (!ReadSignedFloat(token, ref scrollSpeed))
if(!ReadSignedFloat(token, ref scrollSpeed))
{
// Not numeric!
General.ErrorLogger.Add(ErrorType.Warning, "Unexpected token found in '" + sourcename + "' at line " + GetCurrentLineNumber() + ": expected " + skyType + " scroll speed value, but got '" + token + "'");
datastream.Seek(-token.Length - 1, SeekOrigin.Current); //step back and try parsing this token again
continue;
ReportError("expected " + skyType + " scroll speed value, but got '" + token + "'");
return false;
}
if (skyType == "sky1")
if(skyType == "sky1")
mapinfo.Sky1ScrollSpeed = scrollSpeed;
else
mapinfo.Sky2ScrollSpeed = scrollSpeed;
@ -180,17 +182,17 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
}
else
{
datastream.Seek(-token.Length - 1, SeekOrigin.Current); //step back and try parsing this token again
General.ErrorLogger.Add(ErrorType.Error, "Unexpected token found in '" + sourcename + "' at line " + GetCurrentLineNumber() + ": expected " + skyType + " texture name.");
ReportError("expected " + skyType + " texture name");
return false;
}
}
//old format
else
{
//token should be sky1/2 name
if (!string.IsNullOrEmpty(token))
if(!string.IsNullOrEmpty(token))
{
if (skyType == "sky1")
if(skyType == "sky1")
mapinfo.Sky1 = token;
else
mapinfo.Sky2 = token;
@ -200,14 +202,14 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
token = StripTokenQuotes(ReadToken());
float scrollSpeed = 0;
if (!ReadSignedFloat(token, ref scrollSpeed))
if(!ReadSignedFloat(token, ref scrollSpeed))
{
// Not numeric!
datastream.Seek(-token.Length - 1, SeekOrigin.Current); //step back and try parsing this token again
continue;
}
if (skyType == "sky1")
if(skyType == "sky1")
mapinfo.Sky1ScrollSpeed = scrollSpeed;
else
mapinfo.Sky2ScrollSpeed = scrollSpeed;
@ -215,20 +217,20 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
}
else
{
datastream.Seek(-token.Length - 1, SeekOrigin.Current); //step back and try parsing this token again
General.ErrorLogger.Add(ErrorType.Error, "Unexpected token found in '" + sourcename + "' at line " + GetCurrentLineNumber() + ": expected " + skyType + " texture name.");
ReportError("expected " + skyType + " texture name");
return false;
}
}
}
//fade or outsidefog
else if (token == "fade" || token == "outsidefog")
else if(token == "fade" || token == "outsidefog")
{
string fadeType = token;
SkipWhitespace(true);
token = StripTokenQuotes(ReadToken()).ToLowerInvariant();
//new format?
if (token == "=")
if(token == "=")
{
SkipWhitespace(true);
token = ReadToken();
@ -249,18 +251,18 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
}
else //...or not
{
General.ErrorLogger.Add(ErrorType.Error, "Failed to parse " + fadeType + " value from string '" + colorVal + "' in '" + sourcename + "' at line " + GetCurrentLineNumber());
datastream.Seek(-token.Length - 1, SeekOrigin.Current); //step back and try parsing this token again
ReportError("failed to parse " + fadeType + " value from string '" + colorVal + "'");
return false;
}
}
else
{
General.ErrorLogger.Add(ErrorType.Error, "Unexpected token found in '" + sourcename + "' at line " + GetCurrentLineNumber() + ": expected " + fadeType + " color value.");
datastream.Seek(-token.Length - 1, SeekOrigin.Current); //step back and try parsing this token again
ReportError("expected " + fadeType + " color value");
return false;
}
}
//vertwallshade or horizwallshade
else if (token == "vertwallshade" || token == "horizwallshade")
else if(token == "vertwallshade" || token == "horizwallshade")
{
string shadeType = token;
SkipWhitespace(true);
@ -277,9 +279,8 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
if(!ReadSignedInt(token, ref val))
{
// Not numeric!
General.ErrorLogger.Add(ErrorType.Error, "Unexpected token found in '" + sourcename + "' at line " + GetCurrentLineNumber() + ": expected " + shadeType + " value, but got '" + token + "'");
datastream.Seek(-token.Length - 1, SeekOrigin.Current); //step back and try parsing this token again
continue;
ReportError("expected " + shadeType + " value, but got '" + token + "'");
return false;
}
if(shadeType == "vertwallshade")
@ -305,23 +306,22 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
if(!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out val))
{
// Not numeric!
General.ErrorLogger.Add(ErrorType.Error, "Unexpected token found in '" + sourcename + "' at line " + GetCurrentLineNumber() + ": expected " + densityType + " value, but got '" + token + "'");
datastream.Seek(-token.Length - 1, SeekOrigin.Current); //step back and try parsing this token again
continue;
ReportError("expected " + densityType + " value, but got '" + token + "'");
return false;
}
if (densityType == "fogdensity")
if(densityType == "fogdensity")
mapinfo.FogDensity = (int)(1024 * (256.0f / val));
else
mapinfo.OutsideFogDensity = (int)(1024 * (256.0f / val));
}
//doublesky
else if (token == "doublesky")
else if(token == "doublesky")
{
mapinfo.DoubleSky = true;
}
//evenlighting
else if (token == "evenlighting")
else if(token == "evenlighting")
{
mapinfo.EvenLighting = true;
}
@ -331,7 +331,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
mapinfo.SmoothLighting = true;
}
//block end
else if (token == "}")
else if(token == "}")
{
return ParseBlock(token);
}
@ -356,12 +356,13 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
else if(token == "include")
{
SkipWhitespace(true);
string includeLump = StripTokenQuotes(ReadToken()).ToLowerInvariant();
if(!string.IsNullOrEmpty(includeLump))
string includelump = StripTokenQuotes(ReadToken(false)).ToLowerInvariant(); // Don't skip newline
if(!string.IsNullOrEmpty(includelump))
{
// Callback to parse this file
if(OnInclude != null)
OnInclude(this, includeLump.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar));
OnInclude(this, includelump.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar));
// Set our buffers back to continue parsing
datastream = localstream;
@ -370,32 +371,33 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
}
else
{
General.ErrorLogger.Add(ErrorType.Error, "Error in '" + sourcename + "' at line " + GetCurrentLineNumber() + ": got #include directive with missing or incorrect path: '" + includeLump + "'.");
ReportError("got include directive with missing or incorrect path: '" + includelump + "'");
return false;
}
}
else if(token == "gameinfo")
{
if(!NextTokenIs("{")) return true; // Finished with this file
if(!NextTokenIs("{")) return false; // Finished with this file
while(SkipWhitespace(true))
{
token = ReadToken();
if(string.IsNullOrEmpty(token))
{
General.ErrorLogger.Add(ErrorType.Error, "Error while parisng '" + sourcename + "' at line " + GetCurrentLineNumber() + ": failed to find the end of GameInfo block");
return true; // Finished with this file
ReportError("failed to find the end of GameInfo block");
return false; // Finished with this file
}
if(token == "}") break;
if(token == "skyflatname")
{
if(!NextTokenIs("=")) return true; // Finished with this file
if(!NextTokenIs("=")) return false; // Finished with this file
SkipWhitespace(true);
string skyflatname = StripTokenQuotes(ReadToken());
if(string.IsNullOrEmpty(skyflatname))
{
General.ErrorLogger.Add(ErrorType.Error, "Error while parisng '" + sourcename + "' at line " + GetCurrentLineNumber() + ": unable to get SkyFlatName value");
return true; // Finished with this file
ReportError("unable to get SkyFlatName value");
return false; // Finished with this file
}
General.Map.Config.SkyFlatName = skyflatname.ToUpperInvariant();
@ -404,15 +406,15 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
}
else if(token == "doomednums")
{
if(!NextTokenIs("{")) return true; // Finished with this file
if(!NextTokenIs("{")) return false; // Finished with this file
while(SkipWhitespace(true))
{
token = ReadToken();
if(string.IsNullOrEmpty(token))
{
General.ErrorLogger.Add(ErrorType.Error, "Error while parisng '" + sourcename + "' at line " + GetCurrentLineNumber() + ": failed to find the end of DoomEdNums block");
return true; // Finished with this file
ReportError("failed to find the end of DoomEdNums block");
return false; // Finished with this file
}
if(token == "}") break;
@ -421,24 +423,24 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
if(!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out id))
{
// Not numeric!
General.ErrorLogger.Add(ErrorType.Error, "Unexpected token found in '" + sourcename + "' at line " + GetCurrentLineNumber() + ": expected DoomEdNums entry number, but got '" + token + "'");
return true; // Finished with this file
ReportError("expected DoomEdNums entry number, but got '" + token + "'");
return false; // Finished with this file
}
// Then "="
if(!NextTokenIs("=")) return true; // Finished with this file
if(!NextTokenIs("=")) return false; // Finished with this file
// Then actor class
SkipWhitespace(false);
string classname = StripTokenQuotes(ReadToken());
if(string.IsNullOrEmpty(classname))
{
General.ErrorLogger.Add(ErrorType.Error, "Error while parisng '" + sourcename + "' at line " + GetCurrentLineNumber() + ": unable to get DoomEdNums entry class definition");
return true; // Finished with this file
ReportError("unable to get DoomEdNums entry class definition");
return false; // Finished with this file
}
// Possible special and args. We'll skip them
for (int i = 0; i < 6; i++)
for(int i = 0; i < 6; i++)
{
if(!NextTokenIs(",", false)) break;
@ -452,15 +454,15 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
}
else if(token == "spawnnums")
{
if(!NextTokenIs("{")) return true; // Finished with this file
if(!NextTokenIs("{")) return false; // Finished with this file
while (SkipWhitespace(true))
while(SkipWhitespace(true))
{
token = ReadToken();
if(string.IsNullOrEmpty(token))
{
General.ErrorLogger.Add(ErrorType.Error, "Error while parisng '" + sourcename + "' at line " + GetCurrentLineNumber() + ": failed to find the end of SpawnNums block");
return true; // Finished with this file
ReportError("failed to find the end of SpawnNums block");
return false; // Finished with this file
}
if(token == "}") break;
@ -469,20 +471,20 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
if(!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out id))
{
// Not numeric!
General.ErrorLogger.Add(ErrorType.Error, "Unexpected token found in '" + sourcename + "' at line " + GetCurrentLineNumber() + ": expected SpawnNums number, but got '" + token + "'");
return true; // Finished with this file
ReportError("expected SpawnNums number, but got '" + token + "'");
return false; // Finished with this file
}
// Then "="
if(!NextTokenIs("=")) return true; // Finished with this file
if(!NextTokenIs("=")) return false; // Finished with this file
// Then actor class
SkipWhitespace(false);
token = StripTokenQuotes(ReadToken());
if(string.IsNullOrEmpty(token))
{
General.ErrorLogger.Add(ErrorType.Error, "Error while parisng '" + sourcename + "' at line " + GetCurrentLineNumber() + ": unable to get SpawnNums entry class definition");
return true;
ReportError("unable to get SpawnNums entry class definition");
return false;
}
// Add to collection
@ -503,11 +505,11 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
private static bool GetColor(string name, ref Color4 color)
{
if (name == "black") return true;
if(name == "black") return true;
//probably it's a hex color (like FFCC11)?
int ci;
if (int.TryParse(name, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out ci))
if(int.TryParse(name, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out ci))
{
color = new Color4(ci) {Alpha = 1.0f};
return true;
@ -515,7 +517,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
//probably it's a color name?
Color c = Color.FromName(name); //should be similar to C++ color name detection, I suppose
if (c.IsKnownColor)
if(c.IsKnownColor)
{
color = new Color4(c);
return true;
@ -523,6 +525,11 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
return false;
}
protected override string GetLanguageType()
{
return "MAPINFO";
}
#endregion
}
}

View file

@ -10,7 +10,6 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
{
private Dictionary<string, ModelData> entries; //classname, entry
internal Dictionary<string, ModelData> Entries { get { return entries; } }
internal string Source { get { return sourcename; } }
internal ModeldefParser()
{
@ -24,66 +23,88 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
entries = new Dictionary<string, ModelData>(StringComparer.Ordinal);
// Continue until at the end of the stream
while (SkipWhitespace(true))
while(SkipWhitespace(true))
{
string token = ReadToken();
if (!string.IsNullOrEmpty(token))
if(!string.IsNullOrEmpty(token))
{
token = StripTokenQuotes(token).ToLowerInvariant();
if (token == "model") //model structure start
if(token == "model") //model structure start
{
//find classname
SkipWhitespace(true);
string className = StripTokenQuotes(ReadToken(ActorStructure.ACTOR_CLASS_SPECIAL_TOKENS)).ToLowerInvariant();
string displayclassname = StripTokenQuotes(ReadToken(ActorStructure.ACTOR_CLASS_SPECIAL_TOKENS));
string classname = displayclassname.ToLowerInvariant();
if(!string.IsNullOrEmpty(className) && !entries.ContainsKey(className))
if(!string.IsNullOrEmpty(classname) && !entries.ContainsKey(classname))
{
//now find opening brace
SkipWhitespace(true);
token = ReadToken();
if (token != "{")
if(token != "{")
{
General.ErrorLogger.Add(ErrorType.Error, "Unexpected token found in '"+sourcefilename+"' at line "+GetCurrentLineNumber()+": expected '{', but got '" + token + "'");
General.ErrorLogger.Add(ErrorType.Error, "Unexpected token found in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": expected '{', but got '" + token + "'");
continue; //something wrong with modeldef declaration, continue to next one
}
ModeldefStructure mds = new ModeldefStructure();
ModelData mde = mds.Parse(this);
if (mde != null) entries.Add(className, mde);
if(mds.Parse(this, displayclassname) && mds.ModelData != null)
{
entries.Add(classname, mds.ModelData);
}
if(HasError)
{
LogError();
ClearError();
}
// Skip untill current structure end
if(!mds.ParsingFinished)
{
while(SkipWhitespace(true))
{
token = ReadToken();
if(string.IsNullOrEmpty(token) || token == "}") break;
}
}
}
}
else
{
// Unknown structure!
string token2;
if (token != "{")
if(token != "{")
{
do
{
if (!SkipWhitespace(true)) break;
if(!SkipWhitespace(true)) break;
token2 = ReadToken();
if (string.IsNullOrEmpty(token2)) break;
if(string.IsNullOrEmpty(token2)) break;
}
while (token2 != "{");
while(token2 != "{");
}
int scopelevel = 1;
do
{
if (!SkipWhitespace(true)) break;
if(!SkipWhitespace(true)) break;
token2 = ReadToken();
if (string.IsNullOrEmpty(token2)) break;
if (token2 == "{") scopelevel++;
if (token2 == "}") scopelevel--;
if(string.IsNullOrEmpty(token2)) break;
if(token2 == "{") scopelevel++;
if(token2 == "}") scopelevel--;
}
while (scopelevel > 0);
while(scopelevel > 0);
}
}
}
return entries.Count > 0;
}
protected override string GetLanguageType()
{
return "MODELDEF";
}
}
}

View file

@ -1,13 +1,14 @@
#region ================== Namespaces
using System.IO;
using System.Collections.Generic;
using CodeImp.DoomBuilder.ZDoom;
using System.IO;
using CodeImp.DoomBuilder.GZBuilder.Data;
using CodeImp.DoomBuilder.ZDoom;
#endregion
//mxd. Modeldef parser used to create ScriptItems for use in script editor's navigator
//Should be parse model definitions even from invalid MODELDEF and should never fail parsing
namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
{
internal sealed class ModeldefParserSE : ZDTextParser
@ -25,34 +26,39 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
base.Parse(stream, sourcefilename);
// Continue until at the end of the stream
while (SkipWhitespace(true))
while(SkipWhitespace(true))
{
string token = ReadToken();
if(string.IsNullOrEmpty(token) || token.ToUpperInvariant() != "MODEL") continue;
if (!string.IsNullOrEmpty(token))
SkipWhitespace(true);
int startpos = (int)stream.Position;
string modelname = ReadToken();
SkipWhitespace(true);
token = ReadToken(); //this should be "{"
if(token == "{")
{
token = token.ToUpperInvariant();
ScriptItem i = new ScriptItem(modelname, startpos, false);
models.Add(i);
}
if(token == "MODEL")
{
SkipWhitespace(true);
int startPos = (int)stream.Position;
string modelName = ReadToken();
SkipWhitespace(true);
token = ReadToken(); //this should be "{"
if (token == "{")
{
ScriptItem i = new ScriptItem(modelName, startPos, false);
models.Add(i);
}
}
while(SkipWhitespace(true))
{
token = ReadToken();
if(string.IsNullOrEmpty(token) || token == "}") break;
}
}
//sort nodes
// Sort nodes
models.Sort(ScriptItem.SortByName);
return true;
}
protected override string GetLanguageType()
{
return "MODELDEF";
}
}
}

View file

@ -14,8 +14,12 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
internal sealed class ModeldefStructure
{
private const int MAX_MODELS = 4; //maximum models per modeldef entry, zero-based
private bool parsingfinished;
internal ModelData Parse(ModeldefParser parser)
internal ModelData ModelData;
internal bool ParsingFinished { get { return parsingfinished; } }
internal bool Parse(ModeldefParser parser, string classname)
{
#region ================== Vars
@ -35,13 +39,12 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
bool inheritactorroll = false;
string token;
bool gotErrors = false;
bool allParsed = false;
#endregion
//read modeldef structure contents
while(!gotErrors && !allParsed && parser.SkipWhitespace(true))
parsingfinished = false;
while(!parsingfinished && parser.SkipWhitespace(true))
{
token = parser.ReadToken();
if(!string.IsNullOrEmpty(token))
@ -54,11 +57,11 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
case "path":
parser.SkipWhitespace(true);
path = parser.StripTokenQuotes(parser.ReadToken()).Replace("/", "\\");
if(string.IsNullOrEmpty(path))
path = parser.StripTokenQuotes(parser.ReadToken(false)).Replace("/", "\\"); // Don't skip newline
if(string.IsNullOrEmpty(path))
{
General.ErrorLogger.Add(ErrorType.Error, "Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": expected path to model, but got '" + token + "'");
gotErrors = true;
parser.ReportError("expected model path, but got '" + token + "'");
return false;
}
break;
@ -75,47 +78,42 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
if(!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out index))
{
// Not numeric!
General.ErrorLogger.Add(ErrorType.Error, "Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": expected model index, but got '" + token + "'");
gotErrors = true;
break;
parser.ReportError("expected model index, but got '" + token + "'");
return false;
}
if(index >= MAX_MODELS)
{
General.ErrorLogger.Add(ErrorType.Error, "Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": GZDoom doesn't allow more than " + MAX_MODELS + " models per MODELDEF entry!");
gotErrors = true;
break;
parser.ReportError("GZDoom doesn't allow more than " + MAX_MODELS + " models per MODELDEF entry");
return false;
}
parser.SkipWhitespace(true);
//model path
token = parser.StripTokenQuotes(parser.ReadToken()).ToLowerInvariant();
token = parser.StripTokenQuotes(parser.ReadToken(false)).ToLowerInvariant(); // Don't skip newline
if(string.IsNullOrEmpty(token))
{
General.ErrorLogger.Add(ErrorType.Error, "Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": expected model name, but got '" + token + "'");
gotErrors = true;
parser.ReportError("model name required");
return false;
}
else
{
//check extension
string fileExt = Path.GetExtension(token);
if(string.IsNullOrEmpty(fileExt))
{
General.ErrorLogger.Add(ErrorType.Error, "Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": model '" + token + "' won't be loaded. Models without extension are not supported by GZDoom.");
gotErrors = true;
break;
}
if(fileExt != ".md3" && fileExt != ".md2")
{
General.ErrorLogger.Add(ErrorType.Error, "Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": model '" + token + "' won't be loaded. Only MD2 and MD3 models are supported.");
gotErrors = true;
break;
}
//GZDoom allows models with identical modelIndex, it uses the last one encountered
modelNames[index] = Path.Combine(path, token);
//check extension
string fileExt = Path.GetExtension(token);
if(string.IsNullOrEmpty(fileExt))
{
parser.ReportError("model '" + token + "' won't be loaded. Models without extension are not supported by GZDoom");
return false;
}
if(fileExt != ".md3" && fileExt != ".md2")
{
parser.ReportError("model '" + token + "' won't be loaded. Only MD2 and MD3 models are supported");
return false;
}
//GZDoom allows models with identical modelIndex, it uses the last one encountered
modelNames[index] = Path.Combine(path, token);
break;
#endregion
@ -131,42 +129,36 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
if(!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out skinIndex))
{
// Not numeric!
General.ErrorLogger.Add(ErrorType.Error, "Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": expected skin index, but got '" + token + "'");
gotErrors = true;
break;
parser.ReportError("expected skin index, but got '" + token + "'");
return false;
}
if(skinIndex >= MAX_MODELS)
{
General.ErrorLogger.Add(ErrorType.Error, "Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": GZDoom doesn't allow more than " + MAX_MODELS + " skins per MODELDEF entry!");
gotErrors = true;
break;
parser.ReportError("GZDoom doesn't allow more than " + MAX_MODELS + " skins per MODELDEF entry");
return false;
}
parser.SkipWhitespace(true);
//skin path
token = parser.StripTokenQuotes(parser.ReadToken()).ToLowerInvariant();
token = parser.StripTokenQuotes(parser.ReadToken(false)).ToLowerInvariant(); // Don't skip newline
if(string.IsNullOrEmpty(token))
{
General.ErrorLogger.Add(ErrorType.Error, "Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": expected skin name, but got '" + token + "'");
gotErrors = true;
parser.ReportError("skin path required");
return false;
}
else
//check extension
string ext = Path.GetExtension(token);
if(Array.IndexOf(ModelData.SUPPORTED_TEXTURE_EXTENSIONS, ext) == -1)
{
//check extension
string ext = Path.GetExtension(token);
if(Array.IndexOf(TextureData.SUPPORTED_TEXTURE_EXTENSIONS, ext) == -1)
{
General.ErrorLogger.Add(ErrorType.Error, "Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": image format '" + ext + "' is not supported!");
textureNames[skinIndex] = TextureData.INVALID_TEXTURE;
}
else
{
//GZDoom allows skins with identical modelIndex, it uses the last one encountered
textureNames[skinIndex] = Path.Combine(path, token);
}
}
parser.ReportError("image format '" + ext + "' is not supported!");
return false;
}
//GZDoom allows skins with identical modelIndex, it uses the last one encountered
textureNames[skinIndex] = Path.Combine(path, token);
break;
#endregion
@ -179,9 +171,8 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
if(!parser.ReadSignedFloat(token, ref scale.Y))
{
// Not numeric!
General.ErrorLogger.Add(ErrorType.Error, "Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": expected Scale X value, but got '" + token + "'");
gotErrors = true;
break;
parser.ReportError("expected Scale X value, but got '" + token + "'");
return false;
}
parser.SkipWhitespace(true);
@ -189,9 +180,8 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
if(!parser.ReadSignedFloat(token, ref scale.X))
{
// Not numeric!
General.ErrorLogger.Add(ErrorType.Error, "Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": expected Scale Y value, but got '" + token + "'");
gotErrors = true;
break;
parser.ReportError("expected Scale Y value, but got '" + token + "'");
return false;
}
parser.SkipWhitespace(true);
@ -199,8 +189,8 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
if(!parser.ReadSignedFloat(token, ref scale.Z))
{
// Not numeric!
General.ErrorLogger.Add(ErrorType.Error, "Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": expected Scale Z value, but got '" + token + "'");
gotErrors = true;
parser.ReportError("expected Scale Z value, but got '" + token + "'");
return false;
}
break;
@ -214,9 +204,8 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
if(!parser.ReadSignedFloat(token, ref offset.X))
{
// Not numeric!
General.ErrorLogger.Add(ErrorType.Error, "Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": expected Offset X value, but got '" + token + "'");
gotErrors = true;
break;
parser.ReportError("expected Offset X value, but got '" + token + "'");
return false;
}
parser.SkipWhitespace(true);
@ -224,9 +213,8 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
if(!parser.ReadSignedFloat(token, ref offset.Y))
{
// Not numeric!
General.ErrorLogger.Add(ErrorType.Error, "Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": expected Offset Y value, but got '" + token + "'");
gotErrors = true;
break;
parser.ReportError("expected Offset Y value, but got '" + token + "'");
return false;
}
parser.SkipWhitespace(true);
@ -234,8 +222,8 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
if(!parser.ReadSignedFloat(token, ref offset.Z))
{
// Not numeric!
General.ErrorLogger.Add(ErrorType.Error, "Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": expected Offset Z value, but got '" + token + "'");
gotErrors = true;
parser.ReportError("expected Offset Z value, but got '" + token + "'");
return false;
}
break;
@ -249,8 +237,8 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
if(!parser.ReadSignedFloat(token, ref offset.Z))
{
// Not numeric!
General.ErrorLogger.Add(ErrorType.Error, "Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": expected ZOffset value, but got '" + token + "'");
gotErrors = true;
parser.ReportError("expected ZOffset value, but got '" + token + "'");
return false;
}
break;
@ -264,8 +252,8 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
if(!parser.ReadSignedFloat(token, ref angleOffset))
{
// Not numeric!
General.ErrorLogger.Add(ErrorType.Error, "Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": expected AngleOffset value, but got '" + token + "'");
gotErrors = true;
parser.ReportError("expected AngleOffset value, but got '" + token + "'");
return false;
}
break;
@ -279,8 +267,8 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
if(!parser.ReadSignedFloat(token, ref pitchOffset))
{
// Not numeric!
General.ErrorLogger.Add(ErrorType.Error, "Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": expected PitchOffset value, but got '" + token + "'");
gotErrors = true;
parser.ReportError("expected PitchOffset value, but got '" + token + "'");
return false;
}
break;
@ -294,8 +282,8 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
if(!parser.ReadSignedFloat(token, ref rollOffset))
{
// Not numeric!
General.ErrorLogger.Add(ErrorType.Error, "Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": expected RollOffset value, but got '" + token + "'");
gotErrors = true;
parser.ReportError("expected RollOffset value, but got '" + token + "'");
return false;
}
break;
@ -322,8 +310,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
case "frameindex":
case "frame":
//parsed all required fields. if got more than one model - find which one(s) should be displayed
int len = modelNames.GetLength(0);
if(!gotErrors && len > 1)
if(modelNames.GetLength(0) > 1)
{
string spriteLump = null;
string spriteFrame = null;
@ -389,23 +376,20 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
if(!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out modelIndex))
{
// Not numeric!
General.ErrorLogger.Add(ErrorType.Error, "Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": expected model index, but got '" + token + "'");
gotErrors = true;
break;
parser.ReportError("expected model index, but got '" + token + "'");
return false;
}
if(modelIndex >= MAX_MODELS)
{
General.ErrorLogger.Add(ErrorType.Error, "Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": GZDoom doesn't allow more than " + MAX_MODELS + " models per MODELDEF entry!");
gotErrors = true;
break;
parser.ReportError("GZDoom doesn't allow more than " + MAX_MODELS + " models per MODELDEF entry");
return false;
}
if(modelNames[modelIndex] == null)
{
General.ErrorLogger.Add(ErrorType.Error, "Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": got model index, which doesn't correspond to any defined model!");
gotErrors = true;
break;
parser.ReportError("got model index, which doesn't correspond to any defined model");
return false;
}
modelsUsed[modelIndex] = true;
@ -420,9 +404,8 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
if(!parser.ReadSignedInt(token, ref frame))
{
// Not numeric!
General.ErrorLogger.Add(ErrorType.Error, "Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": expected model frame index, but got '" + token + "'");
gotErrors = true;
break;
parser.ReportError("expected model frame index, but got '" + token + "'");
return false;
}
// Skip the model if frame index is -1
@ -434,9 +417,8 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
if(string.IsNullOrEmpty(token))
{
// Missing!
General.ErrorLogger.Add(ErrorType.Error, "Error in " + parser.Source + " at line " + parser.GetCurrentLineNumber() + ": expected model frame name");
gotErrors = true;
break;
parser.ReportError("expected model frame name");
return false;
}
frameNames[modelIndex] = token.ToLowerInvariant();
@ -451,7 +433,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
}
}
allParsed = true;
parsingfinished = true;
break;
#endregion
@ -467,28 +449,38 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
}
// Bail out when got errors or no models are used
if(gotErrors || Array.IndexOf(modelsUsed, true) == -1) return null;
if(Array.IndexOf(modelsUsed, true) == -1)
{
parser.ReportError("no models are used by '" + classname + "'");
return false;
}
// Classname is set in ModeldefParser
ModelData mde = new ModelData();
mde.InheritActorPitch = inheritactorpitch;
mde.InheritActorRoll = inheritactorroll;
ModelData = new ModelData();
ModelData.InheritActorPitch = inheritactorpitch;
ModelData.InheritActorRoll = inheritactorroll;
Matrix moffset = Matrix.Translation(offset.Y, -offset.X, offset.Z); // Things are complicated in GZDoom...
Matrix mrotation = Matrix.RotationY(-Angle2D.DegToRad(rollOffset)) * Matrix.RotationX(-Angle2D.DegToRad(pitchOffset)) * Matrix.RotationZ(Angle2D.DegToRad(angleOffset));
mde.SetTransform(mrotation, moffset, scale);
ModelData.SetTransform(mrotation, moffset, scale);
for(int i = 0; i < modelNames.Length; i++)
{
if(!string.IsNullOrEmpty(modelNames[i]) && modelsUsed[i])
{
mde.TextureNames.Add(string.IsNullOrEmpty(textureNames[i]) ? string.Empty : textureNames[i].ToLowerInvariant());
mde.ModelNames.Add(modelNames[i].ToLowerInvariant());
mde.FrameNames.Add(frameNames[i]);
mde.FrameIndices.Add(frameIndices[i]);
ModelData.TextureNames.Add(string.IsNullOrEmpty(textureNames[i]) ? string.Empty : textureNames[i].ToLowerInvariant());
ModelData.ModelNames.Add(modelNames[i].ToLowerInvariant());
ModelData.FrameNames.Add(frameNames[i]);
ModelData.FrameIndices.Add(frameIndices[i]);
}
}
return (mde.ModelNames.Count > 0 ? mde : null);
if(ModelData.ModelNames.Count == 0)
{
parser.ReportError("'" + classname + "' has no models");
return false;
}
return true;
}
}
}

View file

@ -28,18 +28,18 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
{
string token = ReadToken();
if (!string.IsNullOrEmpty(token))
if(!string.IsNullOrEmpty(token))
{
token = token.ToUpperInvariant();
if (token == "MODEL")
if(token == "MODEL")
{
SkipWhitespace(true);
ReadToken(); //should be model name
SkipWhitespace(true);
token = ReadToken();//should be opening brace
if (token == "{")
if(token == "{")
{
scriptType = ScriptType.MODELDEF;
return true;
@ -55,7 +55,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
SkipWhitespace(true);
token = ReadToken(); //should be opening brace
if (token == "{")
if(token == "{")
{
scriptType = ScriptType.ACS;
return true;
@ -70,7 +70,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
SkipWhitespace(true);
token = ReadToken();
if (token == ":" || token == "{" || token == "REPLACES")
if(token == ":" || token == "{" || token == "REPLACES")
{
scriptType = ScriptType.DECORATE;
return true;
@ -79,7 +79,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
SkipWhitespace(true);
token = ReadToken(); //should be actor name
if (token == "{")
if(token == "{")
{
scriptType = ScriptType.DECORATE;
return true;
@ -90,5 +90,10 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
return false;
}
protected override string GetLanguageType()
{
return "SCRIPT TYPE CHECKER";
}
}
}

View file

@ -148,15 +148,8 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3
//load texture
List<string> errors = new List<string>();
//texture has unsupported extension?
if(mde.TextureNames[i] == TextureData.INVALID_TEXTURE)
{
for(int c = 0; c < result.Meshes.Count; c++)
mde.Model.Textures.Add(General.Map.Data.UnknownTexture3D.Texture);
//texture not defined in MODELDEF?
}
else if(useSkins)
// Texture not defined in MODELDEF?
if(useSkins)
{
//try to use model's own skins
for(int m = 0; m < result.Meshes.Count; m++)
@ -171,7 +164,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3
string path = result.Skins[m].Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
ext = Path.GetExtension(path);
if(Array.IndexOf(TextureData.SUPPORTED_TEXTURE_EXTENSIONS, ext) == -1)
if(Array.IndexOf(ModelData.SUPPORTED_TEXTURE_EXTENSIONS, ext) == -1)
{
mde.Model.Textures.Add(General.Map.Data.UnknownTexture3D.Texture);
errors.Add("image format '" + ext + "' is not supported!");
@ -193,8 +186,9 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3
mde.Model.Textures.Add(t);
}
}
else //try to use texture loaded from MODELDEFS
}
//Try to use texture loaded from MODELDEFS
else
{
Texture t = LoadTexture(containers, mde.TextureNames[i], device);
if(t == null)

View file

@ -81,29 +81,38 @@ namespace CodeImp.DoomBuilder
lock(this)
{
errors.Add(new ErrorItem(type, message));
switch(type)
//mxd. Don't add duplicate messages
if(errors.Count == 0 || message != errors[errors.Count - 1].message || type != errors[errors.Count - 1].type)
{
case ErrorType.Error:
erroradded = true;
prefix = "ERROR: ";
errors.Add(new ErrorItem(type, message));
switch(type)
{
case ErrorType.Error:
erroradded = true;
prefix = "ERROR: ";
#if DEBUG
DebugConsole.WriteLine(DebugMessageType.ERROR, message);
DebugConsole.WriteLine(DebugMessageType.ERROR, message);
#endif
break;
case ErrorType.Warning:
warningadded = true;
prefix = "WARNING: ";
#if DEBUG
DebugConsole.WriteLine(DebugMessageType.WARNING, message);
#endif
break;
}
changed = true;
break;
General.WriteLogLine(prefix + message);
General.MainWindow.SetWarningsCount(errors.Count, erroradded); //mxd
case ErrorType.Warning:
warningadded = true;
prefix = "WARNING: ";
#if DEBUG
DebugConsole.WriteLine(DebugMessageType.WARNING, message);
#endif
break;
}
changed = true;
General.WriteLogLine(prefix + message);
General.MainWindow.SetWarningsCount(errors.Count, erroradded); //mxd
}
//mxd. But still blink the indicator on errors
else if(type == ErrorType.Error)
{
General.MainWindow.SetWarningsCount(errors.Count, true);
}
}
}

View file

@ -1879,10 +1879,12 @@ namespace CodeImp.DoomBuilder
List<CompilerError> compilererrors = UpdateScriptNames();
if(logerrors && compilererrors.Count > 0)
{
//INFO: CompileLump() prepends lumpname with "?" to distinguish between temporary files and files compiled in place
//INFO: also, error.linenumber is zero-based
foreach(CompilerError error in compilererrors)
{
General.ErrorLogger.Add(ErrorType.Error, "ACS error in '" + error.filename
+ (error.linenumber != CompilerError.NO_LINE_NUMBER ? "', line " + error.linenumber : "'")
General.ErrorLogger.Add(ErrorType.Error, "ACS error in '" + (error.filename.StartsWith("?") ? error.filename.Replace("?", "") : error.filename)
+ (error.linenumber != CompilerError.NO_LINE_NUMBER ? "', line " + (error.linenumber + 1) : "'")
+ ". " + error.description + ".");
}
}
@ -1927,15 +1929,18 @@ namespace CodeImp.DoomBuilder
{
// Get script names
AcsParserSE parser = new AcsParserSE { OnInclude = (se, path) => se.Parse(General.Map.Data.LoadFile(path), path, true, true) };
if(parser.Parse(stream, "SCRIPTS", scriptconfig.Compiler.Files, true, false))
//INFO: CompileLump() prepends lumpname with "?" to distinguish between temporary files and files compiled in place
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)
if(parser.HasError)
{
compilererrors.Add(new CompilerError(parser.ErrorDescription, parser.ErrorSource, parser.ErrorLine));
break;

View file

@ -109,7 +109,7 @@ namespace CodeImp.DoomBuilder.ZDoom
{
token = token.ToLowerInvariant();
switch (token)
switch(token)
{
case ":":
// The next token must be the class to inherit from
@ -123,9 +123,6 @@ namespace CodeImp.DoomBuilder.ZDoom
// Find the actor to inherit from
baseclass = parser.GetArchivedActorByName(inheritclass);
//mxd. Does it exist? (We can carry on regardless, so add a warning)
if(baseclass == null) parser.ReportWarning("Parent class '" + inheritclass + "' does not exist");
break;
case "replaces":
@ -171,7 +168,7 @@ namespace CodeImp.DoomBuilder.ZDoom
break;
}
if (done) break; //mxd
if(done) break; //mxd
}
else
{
@ -188,7 +185,7 @@ namespace CodeImp.DoomBuilder.ZDoom
string token = parser.ReadToken();
token = token.ToLowerInvariant();
switch (token)
switch(token)
{
case "+":
case "-":
@ -196,7 +193,7 @@ namespace CodeImp.DoomBuilder.ZDoom
bool flagvalue = (token == "+");
parser.SkipWhitespace(true);
string flagname = parser.ReadToken();
if (!string.IsNullOrEmpty(flagname))
if(!string.IsNullOrEmpty(flagname))
{
// Add the flag with its value
flagname = flagname.ToLowerInvariant();
@ -212,10 +209,10 @@ namespace CodeImp.DoomBuilder.ZDoom
case "action":
case "native":
// We don't need this, ignore up to the first next ;
while (parser.SkipWhitespace(true))
while(parser.SkipWhitespace(true))
{
string t = parser.ReadToken();
if (string.IsNullOrEmpty(t) || t == ";") break;
if(string.IsNullOrEmpty(t) || t == ";") break;
}
break;
@ -225,31 +222,31 @@ namespace CodeImp.DoomBuilder.ZDoom
case "states":
// Now parse actor states until we reach the end of the states structure
while (parser.SkipWhitespace(true))
while(parser.SkipWhitespace(true))
{
string statetoken = parser.ReadToken();
if (!string.IsNullOrEmpty(statetoken))
if(!string.IsNullOrEmpty(statetoken))
{
// Start of scope?
if (statetoken == "{")
if(statetoken == "{")
{
// This is fine
}
// End of scope?
else if (statetoken == "}")
else if(statetoken == "}")
{
// Done with the states,
// break out of this parse loop
break;
}
// State label?
else if (statetoken == ":")
else if(statetoken == ":")
{
if (!string.IsNullOrEmpty(previoustoken))
if(!string.IsNullOrEmpty(previoustoken))
{
// Parse actor state
StateStructure st = new StateStructure(this, parser);
if (parser.HasError) return;
if(parser.HasError) return;
states[previoustoken.ToLowerInvariant()] = st;
}
else
@ -273,11 +270,11 @@ namespace CodeImp.DoomBuilder.ZDoom
break;
case "var": //mxd
while (parser.SkipWhitespace(true))
while(parser.SkipWhitespace(true))
{
string t = parser.ReadToken();
if (string.IsNullOrEmpty(t) || t == ";") break;
if (t.StartsWith("user_") && !userVars.Contains(t))
if(string.IsNullOrEmpty(t) || t == ";") break;
if(t.StartsWith("user_") && !userVars.Contains(t))
userVars.Add(t);
}
break;
@ -323,17 +320,17 @@ namespace CodeImp.DoomBuilder.ZDoom
case "game":
// Include all tokens on the same line
List<string> games = new List<string>();
while (parser.SkipWhitespace(false))
while(parser.SkipWhitespace(false))
{
string v = parser.ReadToken();
if (string.IsNullOrEmpty(v))
if(string.IsNullOrEmpty(v))
{
parser.ReportError("Unexpected end of structure");
return;
}
if (v == "\n") break;
if (v == "}") return; //mxd
if (v != ",") games.Add(v.ToLowerInvariant());
if(v == "\n") break;
if(v == "}") return; //mxd
if(v != ",") games.Add(v.ToLowerInvariant());
}
props[token] = games;
break;
@ -341,7 +338,7 @@ namespace CodeImp.DoomBuilder.ZDoom
// Property
default:
// Property begins with $? Then the whole line is a single value
if (token.StartsWith("$"))
if(token.StartsWith("$"))
{
// This is for editor-only properties such as $sprite and $category
props[token] = new List<string> { (parser.SkipWhitespace(false) ? parser.ReadLine() : "") };
@ -350,17 +347,17 @@ namespace CodeImp.DoomBuilder.ZDoom
{
// Next tokens up until the next newline are values
List<string> values = new List<string>();
while (parser.SkipWhitespace(false))
while(parser.SkipWhitespace(false))
{
string v = parser.ReadToken();
if (string.IsNullOrEmpty(v))
if(string.IsNullOrEmpty(v))
{
parser.ReportError("Unexpected end of structure");
return;
}
if (v == "\n") break;
if (v == "}") return; //mxd
if (v != ",") values.Add(v);
if(v == "\n") break;
if(v == "}") return; //mxd
if(v != ",") values.Add(v);
}
//mxd. Translate scale to xscale and yscale
@ -377,7 +374,7 @@ namespace CodeImp.DoomBuilder.ZDoom
break;
}
if (done) break; //mxd
if(done) break; //mxd
// Keep token
previoustoken = token;
@ -407,16 +404,16 @@ namespace CodeImp.DoomBuilder.ZDoom
//properties
if(!props.ContainsKey("height"))
props["height"] = new List<string>() { ti.Value.Height.ToString() };
props["height"] = new List<string> { ti.Value.Height.ToString() };
if(!props.ContainsKey("radius"))
props["radius"] = new List<string>() { ti.Value.Radius.ToString() };
props["radius"] = new List<string> { ti.Value.Radius.ToString() };
return;
}
}
General.ErrorLogger.Add(ErrorType.Warning, "Unable to find the DECORATE class '" + inheritclass + "' to inherit from, while parsing '" + classname + ":" + doomednum + "'");
parser.LogWarning("Unable to find '" + inheritclass + "' class to inherit from, while parsing '" + classname + ":" + doomednum + "'");
}
}
@ -438,12 +435,9 @@ namespace CodeImp.DoomBuilder.ZDoom
/// </summary>
public bool HasProperty(string propname)
{
if(props.ContainsKey(propname))
return true;
else if(!skipsuper && (baseclass != null))
return baseclass.HasProperty(propname);
else
return false;
if(props.ContainsKey(propname)) return true;
if(!skipsuper && (baseclass != null)) return baseclass.HasProperty(propname);
return false;
}
/// <summary>
@ -451,12 +445,9 @@ namespace CodeImp.DoomBuilder.ZDoom
/// </summary>
public bool HasPropertyWithValue(string propname)
{
if(props.ContainsKey(propname) && (props[propname].Count > 0))
return true;
else if(!skipsuper && (baseclass != null))
return baseclass.HasPropertyWithValue(propname);
else
return false;
if(props.ContainsKey(propname) && (props[propname].Count > 0)) return true;
if(!skipsuper && (baseclass != null)) return baseclass.HasPropertyWithValue(propname);
return false;
}
/// <summary>
@ -466,10 +457,9 @@ namespace CodeImp.DoomBuilder.ZDoom
{
if(props.ContainsKey(propname) && (props[propname].Count > 0))
return string.Join(" ", props[propname].ToArray());
else if(!skipsuper && (baseclass != null))
if(!skipsuper && (baseclass != null))
return baseclass.GetPropertyAllValues(propname);
else
return "";
return "";
}
/// <summary>
@ -479,10 +469,9 @@ namespace CodeImp.DoomBuilder.ZDoom
{
if(props.ContainsKey(propname) && (props[propname].Count > valueindex))
return props[propname][valueindex];
else if(!skipsuper && (baseclass != null))
if(!skipsuper && (baseclass != null))
return baseclass.GetPropertyValueString(propname, valueindex);
else
return "";
return "";
}
/// <summary>
@ -524,10 +513,8 @@ namespace CodeImp.DoomBuilder.ZDoom
/// </summary>
public bool HasFlagValue(string flag)
{
if(flags.ContainsKey(flag))
return true;
if(!skipsuper && (baseclass != null))
return baseclass.HasFlagValue(flag);
if(flags.ContainsKey(flag)) return true;
if(!skipsuper && (baseclass != null)) return baseclass.HasFlagValue(flag);
return false;
}
@ -536,10 +523,8 @@ namespace CodeImp.DoomBuilder.ZDoom
/// </summary>
public bool GetFlagValue(string flag, bool defaultvalue)
{
if(flags.ContainsKey(flag))
return flags[flag];
if(!skipsuper && (baseclass != null))
return baseclass.GetFlagValue(flag, defaultvalue);
if(flags.ContainsKey(flag)) return flags[flag];
if(!skipsuper && (baseclass != null)) return baseclass.GetFlagValue(flag, defaultvalue);
return defaultvalue;
}
@ -548,10 +533,8 @@ namespace CodeImp.DoomBuilder.ZDoom
/// </summary>
public bool HasState(string statename)
{
if(states.ContainsKey(statename))
return true;
if(!skipsuper && (baseclass != null))
return baseclass.HasState(statename);
if(states.ContainsKey(statename)) return true;
if(!skipsuper && (baseclass != null)) return baseclass.HasState(statename);
return false;
}
@ -560,10 +543,8 @@ namespace CodeImp.DoomBuilder.ZDoom
/// </summary>
public StateStructure GetState(string statename)
{
if(states.ContainsKey(statename))
return states[statename];
if(!skipsuper && (baseclass != null))
return baseclass.GetState(statename);
if(states.ContainsKey(statename)) return states[statename];
if(!skipsuper && (baseclass != null)) return baseclass.GetState(statename);
return null;
}
@ -734,7 +715,7 @@ namespace CodeImp.DoomBuilder.ZDoom
if(!string.IsNullOrEmpty(result))
{
if (voxels.ContainsKey(result)) return result;
if(voxels.ContainsKey(result)) return result;
// The sprite name may be incomplete. Find an existing sprite with direction.
foreach(string postfix in SPRITE_POSTFIXES)

View file

@ -119,42 +119,56 @@ namespace CodeImp.DoomBuilder.ZDoom
if(!string.IsNullOrEmpty(objdeclaration))
{
objdeclaration = objdeclaration.ToLowerInvariant();
if(objdeclaration == "actor")
switch(objdeclaration)
{
// Read actor structure
ActorStructure actor = new ActorStructure(this);
if(this.HasError) break;
// Add the actor
archivedactors[actor.ClassName.ToLowerInvariant()] = actor;
if(actor.CheckActorSupported())
actors[actor.ClassName.ToLowerInvariant()] = actor;
// Replace an actor?
if(actor.ReplacesClass != null)
case "actor":
{
if(GetArchivedActorByName(actor.ReplacesClass) != null)
archivedactors[actor.ReplacesClass.ToLowerInvariant()] = actor;
else
General.ErrorLogger.Add(ErrorType.Warning, "Unable to find the DECORATE class '" + actor.ReplacesClass + "' to replace, while parsing '" + actor.ClassName + "'");
// Read actor structure
ActorStructure actor = new ActorStructure(this);
if(this.HasError) return false;
// Add the actor
archivedactors[actor.ClassName.ToLowerInvariant()] = actor;
if(actor.CheckActorSupported())
actors[actor.ClassName.ToLowerInvariant()] = actor;
// Replace an actor?
if(actor.ReplacesClass != null)
{
if(GetActorByName(actor.ReplacesClass) != null)
if(GetArchivedActorByName(actor.ReplacesClass) != null)
archivedactors[actor.ReplacesClass.ToLowerInvariant()] = actor;
else
LogWarning("Unable to find '" + actor.ReplacesClass + "' class to replace, while parsing '" + actor.ClassName + "'");
if(actor.CheckActorSupported() && GetActorByName(actor.ReplacesClass) != null)
actors[actor.ReplacesClass.ToLowerInvariant()] = actor;
}
}
}
else if(objdeclaration == "#include")
{
// Include a file
SkipWhitespace(true);
string filename = ReadToken();
if(!string.IsNullOrEmpty(filename))
break;
case "#include":
{
// Include a file
SkipWhitespace(true);
string filename = ReadToken(false); //mxd. Don't skip newline
//mxd. Sanity checks
if(!filename.StartsWith("\"") || !filename.EndsWith("\""))
{
ReportError("#include filename should be quoted");
return false;
}
// Strip the quotes
filename = filename.Replace("\"", "");
//mxd. More sanity checks
if(string.IsNullOrEmpty(filename))
{
ReportError("Expected file name to include");
return false;
}
// Callback to parse this file now
if(OnInclude != null) OnInclude(this, filename);
@ -162,50 +176,48 @@ namespace CodeImp.DoomBuilder.ZDoom
datastream = localstream;
datareader = localreader;
sourcename = localsourcename;
if(HasError) break;
if(this.HasError) return false;
}
else
{
ReportError("Expected file name to include");
break;
}
}
else if((objdeclaration == "const") || (objdeclaration == "native") || (objdeclaration == "enum"))
{
// We don't need this, ignore up to the first next ;
while(SkipWhitespace(true))
{
string t = ReadToken();
if(string.IsNullOrEmpty(t) || t == ";") break;
}
}
else if(objdeclaration == "$gzdb_skip") //mxd
{
break;
}
else
{
// Unknown structure!
// Best we can do now is just find the first { and then
// follow the scopes until the matching } is found
string token2;
do
case "enum":
case "native":
case "const":
while(SkipWhitespace(true))
{
string t = ReadToken();
if(string.IsNullOrEmpty(t) || t == ";") break;
}
break;
case "$gzdb_skip": break;
default:
{
if(!SkipWhitespace(true)) break;
token2 = ReadToken();
if(string.IsNullOrEmpty(token2)) break;
// Unknown structure!
// Best we can do now is just find the first { and then
// follow the scopes until the matching } is found
string token2;
do
{
if(!SkipWhitespace(true)) break;
token2 = ReadToken();
if(string.IsNullOrEmpty(token2)) break;
}
while(token2 != "{");
int scopelevel = 1;
do
{
if(!SkipWhitespace(true)) break;
token2 = ReadToken();
if(string.IsNullOrEmpty(token2)) break;
if(token2 == "{") scopelevel++;
if(token2 == "}") scopelevel--;
}
while(scopelevel > 0);
}
while(token2 != "{");
int scopelevel = 1;
do
{
if(!SkipWhitespace(true)) break;
token2 = ReadToken();
if(string.IsNullOrEmpty(token2)) break;
if(token2 == "{") scopelevel++;
if(token2 == "}") scopelevel--;
}
while(scopelevel > 0);
break;
}
}
}
@ -224,10 +236,7 @@ namespace CodeImp.DoomBuilder.ZDoom
public ActorStructure GetActorByName(string name)
{
name = name.ToLowerInvariant();
if(actors.ContainsKey(name))
return actors[name];
else
return null;
return actors.ContainsKey(name) ? actors[name] : null;
}
/// <summary>
@ -235,12 +244,8 @@ namespace CodeImp.DoomBuilder.ZDoom
/// </summary>
public ActorStructure GetActorByDoomEdNum(int doomednum)
{
ICollection<ActorStructure> collection = actors.Values;
foreach(ActorStructure a in collection)
{
if(a.DoomEdNum == doomednum)
return a;
}
foreach(ActorStructure a in actors.Values)
if(a.DoomEdNum == doomednum) return a;
return null;
}
@ -251,6 +256,12 @@ namespace CodeImp.DoomBuilder.ZDoom
name = name.ToLowerInvariant();
return (archivedactors.ContainsKey(name) ? archivedactors[name] : null);
}
//mxd
protected override string GetLanguageType()
{
return "DECORATE";
}
#endregion
}

View file

@ -83,7 +83,7 @@ namespace CodeImp.DoomBuilder.ZDoom
// First token is the class name
parser.SkipWhitespace(true);
name = parser.StripTokenQuotes(parser.ReadToken());
name = parser.StripTokenQuotes(parser.ReadToken(false)); //mxd. Don't skip newline
if(string.IsNullOrEmpty(name))
{
parser.ReportError("Expected patch name");
@ -163,36 +163,36 @@ namespace CodeImp.DoomBuilder.ZDoom
break;
case "rotate":
if (!ReadTokenInt(parser, token, out rotation)) return;
if(!ReadTokenInt(parser, token, out rotation)) return;
rotation = rotation % 360; //Coalesce multiples
if (rotation < 0) rotation += 360; //Force positive
if(rotation < 0) rotation += 360; //Force positive
if (rotation != 0 && rotation != 90 && rotation != 180 && rotation != 270)
if(rotation != 0 && rotation != 90 && rotation != 180 && rotation != 270)
{
General.ErrorLogger.Add(ErrorType.Warning, "Got unsupported rotation (" + rotation + ") in patch " + name);
parser.LogWarning("Got unsupported rotation (" + rotation + ") in patch '" + name + "'");
rotation = 0;
}
break;
case "style": //mxd
string s;
if (!ReadTokenString(parser, token, out s)) return;
if(!ReadTokenString(parser, token, out s)) return;
int index = Array.IndexOf(renderStyles, s.ToLowerInvariant());
renderStyle = index == -1 ? TexturePathRenderStyle.Copy : (TexturePathRenderStyle) index;
break;
case "blend": //mxd
int val;
if (!ReadTokenColor(parser, token, out val)) return;
if(!ReadTokenColor(parser, token, out val)) return;
blendColor = PixelColor.FromInt(val);
parser.SkipWhitespace(false);
token = parser.ReadToken();
if (token == ",") //read tint ammount
if(token == ",") //read tint ammount
{
parser.SkipWhitespace(false);
if (!ReadTokenFloat(parser, token, out tintAmmount)) return;
if(!ReadTokenFloat(parser, token, out tintAmmount)) return;
tintAmmount = General.Clamp(tintAmmount, 0.0f, 1.0f);
blendStyle = TexturePathBlendStyle.Tint;
}
@ -278,6 +278,7 @@ namespace CodeImp.DoomBuilder.ZDoom
parser.ReportError("Expected a value for property '" + propertyname + "'");
return false;
}
return true;
}
@ -306,7 +307,8 @@ namespace CodeImp.DoomBuilder.ZDoom
{
parser.ReportError("Expected color value for property '" + propertyname + "'");
return false;
}
}
return true;
}

View file

@ -47,7 +47,7 @@ namespace CodeImp.DoomBuilder.ZDoom
if(string.IsNullOrEmpty(name))
{
ReportError("Got empty sound environment name!");
ReportError("Got empty sound environment name");
break;
}
@ -57,7 +57,7 @@ namespace CodeImp.DoomBuilder.ZDoom
int arg1;
if(!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out arg1))
{
ReportError("Failed to parse the first part of '" + name + "' sound environment ID!");
ReportError("Failed to parse the first part of '" + name + "' sound environment ID");
break;
}
@ -67,7 +67,7 @@ namespace CodeImp.DoomBuilder.ZDoom
int arg2;
if(!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out arg2))
{
ReportError("Failed to parse the second part of '" + name + "' sound environment ID!");
ReportError("Failed to parse the second part of '" + name + "' sound environment ID");
break;
}
@ -75,7 +75,7 @@ namespace CodeImp.DoomBuilder.ZDoom
int combinedindex = combinedargs.IndexOf(combined);
if(combinedindex != -1)
{
General.ErrorLogger.Add(ErrorType.Warning, "'" + names[combinedindex] + "' and '" + name + "' sound environments share the same ID (" + arg1 + " " + arg2 + ")!");
LogWarning("'" + names[combinedindex] + "' and '" + name + "' sound environments share the same ID (" + arg1 + " " + arg2 + ")");
}
else
{
@ -84,7 +84,7 @@ namespace CodeImp.DoomBuilder.ZDoom
// Add to collections
if(names.Contains(name))
{
General.ErrorLogger.Add(ErrorType.Warning, "'" + name + "' sound environment is double-defined in '" + sourcefilename + "'!");
LogWarning("'" + name + "' sound environment is double-defined in '" + sourcefilename + "'");
int index = names.IndexOf(name);
firstargs[index] = arg1;
secondargs[index] = arg2;
@ -119,5 +119,10 @@ namespace CodeImp.DoomBuilder.ZDoom
return result;
}
protected override string GetLanguageType()
{
return "REVERBS";
}
}
}

View file

@ -86,6 +86,11 @@ namespace CodeImp.DoomBuilder.ZDoom
return result;
}
protected override string GetLanguageType()
{
return "SNDSEQ";
}
#endregion
}
}

View file

@ -32,9 +32,9 @@ namespace CodeImp.DoomBuilder.ZDoom
#region ================== Variables
// All we care about is the first sprite in the sequence
private List<string> sprites;
private StateGoto gotostate;
private DecorateParser parser;
private readonly List<string> sprites;
private readonly StateGoto gotostate;
private readonly DecorateParser parser;
#endregion
@ -77,20 +77,21 @@ namespace CodeImp.DoomBuilder.ZDoom
else if(token == ":")
{
// Rewind so that this label can be read again
parser.DataStream.Seek(-(lasttoken.Length + 1), SeekOrigin.Current);
if(!string.IsNullOrEmpty(lasttoken))
parser.DataStream.Seek(-(lasttoken.Length + 1), SeekOrigin.Current);
// Done here
return;
}
//mxd. Start of inner scope?
else if (token == "{")
else if(token == "{")
{
int bracelevel = 1;
while(!string.IsNullOrEmpty(token) && bracelevel > 0)
{
parser.SkipWhitespace(false);
token = parser.ReadToken();
switch (token)
switch(token)
{
case "{": bracelevel++; break;
case "}": bracelevel--; break;
@ -143,7 +144,7 @@ namespace CodeImp.DoomBuilder.ZDoom
spritename = spritename.ToUpperInvariant();
// Ignore some odd ZDoom things
if (!spritename.StartsWith("TNT1") && !spritename.StartsWith("----") && !spritename.Contains("#"))
if(!spritename.StartsWith("TNT1") && !spritename.StartsWith("----") && !spritename.Contains("#"))
sprites.Add(spritename);
}
@ -202,10 +203,7 @@ namespace CodeImp.DoomBuilder.ZDoom
private string GetSprite(int index, List<StateStructure> prevstates)
{
// If we have sprite of our own, see if we can return this index
if(index < sprites.Count)
{
return sprites[index];
}
if(index < sprites.Count) return sprites[index];
// Otherwise, continue searching where goto tells us to go
if(gotostate != null)

View file

@ -84,20 +84,20 @@ namespace CodeImp.DoomBuilder.ZDoom
// There should be 3 tokens separated by 2 commas now:
// Name, Width, Height
// First token is the class name
// First token is the texture name
parser.SkipWhitespace(true);
name = parser.StripTokenQuotes(parser.ReadToken());
name = parser.StripTokenQuotes(parser.ReadToken(false)); //mxd. Don't skip newline
//mxd. It can also be "optional" keyword.
if(name.ToLowerInvariant() == "optional")
{
parser.SkipWhitespace(true);
name = parser.StripTokenQuotes(parser.ReadToken());
name = parser.StripTokenQuotes(parser.ReadToken(false)); //mxd. Don't skip newline
}
if(string.IsNullOrEmpty(name))
{
parser.ReportError("Expected texture or sprite name");
parser.ReportError("Expected " + typename + " name");
return;
}
@ -153,14 +153,14 @@ namespace CodeImp.DoomBuilder.ZDoom
string token = parser.ReadToken();
token = token.ToLowerInvariant();
switch (token)
switch(token)
{
case "xscale":
if (!ReadTokenFloat(parser, token, out xscale)) return;
if(!ReadTokenFloat(parser, token, out xscale)) return;
break;
case "yscale":
if (!ReadTokenFloat(parser, token, out yscale)) return;
if(!ReadTokenFloat(parser, token, out yscale)) return;
break;
case "worldpanning":
@ -169,25 +169,25 @@ namespace CodeImp.DoomBuilder.ZDoom
case "offset":
// Read x offset
if (!ReadTokenInt(parser, token, out xoffset)) return;
if(!ReadTokenInt(parser, token, out xoffset)) return;
// Now we should find a comma
parser.SkipWhitespace(true);
tokenstr = parser.ReadToken();
if (tokenstr != ",")
if(tokenstr != ",")
{
parser.ReportError("Expected a comma");
return;
}
// Read y offset
if (!ReadTokenInt(parser, token, out yoffset)) return;
if(!ReadTokenInt(parser, token, out yoffset)) return;
break;
case "patch":
// Read patch structure
PatchStructure pt = new PatchStructure(parser);
if (parser.HasError) break;
if(parser.HasError) break;
//mxd. Let's ignore TNT1A0
if(pt.Name == IGNORE_SPRITE) break;

View file

@ -46,9 +46,9 @@ namespace CodeImp.DoomBuilder.ZDoom
#region ================== Properties
public ICollection<TextureStructure> Textures { get { return textures.Values; } }
public ICollection<TextureStructure> Flats { get { return flats.Values; } }
public ICollection<TextureStructure> Sprites { get { return sprites.Values; } }
public IEnumerable<TextureStructure> Textures { get { return textures.Values; } }
public IEnumerable<TextureStructure> Flats { get { return flats.Values; } }
public IEnumerable<TextureStructure> Sprites { get { return sprites.Values; } }
#endregion
@ -89,104 +89,139 @@ namespace CodeImp.DoomBuilder.ZDoom
if(!string.IsNullOrEmpty(objdeclaration))
{
objdeclaration = objdeclaration.ToLowerInvariant();
if(objdeclaration == "texture")
switch(objdeclaration)
{
// Read texture structure
TextureStructure tx = new TextureStructure(this, "texture", virtualpath);
if(this.HasError) break;
case "texture":
{
// Read texture structure
TextureStructure tx = new TextureStructure(this, "texture", virtualpath);
if(this.HasError) return false;
// if a limit for the texture name length is set make sure that it's not exceeded
if(tx.Name.Length > General.Map.Config.MaxTextureNameLength)
{
ReportError("Texture name \"" + tx.Name + "\" too long. Texture names must have a length of " + General.Map.Config.MaxTextureNameLength + " characters or less");
return false;
}
//mxd. Can't load image without name
if(string.IsNullOrEmpty(tx.Name))
{
ReportError("Can't load an unnamed texture. Please consider giving names to your resources.");
return false;
}
// if a limit for the texture name length is set make sure that it's not exceeded
if(tx.Name.Length > General.Map.Config.MaxTextureNameLength)
{
General.ErrorLogger.Add(ErrorType.Error, "Texture name \"" + tx.Name + "\" too long. Texture names must have a length of " + General.Map.Config.MaxTextureNameLength + " characters or less");
}
else
{
// Add the texture
textures[tx.Name] = tx;
if(!General.Map.Config.MixTexturesFlats) flats[tx.Name] = tx; //mxd. If MixTexturesFlats is set, textures and flats will be mixed in DataManager anyway
}
}
else if(objdeclaration == "sprite")
{
// Read sprite structure
TextureStructure tx = new TextureStructure(this, "sprite", virtualpath);
if(this.HasError) break;
break;
// if a limit for the sprite name length is set make sure that it's not exceeded
if(tx.Name.Length > DataManager.CLASIC_IMAGE_NAME_LENGTH)
{
General.ErrorLogger.Add(ErrorType.Error, "Sprite name \"" + tx.Name + "\" too long. Sprite names must have a length of " + DataManager.CLASIC_IMAGE_NAME_LENGTH + " characters or less");
}
else
case "sprite":
{
// Read sprite structure
TextureStructure tx = new TextureStructure(this, "sprite", virtualpath);
if(this.HasError) return false;
// if a limit for the sprite name length is set make sure that it's not exceeded
if(tx.Name.Length > DataManager.CLASIC_IMAGE_NAME_LENGTH)
{
ReportError("Sprite name \"" + tx.Name + "\" too long. Sprite names must have a length of " + DataManager.CLASIC_IMAGE_NAME_LENGTH + " characters or less");
return false;
}
//mxd. Can't load image without name
if(string.IsNullOrEmpty(tx.Name))
{
ReportError("Can't load an unnamed sprite. Please consider giving names to your resources.");
return false;
}
// Add the sprite
sprites[tx.Name] = tx;
}
}
else if(objdeclaration == "walltexture")
{
// Read walltexture structure
TextureStructure tx = new TextureStructure(this, "walltexture", virtualpath);
if(this.HasError) break;
break;
// if a limit for the walltexture name length is set make sure that it's not exceeded
if(tx.Name.Length > General.Map.Config.MaxTextureNameLength)
{
General.ErrorLogger.Add(ErrorType.Error, "WallTexture name \"" + tx.Name + "\" too long. WallTexture names must have a length of " + General.Map.Config.MaxTextureNameLength + " characters or less");
}
else
case "walltexture":
{
// Read walltexture structure
TextureStructure tx = new TextureStructure(this, "walltexture", virtualpath);
if(this.HasError) return false;
// if a limit for the walltexture name length is set make sure that it's not exceeded
if(tx.Name.Length > General.Map.Config.MaxTextureNameLength)
{
ReportError("WallTexture name \"" + tx.Name + "\" too long. WallTexture names must have a length of " + General.Map.Config.MaxTextureNameLength + " characters or less");
return false;
}
//mxd. Can't load image without name
if(string.IsNullOrEmpty(tx.Name))
{
ReportError("Can't load an unnamed WallTexture. Please consider giving names to your resources.");
return false;
}
// Add the walltexture
if(!textures.ContainsKey(tx.Name) || (textures[tx.Name].TypeName != "texture"))
textures[tx.Name] = tx;
}
}
else if(objdeclaration == "flat")
{
// Read flat structure
TextureStructure tx = new TextureStructure(this, "flat", virtualpath);
if(this.HasError) break;
break;
// if a limit for the flat name length is set make sure that it's not exceeded
if(tx.Name.Length > General.Map.Config.MaxTextureNameLength)
{
General.ErrorLogger.Add(ErrorType.Error, "Flat name \"" + tx.Name + "\" too long. Flat names must have a length of " + General.Map.Config.MaxTextureNameLength + " characters or less");
}
else
case "flat":
{
// Read flat structure
TextureStructure tx = new TextureStructure(this, "flat", virtualpath);
if(this.HasError) return false;
// if a limit for the flat name length is set make sure that it's not exceeded
if(tx.Name.Length > General.Map.Config.MaxTextureNameLength)
{
ReportError("Flat name \"" + tx.Name + "\" too long. Flat names must have a length of " + General.Map.Config.MaxTextureNameLength + " characters or less");
return false;
}
//mxd. Can't load image without name
if(string.IsNullOrEmpty(tx.Name))
{
ReportError("Can't load an unnamed flat. Please consider giving names to your resources.");
return false;
}
// Add the flat
if(!flats.ContainsKey(tx.Name) || (flats[tx.Name].TypeName != "texture"))
flats[tx.Name] = tx;
}
}
else if(objdeclaration == "$gzdb_skip") //mxd
{
break;
}
else
{
// Unknown structure!
// Best we can do now is just find the first { and then
// follow the scopes until the matching } is found
string token2;
do
case "$gzdb_skip": break;
default:
{
if(!SkipWhitespace(true)) break;
token2 = ReadToken();
if(string.IsNullOrEmpty(token2)) break;
// Unknown structure!
// Best we can do now is just find the first { and then
// follow the scopes until the matching } is found
string token2;
do
{
if(!SkipWhitespace(true)) break;
token2 = ReadToken();
if(string.IsNullOrEmpty(token2)) break;
}
while(token2 != "{");
int scopelevel = 1;
do
{
if(!SkipWhitespace(true)) break;
token2 = ReadToken();
if(string.IsNullOrEmpty(token2)) break;
if(token2 == "{") scopelevel++;
if(token2 == "}") scopelevel--;
}
while(scopelevel > 0);
}
while(token2 != "{");
int scopelevel = 1;
do
{
if(!SkipWhitespace(true)) break;
token2 = ReadToken();
if(string.IsNullOrEmpty(token2)) break;
if(token2 == "{") scopelevel++;
if(token2 == "}") scopelevel--;
}
while(scopelevel > 0);
break;
}
}
}
@ -194,6 +229,12 @@ namespace CodeImp.DoomBuilder.ZDoom
// Return true when no errors occurred
return (ErrorDescription == null);
}
//mxd
protected override string GetLanguageType()
{
return "TEXTURES";
}
#endregion
}

View file

@ -49,17 +49,15 @@ namespace CodeImp.DoomBuilder.ZDoom
if(string.IsNullOrEmpty(token))
{
General.ErrorLogger.Add(ErrorType.Error, "Unable to get voxel model name from '" + sourcefilename + "', line " + GetCurrentLineNumber());
spriteNames.Clear();
continue;
ReportError("Expected voxel name");
return false;
}
modelName = StripTokenQuotes(token).ToLowerInvariant();
}
else if(token == "{") //read the settings
{
ModelData mde = new ModelData();
mde.IsVoxel = true;
ModelData mde = new ModelData { IsVoxel = true };
float scale = 1.0f;
float angleoffset = 0;
@ -109,15 +107,16 @@ namespace CodeImp.DoomBuilder.ZDoom
token = StripTokenQuotes(ReadToken());
if(token != "=")
{
General.ErrorLogger.Add(ErrorType.Error, "Error in " + sourcefilename + " at line " + GetCurrentLineNumber() + ": expected '=', but got '" + token + "'");
break;
ReportError("expected '=', but got '" + token + "'");
return false;
}
token = StripTokenQuotes(ReadToken());
if(!ReadSignedFloat(token, ref angleoffset))
{
// Not numeric!
General.ErrorLogger.Add(ErrorType.Error, "Error in " + sourcefilename + " at line " + GetCurrentLineNumber() + ": expected AngleOffset value, but got '" + token + "'");
ReportError("expected AngleOffset value, but got '" + token + "'");
return false;
}
}
else if(token == "scale")
@ -127,17 +126,19 @@ namespace CodeImp.DoomBuilder.ZDoom
token = StripTokenQuotes(ReadToken());
if(token != "=")
{
General.ErrorLogger.Add(ErrorType.Error, "Error in " + sourcefilename + " at line " + GetCurrentLineNumber() + ": expected '=', but got '" + token + "'");
break;
ReportError("expected '=', but got '" + token + "'");
return false;
}
token = StripTokenQuotes(ReadToken());
if(!ReadSignedFloat(token, ref scale))
{
// Not numeric!
General.ErrorLogger.Add(ErrorType.Error, "Error in " + sourcefilename + " at line " + GetCurrentLineNumber() + ": expected Scale value, but got '" + token + "'");
ReportError("expected Scale value, but got '" + token + "'");
return false;
}
}
prevToken = token.ToUpperInvariant();
}
}
@ -151,5 +152,10 @@ namespace CodeImp.DoomBuilder.ZDoom
return entries.Count > 0;
}
protected override string GetLanguageType()
{
return "VOXELDEF";
}
}
}

View file

@ -47,7 +47,7 @@ namespace CodeImp.DoomBuilder.ZDoom
private int errorline;
private string errordesc;
private string errorsource;
private long prevstreamposition; //mxd. Text stream position storted before poerforming ReadToken.
private long prevstreamposition; //mxd. Text stream position storted before performing ReadToken.
#endregion
@ -213,7 +213,8 @@ namespace CodeImp.DoomBuilder.ZDoom
// This reads a token (all sequential non-whitespace characters or a single character)
// Returns null when the end of the stream has been reached
protected internal string ReadToken()
protected internal string ReadToken() { return ReadToken(true); } //mxd. Added "multiline" param
protected internal string ReadToken(bool multiline)
{
//mxd. Return empty string when the end of the stream has been reached
if(datastream.Position == datastream.Length) return string.Empty;
@ -228,6 +229,14 @@ namespace CodeImp.DoomBuilder.ZDoom
char c = (char)datareader.ReadByte();
while(!IsWhitespace(c) || quotedstring || IsSpecialToken(c))
{
//mxd. Break at newline?
if(!multiline && c == '\r')
{
// Go one character back so line number is correct
datastream.Seek(-1, SeekOrigin.Current);
return token;
}
// Special token?
if(!quotedstring && IsSpecialToken(c))
{
@ -418,7 +427,7 @@ namespace CodeImp.DoomBuilder.ZDoom
if(token != expectedtoken)
{
if(reporterror) General.ErrorLogger.Add(ErrorType.Error, "Error in '" + sourcename + "' at line " + GetCurrentLineNumber() + ": expected '" + expectedtoken + "', but got '" + token + "'");
if(reporterror) ReportError("expected '" + expectedtoken + "', but got '" + token + "'");
// Rewind so this structure can be read again
DataStream.Seek(-token.Length - 1, SeekOrigin.Current);
@ -469,20 +478,39 @@ namespace CodeImp.DoomBuilder.ZDoom
errorsource = sourcename;
}
//mxd. This reports a warning
protected internal void ReportWarning(string message)
//mxd. This adds a warning to the ErrorLogger
protected internal void LogWarning(string message)
{
// Add a warning
General.ErrorLogger.Add(ErrorType.Warning, "DECORATE warning in '" + sourcename + "', line " + GetCurrentLineNumber() + ". " + message + ".");
int errline = GetCurrentLineNumber();
General.ErrorLogger.Add(ErrorType.Warning, GetLanguageType() + " warning in '" + sourcename
+ (errline != CompilerError.NO_LINE_NUMBER ? "', line " + (errline + 1) : "'") + ". "
+ message + ".");
}
//mxd. This adds an error to the ErrorLogger
public void LogError()
{
General.ErrorLogger.Add(ErrorType.Error, GetLanguageType() + " error in '" + errorsource
+ (errorline != CompilerError.NO_LINE_NUMBER ? "', line " + (errorline + 1) : "'") + ". "
+ errordesc + ".");
}
//mxd
internal void ClearError()
{
errorline = 0;
errordesc = null;
errorsource = null;
}
//mxd
protected internal int GetCurrentLineNumber()
protected int GetCurrentLineNumber()
{
long pos = datastream.Position;
long finishpos = Math.Min(prevstreamposition, pos);
long readpos = 0;
int linenumber = 0;
int linenumber = -1;
// Find the line on which we found this error
datastream.Seek(0, SeekOrigin.Begin);
@ -498,9 +526,12 @@ namespace CodeImp.DoomBuilder.ZDoom
// Return to original position
datastream.Seek(pos, SeekOrigin.Begin);
return linenumber;
return Math.Max(linenumber, 0);
}
//mxd. Language type
protected abstract string GetLanguageType();
#endregion
}
}