Added a terrible makeshift level header parser for SRB2

This commit is contained in:
MascaraSnake 2016-01-30 12:05:12 +01:00
parent 677b218ae5
commit 471649fa84
5 changed files with 314 additions and 29 deletions

View file

@ -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" />

View file

@ -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;
} }

View file

@ -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>(); }

View file

@ -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");

View 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
}
}