mirror of
https://git.do.srb2.org/STJr/ZoneBuilder.git
synced 2024-11-10 06:41:49 +00:00
Added a terrible makeshift level header parser for SRB2
This commit is contained in:
parent
677b218ae5
commit
471649fa84
5 changed files with 314 additions and 29 deletions
|
@ -182,6 +182,7 @@
|
||||||
<Compile Include="Map\Node.cs" />
|
<Compile Include="Map\Node.cs" />
|
||||||
<Compile Include="Map\Seg.cs" />
|
<Compile Include="Map\Seg.cs" />
|
||||||
<Compile Include="Map\Subsector.cs" />
|
<Compile Include="Map\Subsector.cs" />
|
||||||
|
<Compile Include="SRB2\SOCParser.cs" />
|
||||||
<Compile Include="VisualModes\VisualBlockMap.cs" />
|
<Compile Include="VisualModes\VisualBlockMap.cs" />
|
||||||
<Compile Include="VisualModes\VisualMode.cs" />
|
<Compile Include="VisualModes\VisualMode.cs" />
|
||||||
<Compile Include="General\Clock.cs" />
|
<Compile Include="General\Clock.cs" />
|
||||||
|
|
|
@ -22,6 +22,7 @@ using System.Drawing;
|
||||||
using System.Drawing.Drawing2D;
|
using System.Drawing.Drawing2D;
|
||||||
using System.Drawing.Imaging;
|
using System.Drawing.Imaging;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using CodeImp.DoomBuilder.Config;
|
using CodeImp.DoomBuilder.Config;
|
||||||
|
@ -32,6 +33,7 @@ using CodeImp.DoomBuilder.Geometry;
|
||||||
using CodeImp.DoomBuilder.IO;
|
using CodeImp.DoomBuilder.IO;
|
||||||
using CodeImp.DoomBuilder.Map;
|
using CodeImp.DoomBuilder.Map;
|
||||||
using CodeImp.DoomBuilder.Rendering;
|
using CodeImp.DoomBuilder.Rendering;
|
||||||
|
using CodeImp.DoomBuilder.SRB2;
|
||||||
using CodeImp.DoomBuilder.Windows;
|
using CodeImp.DoomBuilder.Windows;
|
||||||
using CodeImp.DoomBuilder.ZDoom;
|
using CodeImp.DoomBuilder.ZDoom;
|
||||||
using SlimDX;
|
using SlimDX;
|
||||||
|
@ -2092,43 +2094,81 @@ namespace CodeImp.DoomBuilder.Data
|
||||||
//mxd. This loads (Z)MAPINFO
|
//mxd. This loads (Z)MAPINFO
|
||||||
private void LoadMapInfo(out Dictionary<int, string> spawnnums, out Dictionary<int, string> doomednums)
|
private void LoadMapInfo(out Dictionary<int, string> spawnnums, out Dictionary<int, string> doomednums)
|
||||||
{
|
{
|
||||||
MapinfoParser parser = new MapinfoParser { OnInclude = ParseFromLocation };
|
if (General.Map.SRB2)
|
||||||
|
|
||||||
// Parse mapinfo
|
|
||||||
foreach (DataReader dr in containers)
|
|
||||||
{
|
{
|
||||||
currentreader = dr;
|
SOCParser parser = new SOCParser { OnInclude = ParseFromLocation };
|
||||||
|
|
||||||
Dictionary<string, Stream> streams = dr.GetMapinfoData();
|
// Parse mapinfo
|
||||||
foreach (KeyValuePair<string, Stream> group in streams)
|
foreach (DataReader dr in containers)
|
||||||
{
|
{
|
||||||
// Parse the data
|
currentreader = dr;
|
||||||
parser.Parse(group.Value, Path.Combine(dr.Location.location, group.Key), General.Map.Options.LevelName, false);
|
|
||||||
|
|
||||||
//MAPINFO lumps are interdependable. Can't carry on...
|
Dictionary<string, Stream> streams1 = dr.GetObjctcfgData();
|
||||||
if (parser.HasError)
|
Dictionary<string, Stream> streams2 = dr.GetMaincfgData();
|
||||||
|
Dictionary<string, Stream> streams3 = dr.GetSOCData();
|
||||||
|
Dictionary<string, Stream> streams = streams1.Concat(streams2).Concat(streams3).ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
|
||||||
|
|
||||||
|
foreach (KeyValuePair<string, Stream> group in streams)
|
||||||
{
|
{
|
||||||
parser.LogError();
|
// Parse the data
|
||||||
break;
|
parser.Parse(group.Value, Path.Combine(dr.Location.location, group.Key), General.Map.Options.LevelName, false);
|
||||||
|
|
||||||
|
//MAPINFO lumps are interdependable. Can't carry on...
|
||||||
|
if (parser.HasError)
|
||||||
|
{
|
||||||
|
parser.LogError();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!parser.HasError)
|
if (!parser.HasError)
|
||||||
{
|
mapinfo = parser.MapInfo;
|
||||||
// Store parsed data
|
else
|
||||||
spawnnums = parser.SpawnNums;
|
mapinfo = new MapInfo();
|
||||||
doomednums = parser.DoomEdNums;
|
|
||||||
mapinfo = parser.MapInfo;
|
spawnnums = new Dictionary<int, string>();
|
||||||
|
doomednums = new Dictionary<int, string>();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// No nulls allowed!
|
MapinfoParser parser = new MapinfoParser { OnInclude = ParseFromLocation };
|
||||||
spawnnums = new Dictionary<int, string>();
|
|
||||||
doomednums = new Dictionary<int, string>();
|
|
||||||
mapinfo = new MapInfo();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Parse mapinfo
|
||||||
|
foreach (DataReader dr in containers)
|
||||||
|
{
|
||||||
|
currentreader = dr;
|
||||||
|
|
||||||
|
Dictionary<string, Stream> streams = dr.GetMapinfoData();
|
||||||
|
foreach (KeyValuePair<string, Stream> group in streams)
|
||||||
|
{
|
||||||
|
// Parse the data
|
||||||
|
parser.Parse(group.Value, Path.Combine(dr.Location.location, group.Key), General.Map.Options.LevelName, false);
|
||||||
|
|
||||||
|
//MAPINFO lumps are interdependable. Can't carry on...
|
||||||
|
if (parser.HasError)
|
||||||
|
{
|
||||||
|
parser.LogError();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!parser.HasError)
|
||||||
|
{
|
||||||
|
// Store parsed data
|
||||||
|
spawnnums = parser.SpawnNums;
|
||||||
|
doomednums = parser.DoomEdNums;
|
||||||
|
mapinfo = parser.MapInfo;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// No nulls allowed!
|
||||||
|
spawnnums = new Dictionary<int, string>();
|
||||||
|
doomednums = new Dictionary<int, string>();
|
||||||
|
mapinfo = new MapInfo();
|
||||||
|
}
|
||||||
|
}
|
||||||
currentreader = null;
|
currentreader = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -161,8 +161,17 @@ namespace CodeImp.DoomBuilder.Data
|
||||||
//mxd. When implemented, this returns the MAPINFO lump
|
//mxd. When implemented, this returns the MAPINFO lump
|
||||||
public abstract Dictionary<string, Stream> GetMapinfoData(); // { return new Dictionary<string, Stream>(); }
|
public abstract Dictionary<string, Stream> GetMapinfoData(); // { return new Dictionary<string, Stream>(); }
|
||||||
|
|
||||||
//mxd. When implemented, this returns the GLDEFS lump
|
//mxd. When implemented, this returns the MAINCFG lump
|
||||||
public abstract Dictionary<string, Stream> GetGldefsData(GameType gametype); // { return new Dictionary<string, Stream>(); }
|
public virtual Dictionary<string, Stream> GetMaincfgData() { return new Dictionary<string, Stream>(); }
|
||||||
|
|
||||||
|
//mxd. When implemented, this returns the OBJCTCFG lump
|
||||||
|
public virtual Dictionary<string, Stream> GetObjctcfgData() { return new Dictionary<string, Stream>(); }
|
||||||
|
|
||||||
|
//mxd. When implemented, this returns the SOC_ lumps
|
||||||
|
public virtual Dictionary<string, Stream> GetSOCData() { return new Dictionary<string, Stream>(); }
|
||||||
|
|
||||||
|
//mxd. When implemented, this returns the GLDEFS lump
|
||||||
|
public abstract Dictionary<string, Stream> GetGldefsData(GameType gametype); // { return new Dictionary<string, Stream>(); }
|
||||||
|
|
||||||
//mxd. When implemented, this returns the REVERBS lump
|
//mxd. When implemented, this returns the REVERBS lump
|
||||||
public abstract Dictionary<string, Stream> GetReverbsData(); // { return new Dictionary<string, Stream>(); }
|
public abstract Dictionary<string, Stream> GetReverbsData(); // { return new Dictionary<string, Stream>(); }
|
||||||
|
|
|
@ -835,8 +835,53 @@ namespace CodeImp.DoomBuilder.Data
|
||||||
return streams;
|
return streams;
|
||||||
}
|
}
|
||||||
|
|
||||||
//mxd
|
public override Dictionary<string, Stream> GetMaincfgData()
|
||||||
public override Dictionary<string, Stream> GetGldefsData(GameType gameType)
|
{
|
||||||
|
if (issuspended) throw new Exception("Data reader is suspended");
|
||||||
|
|
||||||
|
Dictionary<string, Stream> streams = new Dictionary<string, Stream>(StringComparer.Ordinal);
|
||||||
|
string src = "MAINCFG";
|
||||||
|
|
||||||
|
//should be only one entry per wad
|
||||||
|
int lumpindex = file.FindLumpIndex(src);
|
||||||
|
|
||||||
|
if (lumpindex != -1) streams.Add(src, file.Lumps[lumpindex].Stream);
|
||||||
|
return streams;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Dictionary<string, Stream> GetObjctcfgData()
|
||||||
|
{
|
||||||
|
if (issuspended) throw new Exception("Data reader is suspended");
|
||||||
|
|
||||||
|
Dictionary<string, Stream> streams = new Dictionary<string, Stream>(StringComparer.Ordinal);
|
||||||
|
string src = "OBJCTCFG";
|
||||||
|
|
||||||
|
//should be only one entry per wad
|
||||||
|
int lumpindex = file.FindLumpIndex(src);
|
||||||
|
|
||||||
|
if (lumpindex != -1) streams.Add(src, file.Lumps[lumpindex].Stream);
|
||||||
|
return streams;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Dictionary<string, Stream> GetSOCData()
|
||||||
|
{
|
||||||
|
if (issuspended) throw new Exception("Data reader is suspended");
|
||||||
|
|
||||||
|
Dictionary<string, Stream> streams = new Dictionary<string, Stream>(StringComparer.Ordinal);
|
||||||
|
string prefix = "SOC_";
|
||||||
|
|
||||||
|
foreach (Lump lump in file.Lumps)
|
||||||
|
{
|
||||||
|
if (lump.Name.StartsWith(prefix))
|
||||||
|
{
|
||||||
|
streams.Add(lump.Name, lump.Stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return streams;
|
||||||
|
}
|
||||||
|
|
||||||
|
//mxd
|
||||||
|
public override Dictionary<string, Stream> GetGldefsData(GameType gameType)
|
||||||
{
|
{
|
||||||
if(issuspended) throw new Exception("Data reader is suspended");
|
if(issuspended) throw new Exception("Data reader is suspended");
|
||||||
|
|
||||||
|
|
190
Source/Core/SRB2/SOCParser.cs
Normal file
190
Source/Core/SRB2/SOCParser.cs
Normal file
|
@ -0,0 +1,190 @@
|
||||||
|
#region ================== Namespaces
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using CodeImp.DoomBuilder.ZDoom;
|
||||||
|
using CodeImp.DoomBuilder.GZBuilder.Data;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
namespace CodeImp.DoomBuilder.SRB2
|
||||||
|
{
|
||||||
|
internal sealed class SOCParser : ZDTextParser
|
||||||
|
{
|
||||||
|
#region ================== Delegates
|
||||||
|
|
||||||
|
public delegate void IncludeDelegate(SOCParser parser, string includefile, bool clearerror);
|
||||||
|
public IncludeDelegate OnInclude;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ================== Variables
|
||||||
|
|
||||||
|
private MapInfo mapinfo;
|
||||||
|
private string mapname;
|
||||||
|
private readonly HashSet<string> parsedlumps;
|
||||||
|
private StreamReader streamreader;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ================== Properties
|
||||||
|
|
||||||
|
public MapInfo MapInfo { get { return mapinfo; } }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ================== Constructor
|
||||||
|
|
||||||
|
public SOCParser()
|
||||||
|
{
|
||||||
|
// Syntax
|
||||||
|
whitespace = "\n \t\r\u00A0";
|
||||||
|
specialtokens = "=\n";
|
||||||
|
|
||||||
|
mapinfo = new MapInfo();
|
||||||
|
parsedlumps = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ================== Parsing
|
||||||
|
|
||||||
|
override public bool Parse(Stream stream, string sourcefilename, bool clearerrors)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(mapname)) throw new NotSupportedException("Map name required!");
|
||||||
|
return Parse(stream, sourcefilename, mapname, clearerrors);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Parse(Stream stream, string sourcefilename, string mapname, bool clearerrors)
|
||||||
|
{
|
||||||
|
this.mapname = mapname.ToUpperInvariant();
|
||||||
|
if (!base.Parse(stream, sourcefilename, clearerrors)) return false;
|
||||||
|
|
||||||
|
// Keep local data
|
||||||
|
streamreader = new StreamReader(stream, Encoding.ASCII);
|
||||||
|
|
||||||
|
while (!streamreader.EndOfStream)
|
||||||
|
{
|
||||||
|
string line = streamreader.ReadLine();
|
||||||
|
if (String.IsNullOrEmpty(line) || line.StartsWith("\n") || line.StartsWith("#")) continue;
|
||||||
|
string[] tokens = line.Split(new char[] { ' ' });
|
||||||
|
switch (tokens[0].ToUpperInvariant())
|
||||||
|
{
|
||||||
|
case "LEVEL":
|
||||||
|
if (tokens.Length < 2 || String.IsNullOrEmpty(tokens[1]))
|
||||||
|
{
|
||||||
|
ReportError("Level block is missing a level number.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (GetMapName(tokens[1].ToUpperInvariant()) != mapname) break;
|
||||||
|
if (!ParseLevelHeader(mapname)) return false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// All done
|
||||||
|
return !this.HasError;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ================== Map block parsing
|
||||||
|
|
||||||
|
private bool ParseLevelHeader(string mapname)
|
||||||
|
{
|
||||||
|
if (mapname == null) return false;
|
||||||
|
string levelname = "";
|
||||||
|
int act = 0;
|
||||||
|
bool zone = true;
|
||||||
|
while (!streamreader.EndOfStream)
|
||||||
|
{
|
||||||
|
string line = streamreader.ReadLine();
|
||||||
|
if (String.IsNullOrEmpty(line) || line.StartsWith("\n")) break;
|
||||||
|
if (line.StartsWith("#")) continue;
|
||||||
|
string[] tokens = line.Split(new char[] { '=' });
|
||||||
|
if (tokens.Length != 2)
|
||||||
|
{
|
||||||
|
ReportError("Invalid line.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
tokens[0] = tokens[0].Trim().ToUpperInvariant();
|
||||||
|
tokens[1] = tokens[1].Trim().ToUpperInvariant();
|
||||||
|
switch(tokens[0])
|
||||||
|
{
|
||||||
|
case "LEVELNAME":
|
||||||
|
levelname = tokens[1];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "ACT":
|
||||||
|
if (!int.TryParse(tokens[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out act) || act < 0 || act >= 20)
|
||||||
|
{
|
||||||
|
ReportError("Invalid act number.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "NOZONE":
|
||||||
|
zone = tokens[1][0] == 'T' || tokens[1][0] == 'Y';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "SKYNUM":
|
||||||
|
int skyn;
|
||||||
|
if (!int.TryParse(tokens[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out skyn))
|
||||||
|
{
|
||||||
|
ReportError("Invalid sky number.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
mapinfo.Sky1 = "SKY" + skyn;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mapinfo.Title = levelname + (zone ? " ZONE" : "") + (act > 0 ? " " + act : "");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetMapName(string number)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
if (int.TryParse(number, NumberStyles.Integer, CultureInfo.InvariantCulture, out n))
|
||||||
|
return ConvertToExtendedMapNum(n);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (number.Length != 2 || number[0] < 'A' || number[0] > 'Z' || number[1] < '0' || number[1] > '9') return null;
|
||||||
|
return "MAP" + number;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ConvertToExtendedMapNum(int n)
|
||||||
|
{
|
||||||
|
if (n <= 0 || n > 1035)
|
||||||
|
return null;
|
||||||
|
if (n < 10)
|
||||||
|
return "MAP0" + n;
|
||||||
|
if (n < 100)
|
||||||
|
return "MAP" + n.ToString();
|
||||||
|
|
||||||
|
int x = n - 100;
|
||||||
|
int p = x / 36;
|
||||||
|
int q = x % 36;
|
||||||
|
char a = (char)('A' + p);
|
||||||
|
char b = (q < 10) ? (char)('0' + q) : (char)('A' + q - 10);
|
||||||
|
return "MAP" + String.Concat(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ================== Methods
|
||||||
|
|
||||||
|
protected override string GetLanguageType()
|
||||||
|
{
|
||||||
|
return "SOC";
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue