Added, Script Editor: unreferenced ACS files are now shown in the Resources list.

Added, Script Editor: MENUDEF and SBARINFO files/lumps are now shown in the Resources list.
Fixed, ACS handling: fixed a crash when trying to parse an #include file, when specified path was absolute.
This commit is contained in:
MaxED 2016-11-24 21:09:24 +00:00
parent 894279b4ba
commit 9553042c84
15 changed files with 209 additions and 63 deletions

View file

@ -107,7 +107,7 @@ namespace CodeImp.DoomBuilder.Compilers
DataLocation dl = new DataLocation(DataLocation.RESOURCE_DIRECTORY, Path.GetDirectoryName(inputfilepath), false, false, false);
//mxd. TextResourceData must point to temp path when compiling WAD lumps for lump to be recognized as map lump when reporting errors...
TextResourceData data = new TextResourceData(stream, dl, (SourceIsMapScriptsLump ? inputfile : sourcefile), false);
TextResourceData data = new TextResourceData(stream, dl, (SourceIsMapScriptsLump ? inputfile : sourcefile));
if(!parser.Parse(data, info.Files, true, AcsParserSE.IncludeType.NONE, false))
{
// Check for errors

View file

@ -302,7 +302,7 @@ namespace CodeImp.DoomBuilder.Controls
internal ScriptType VerifyScriptType()
{
ScriptTypeParserSE parser = new ScriptTypeParserSE();
TextResourceData data = new TextResourceData(new MemoryStream(editor.GetText()), new DataLocation(), config.Description, false);
TextResourceData data = new TextResourceData(new MemoryStream(editor.GetText()), new DataLocation(), config.Description);
if(parser.Parse(data, false))
{

View file

@ -1218,9 +1218,6 @@ namespace CodeImp.DoomBuilder.Controls
// Save to same filename
t.Save();
//mxd. Also compile if needed
if(t.Config.Compiler != null) t.Compile();
return true;
}

View file

@ -287,14 +287,18 @@ namespace CodeImp.DoomBuilder.Controls
}
else
{
scriptroot = new TreeNode(typename, groupiconindex, groupiconindex);
scriptroot.Name = typename;
scriptroot.Tag = new TextResourceNodeData
{
ResourceLocation = key,
NodeType = TextResourceNodeType.DIRECTORY,
ScriptType = res.ScriptType,
};
var rdata = new TextResourceNodeData
{
ResourceLocation = key,
NodeType = TextResourceNodeType.DIRECTORY,
ScriptType = res.ScriptType,
};
scriptroot = new TreeNode(typename, groupiconindex, groupiconindex)
{
Tag = rdata,
Name = typename,
ToolTipText = rdata.ToString()
};
if(asreadonly) scriptroot.ForeColor = SystemColors.GrayText;
root.Nodes.Add(scriptroot);
@ -324,7 +328,7 @@ namespace CodeImp.DoomBuilder.Controls
var cdata = new TextResourceNodeData
{
ResourceLocation = key,
LocationInResource = localpath,
LocationInResource = path,
NodeType = TextResourceNodeType.DIRECTORY,
ScriptType = res.ScriptType
};
@ -345,11 +349,12 @@ namespace CodeImp.DoomBuilder.Controls
TextResourceNodeData data = new TextResourceNodeData
{
ResourceLocation = key,
LocationInResource = localpath,
LocationInResource = path,
NodeType = TextResourceNodeType.NODE,
Resource = res,
};
TreeNode scriptnode = new TreeNode(res.ToString(), iconindex, iconindex) { Tag = data, ToolTipText = data.ToString() };
string includepath = (res.ScriptType == ScriptType.ACS ? "\nInclude path: \"" + res.Filename + "\"" : "");
TreeNode scriptnode = new TreeNode(res.ToString(), iconindex, iconindex) { Tag = data, ToolTipText = data + includepath };
if(asreadonly) scriptnode.ForeColor = SystemColors.GrayText;
TrySelectNode(selected, scriptnode, ref toselect);

View file

@ -425,6 +425,9 @@ namespace CodeImp.DoomBuilder.Data
LoadCvarInfo();
LoadLockDefs();
//mxd. Load Script Editor-only stuff...
LoadExtraTextLumps();
int thingcount = LoadDecorateThings(spawnnums, doomednums);
int spritecount = LoadThingSprites();
LoadInternalSprites();
@ -2848,6 +2851,41 @@ namespace CodeImp.DoomBuilder.Data
}
}
//mxd. This collects ZDoom text lumps, which are not used by the editor anywhere outside the Script Editor
private void LoadExtraTextLumps()
{
// Load MENUDEFS
HashSet<ScriptResource> menudefs = new HashSet<ScriptResource>();
foreach(DataReader dr in containers)
{
currentreader = dr;
IEnumerable<TextResourceData> streams = dr.GetMenuDefData();
// Add text tesources
foreach(TextResourceData data in streams)
menudefs.Add(new ScriptResource(data, ScriptType.MENUDEF));
}
// Add to collection
if(menudefs.Count > 0) scriptresources[ScriptType.MENUDEF] = menudefs;
// Load SBARINFO
//TODO: SBARINFO supports #include
HashSet<ScriptResource> sbarinfos = new HashSet<ScriptResource>();
foreach(DataReader dr in containers)
{
currentreader = dr;
IEnumerable<TextResourceData> streams = dr.GetSBarInfoData();
// Add text tesources
foreach(TextResourceData data in streams)
sbarinfos.Add(new ScriptResource(data, ScriptType.SBARINFO));
}
// Add to collection
if(sbarinfos.Count > 0) scriptresources[ScriptType.SBARINFO] = sbarinfos;
}
//mxd
internal TextResourceData GetTextResourceData(string name)
{
@ -2857,7 +2895,7 @@ namespace CodeImp.DoomBuilder.Data
if(File.Exists(name))
{
DataLocation location = new DataLocation{ location = name, type = DataLocation.RESOURCE_DIRECTORY };
return new TextResourceData(File.OpenRead(name), location, name, false);
return new TextResourceData(File.OpenRead(name), location, name);
}
return null;
@ -2867,7 +2905,7 @@ namespace CodeImp.DoomBuilder.Data
for(int i = containers.Count - 1; i >= 0; i--)
{
if(containers[i].FileExists(name))
return new TextResourceData(containers[i], containers[i].LoadFile(name), name, false);
return new TextResourceData(containers[i], containers[i].LoadFile(name), name, true);
}
return null;

View file

@ -43,42 +43,43 @@ namespace CodeImp.DoomBuilder.Data
internal DataLocation SourceLocation { get { return sourcelocation; } }
internal string Filename { get { return filename; } } // Lump name/Filename
internal int LumpIndex { get { return lumpindex; } } // Lump index in a WAD
internal bool Trackable { get { return trackable; } set { trackable = value; } } // When false, wont be added to DataManager.TextResources
internal bool Trackable { get { return trackable; } } // When false, wont be added to DataManager.TextResources
internal TextResourceData(DataReader Source, Stream Stream, string Filename, bool Trackable)
internal TextResourceData(DataReader source, Stream stream, string filename, bool trackable)
{
source = Source;
sourcelocation = Source.Location;
stream = Stream;
filename = Filename;
trackable = Trackable;
this.source = source;
this.sourcelocation = source.Location;
this.stream = stream;
this.filename = filename;
this.trackable = trackable;
WADReader reader = source as WADReader;
if(reader != null)
lumpindex = reader.WadFile.FindLumpIndex(filename);
this.lumpindex = reader.WadFile.FindLumpIndex(filename);
else
lumpindex = -1;
this.lumpindex = -1;
}
internal TextResourceData(DataReader Source, Stream Stream, string Filename, int LumpIndex, bool Trackable)
internal TextResourceData(DataReader source, Stream stream, string filename, int lumpindex, bool trackable)
{
source = Source;
sourcelocation = Source.Location;
stream = Stream;
filename = Filename;
lumpindex = LumpIndex;
trackable = Trackable;
this.source = source;
this.sourcelocation = source.Location;
this.stream = stream;
this.filename = filename;
this.lumpindex = lumpindex;
this.trackable = trackable;
}
internal TextResourceData(Stream Stream, DataLocation Location, string Filename, bool Trackable)
// Adds an untrackable resource without DataReader
internal TextResourceData(Stream stream, DataLocation location, string filename)
{
source = null;
sourcelocation = Location;
stream = Stream;
filename = Filename;
lumpindex = -1;
trackable = Trackable;
this.source = null;
this.sourcelocation = location;
this.stream = stream;
this.filename = filename;
this.lumpindex = -1;
this.trackable = false;
}
}
@ -258,6 +259,12 @@ namespace CodeImp.DoomBuilder.Data
//mxd. When implemented, this returns LOCKDEFS lumps
public abstract IEnumerable<TextResourceData> GetLockDefsData();
//mxd. When implemented, this returns MENUDEF lumps
public abstract IEnumerable<TextResourceData> GetMenuDefData();
//mxd. When implemented, this returns SBARINFO lumps
public abstract IEnumerable<TextResourceData> GetSBarInfoData();
//mxd. When implemented, this returns the list of voxel model names
public abstract HashSet<string> GetVoxelNames();

View file

@ -436,7 +436,7 @@ namespace CodeImp.DoomBuilder.Data
}
// This returns all files in a given directory that match the given extension
protected override string[] GetFilesWithExt(string path, string extension, bool subfolders)
internal override string[] GetFilesWithExt(string path, string extension, bool subfolders)
{
return files.GetAllFiles(path, extension, subfolders).ToArray();
}

View file

@ -446,7 +446,7 @@ namespace CodeImp.DoomBuilder.Data
}
// This returns all files in a given directory that match the given extension
protected override string[] GetFilesWithExt(string path, string extension, bool subfolders)
internal override string[] GetFilesWithExt(string path, string extension, bool subfolders)
{
return files.GetAllFiles(path, extension, subfolders).ToArray();
}

View file

@ -816,7 +816,7 @@ namespace CodeImp.DoomBuilder.Data
#endregion
#region ================== Lockdefs (mxd)
#region ================== LOCKDEFS (mxd)
public override IEnumerable<TextResourceData> GetLockDefsData()
{
@ -838,6 +838,50 @@ namespace CodeImp.DoomBuilder.Data
#endregion
#region ================== MENUDEF (mxd)
public override IEnumerable<TextResourceData> GetMenuDefData()
{
// Error when suspended
if(issuspended) throw new Exception("Data reader is suspended");
List<TextResourceData> result = new List<TextResourceData>();
string file = FindFirstFile("MENUDEF", false);
// Add to collection
if(!string.IsNullOrEmpty(file))
result.Add(new TextResourceData(this, LoadFile(file), file, true));
// Find in any of the wad files
foreach(WADReader wr in wads) result.AddRange(wr.GetMenuDefData());
return result;
}
#endregion
#region ================== SBARINFO (mxd)
public override IEnumerable<TextResourceData> GetSBarInfoData()
{
// Error when suspended
if(issuspended) throw new Exception("Data reader is suspended");
List<TextResourceData> result = new List<TextResourceData>();
string file = FindFirstFile("SBARINFO", false);
// Add to collection
if(!string.IsNullOrEmpty(file))
result.Add(new TextResourceData(this, LoadFile(file), file, true));
// Find in any of the wad files
foreach(WADReader wr in wads) result.AddRange(wr.GetSBarInfoData());
return result;
}
#endregion
#region ================== Methods
// This loads the images in this directory
@ -890,7 +934,7 @@ namespace CodeImp.DoomBuilder.Data
protected abstract string[] GetAllFilesWhichTitleStartsWith(string path, string title, bool subfolders);
// This must return all files in a given directory that match the given extension
protected abstract string[] GetFilesWithExt(string path, string extension, bool subfolders);
internal abstract string[] GetFilesWithExt(string path, string extension, bool subfolders);
//mxd. This must return wad files in the root directory
protected abstract string[] GetWadFiles();

View file

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

View file

@ -25,7 +25,7 @@ namespace CodeImp.DoomBuilder.Data.Scripting
target.Items.Clear();
DecorateParserSE parser = new DecorateParserSE();
TextResourceData data = new TextResourceData(stream, new DataLocation(), "DECORATE", false);
TextResourceData data = new TextResourceData(stream, new DataLocation(), "DECORATE");
if(parser.Parse(data, false))
target.Items.AddRange(parser.Actors.ToArray());

View file

@ -25,7 +25,7 @@ namespace CodeImp.DoomBuilder.Data.Scripting
target.Items.Clear();
ModeldefParserSE parser = new ModeldefParserSE();
TextResourceData data = new TextResourceData(stream, new DataLocation(), "MODELDEF", false);
TextResourceData data = new TextResourceData(stream, new DataLocation(), "MODELDEF");
if(parser.Parse(data, false))
target.Items.AddRange(parser.Models.ToArray());

View file

@ -1031,10 +1031,10 @@ namespace CodeImp.DoomBuilder.Data
// First look for ZMAPINFO
List<TextResourceData> result = new List<TextResourceData>();
result.AddRange(GetFirstLump("ZMAPINFO"));
result.AddRange(GetLastLump("ZMAPINFO"));
// Then for MAPINFO
if(result.Count == 0) result.AddRange(GetFirstLump("MAPINFO"));
if(result.Count == 0) result.AddRange(GetLastLump("MAPINFO"));
return result;
}
@ -1121,7 +1121,21 @@ namespace CodeImp.DoomBuilder.Data
}
//mxd
private IEnumerable<TextResourceData> GetFirstLump(string name)
public override IEnumerable<TextResourceData> GetMenuDefData()
{
if(issuspended) throw new Exception("Data reader is suspended");
return GetLastLump("MENUDEF");
}
//mxd
public override IEnumerable<TextResourceData> GetSBarInfoData()
{
if(issuspended) throw new Exception("Data reader is suspended");
return GetLastLump("SBARINFO");
}
//mxd
private IEnumerable<TextResourceData> GetLastLump(string name)
{
List<TextResourceData> result = new List<TextResourceData>();
int lumpindex = file.FindLumpIndex(name);

View file

@ -442,7 +442,7 @@ namespace CodeImp.DoomBuilder
thingsfilter.Update();
//mxd. Update script names
UpdateScriptNames();
LoadACS();
//mxd. Restore selection groups
options.ReadSelectionGroups();
@ -534,7 +534,7 @@ namespace CodeImp.DoomBuilder
data.SetupSkybox();
// Update script names
UpdateScriptNames();
LoadACS();
// Restore selection groups
options.ReadSelectionGroups();
@ -1964,9 +1964,13 @@ namespace CodeImp.DoomBuilder
return success;
}
//mxd. Update script numbers and names
private void UpdateScriptNames()
//mxd. Update script numbers and names, collect loose ACS files.
private void LoadACS()
{
///////////////////////////////////////////
// Step 1: Update script numbers and names
///////////////////////////////////////////
General.Map.Data.ScriptResources[ScriptType.ACS] = new HashSet<ScriptResource>();
// Find SCRIPTS lump and parse it
@ -2009,16 +2013,14 @@ namespace CodeImp.DoomBuilder
{
TextResourceData includedata = General.Map.Data.GetTextResourceData(includefile);
if(includedata == null) return false; // Fial
includedata.Trackable = true;
return se.Parse(includedata, true, includetype, false);
}
};
//INFO: CompileLump() prepends lumpname with "?" to distinguish between temporary files and files compiled in place
DataLocation location = new DataLocation { location = tempwadreader.WadFile.Filename, type = DataLocation.RESOURCE_WAD };
TextResourceData data = new TextResourceData(stream, location, "?SCRIPTS", false);
if(parser.Parse(data, scriptconfig.Compiler.Files, true, AcsParserSE.IncludeType.NONE, false))
TextResourceData trd = new TextResourceData(stream, location, "?SCRIPTS");
if(parser.Parse(trd, scriptconfig.Compiler.Files, true, AcsParserSE.IncludeType.NONE, false))
{
// Add to text resource list
General.Map.Data.ScriptResources[parser.ScriptType].UnionWith(parser.ScriptResources.Values);
@ -2037,10 +2039,47 @@ namespace CodeImp.DoomBuilder
if(parser.HasError) parser.LogError();
// Done here
return;
break;
}
}
}
///////////////////////////////////////////
// Step 2: Try to load unused ACS files
///////////////////////////////////////////
Dictionary<string, HashSet<string>> existingacsfiles = new Dictionary<string, HashSet<string>>();
// Gather already parsed files...
foreach(ScriptResource sr in General.Map.Data.ScriptResources[ScriptType.ACS])
{
if(!existingacsfiles.ContainsKey(sr.Resource.Location.location))
existingacsfiles.Add(sr.Resource.Location.location, new HashSet<string>());
existingacsfiles[sr.Resource.Location.location].Add(sr.Filename);
}
HashSet<ScriptResource> looseacsfiles = new HashSet<ScriptResource>();
foreach(DataReader dr in General.Map.Data.Containers)
{
//TODO: implement for WADs
if(dr is PK3StructuredReader)
{
PK3StructuredReader pkr = (PK3StructuredReader)dr;
string[] acsfiles = pkr.GetFilesWithExt("", "acs", true);
foreach(string acsfile in acsfiles)
{
if(!existingacsfiles.ContainsKey(pkr.Location.location) || !existingacsfiles[pkr.Location.location].Contains(acsfile))
{
TextResourceData trd = new TextResourceData(dr, dr.LoadFile(acsfile), acsfile, true);
looseacsfiles.Add(new ScriptResource(trd, ScriptType.ACS));
}
}
}
}
// Add to the main collection
General.Map.Data.ScriptResources[ScriptType.ACS].UnionWith(looseacsfiles);
}
//mxd
@ -2244,7 +2283,7 @@ namespace CodeImp.DoomBuilder
}
//mxd. Update script names
UpdateScriptNames();
LoadACS();
//mxd. Script Editor may need updating...
if(scriptwindow != null) scriptwindow.OnReloadResources();

View file

@ -508,7 +508,7 @@ namespace CodeImp.DoomBuilder.IO
// This finds a lump by name, returns -1 when not found
public int FindLumpIndex(string name, int start, int end)
{
if(name.Length > 8) return -1;//mxd. Can't be here. Go away!
if(name.Length > 8) return -1; //mxd. Can't be here. Go away!
long longname = Lump.MakeLongName(name);
@ -516,7 +516,9 @@ namespace CodeImp.DoomBuilder.IO
if(end > (lumps.Count - 1)) end = lumps.Count - 1;
// Loop through the lumps
for(int i = start; i <= end; i++)
//mxd. ZDoom seems to prefer the last lump with the matching name
//TODO: is that always the case?
for(int i = end; i > start - 1; i--)
{
// Check if the lump name matches
if(lumps[i].LongName == longname)