@working on decorate support

This commit is contained in:
codeimp 2009-01-21 23:09:25 +00:00
parent 1694d828d1
commit 76ec8a8c98
7 changed files with 172 additions and 47 deletions

View file

@ -49,6 +49,7 @@ namespace CodeImp.DoomBuilder.Data
// Data containers
private List<DataReader> containers;
private DataReader currentreader;
// Palette
private Playpal palette;
@ -1044,22 +1045,25 @@ namespace CodeImp.DoomBuilder.Data
{
// Load Decorate info cumulatively (the last Decorate is added to the previous)
// I'm not sure if this is the right thing to do though.
currentreader = dr;
Stream decodata = dr.GetDecorateData("DECORATE");
if(decodata != null)
{
// Parse the data
decodata.Seek(0, SeekOrigin.Begin);
parser.Parse(decodata);
parser.Parse(decodata, "DECORATE");
// Check for errors
if(parser.HasError)
{
General.WriteLogLine("ERROR: Unable to parse DECORATE data from location " + dr.Location.location + "!");
General.WriteLogLine(parser.ErrorDescription + " on line " + parser.ErrorLine);
General.WriteLogLine("ERROR: " + parser.ErrorDescription + " on line " + parser.ErrorLine + " in '" + parser.ErrorSource + "'");
break;
}
}
}
currentreader = null;
if(!parser.HasError)
{
@ -1073,10 +1077,15 @@ namespace CodeImp.DoomBuilder.Data
}
// This loads Decorate data from a specific file or lump name
private void LoadDecorateFromLocation(string location)
private void LoadDecorateFromLocation(DecorateParser parser, string location)
{
// TODO
int t = 5;
General.WriteLogLine("Including DECORATE resource '" + location + "'...");
Stream decodata = currentreader.GetDecorateData(location);
if(decodata != null)
{
// Parse this data
parser.Parse(decodata, location);
}
}
// This gets thing information by index

View file

@ -105,6 +105,19 @@ namespace CodeImp.DoomBuilder.Data
return null;
}
// This finds the first file that has the specific name
protected override string FindFirstFileWithExt(string path, string beginswith)
{
string[] files = GetAllFiles(path);
foreach(string f in files)
{
if(string.Compare(Path.GetFileName(f), beginswith, true) == 0)
return f;
}
return null;
}
// This loads an entire file in memory and returns the stream
// NOTE: Callers are responsible for disposing the stream!

View file

@ -163,6 +163,21 @@ namespace CodeImp.DoomBuilder.Data
return null;
}
// This finds the first file that has the specific name
protected override string FindFirstFileWithExt(string path, string beginswith)
{
string lowpath = path.ToLowerInvariant();
string lowbegin = beginswith.ToLowerInvariant();
foreach(string f in fileslist)
{
if((string.Compare(Path.GetDirectoryName(f), lowpath) == 0) &&
(string.Compare(Path.GetFileName(f), lowbegin) == 0))
return f;
}
return null;
}
// This loads an entire file in memory and returns the stream
// NOTE: Callers are responsible for disposing the stream!
protected override MemoryStream LoadFile(string filename)

View file

@ -343,8 +343,6 @@ namespace CodeImp.DoomBuilder.Data
// This finds and returns a sprite stream
public override Stream GetDecorateData(string pname)
{
string pfilename = pname.Replace('\\', '^');
// Error when suspended
if(issuspended) throw new Exception("Data reader is suspended");
@ -356,10 +354,13 @@ namespace CodeImp.DoomBuilder.Data
}
// Find in root directory
string filename = FindFirstFile(rootpath, pfilename);
if((filename != null) && FileExists(filename))
string filename = Path.GetFileName(pname);
string pathname = Path.GetDirectoryName(pname);
string fullpath = Path.Combine(rootpath, pathname);
string foundfile = filename.IndexOf('.') > -1 ? FindFirstFileWithExt(fullpath, filename) : FindFirstFile(fullpath, filename);
if((foundfile != null) && FileExists(foundfile))
{
return LoadFile(filename);
return LoadFile(foundfile);
}
// Nothing found
@ -429,6 +430,9 @@ namespace CodeImp.DoomBuilder.Data
// This must find the first file that has the specific name, regardless of file extension
protected abstract string FindFirstFile(string path, string beginswith);
// This must find the first file that has the specific name
protected abstract string FindFirstFileWithExt(string path, string beginswith);
// This must load an entire file in memory and returns the stream
// NOTE: Callers are responsible for disposing the stream!

View file

@ -40,6 +40,7 @@ namespace CodeImp.DoomBuilder.Decorate
#region ================== Variables
// Declaration
private string classname;
private string inheritclass;
private string replaceclass;
private int doomednum = -1;
@ -63,6 +64,7 @@ namespace CodeImp.DoomBuilder.Decorate
#region ================== Properties
public Dictionary<string, bool> Flags { get { return flags; } }
public string Name { get { return classname; } }
public int Radius { get { return radius; } }
public int Height { get { return height; } }
public int DoomEdNum { get { return doomednum; } }
@ -78,6 +80,15 @@ namespace CodeImp.DoomBuilder.Decorate
flags = new Dictionary<string, bool>();
states = new List<StateStructure>();
// First next token is the class name
parser.SkipWhitespace(true);
classname = parser.ReadToken();
if(string.IsNullOrEmpty(classname))
{
parser.ReportError("Expected actor class name");
return;
}
// Parse tokens before entering the actor scope
while(parser.SkipWhitespace(true))
{
@ -96,7 +107,7 @@ namespace CodeImp.DoomBuilder.Decorate
return;
}
}
else if(replaceclass == "replaces")
else if(token == "replaces")
{
// The next token must be the class to replace
parser.SkipWhitespace(true);
@ -119,7 +130,7 @@ namespace CodeImp.DoomBuilder.Decorate
if(!int.TryParse(token, out doomednum))
{
// Not numeric!
parser.ReportError("Expected numeric editor thing number");
parser.ReportError("Expected numeric editor thing number or start of actor scope");
return;
}
}
@ -184,7 +195,7 @@ namespace CodeImp.DoomBuilder.Decorate
if(labeltoken == ":")
{
// Parse actor state
StateStructure st = new StateStructure(parser);
StateStructure st = new StateStructure(parser, statename);
states.Add(st);
if(parser.HasError) return;
}
@ -227,7 +238,7 @@ namespace CodeImp.DoomBuilder.Decorate
if(!string.IsNullOrEmpty(value))
{
// Try parsing as integer value
int intvalue = 0;
int intvalue;
int.TryParse(value, out intvalue);
// Set the property

View file

@ -34,8 +34,8 @@ namespace CodeImp.DoomBuilder.Decorate
public sealed class DecorateParser
{
#region ================== Delegates
public delegate void IncludeDelegate(string includefile);
public delegate void IncludeDelegate(DecorateParser parser, string includefile);
public IncludeDelegate OnInclude;
@ -56,21 +56,24 @@ namespace CodeImp.DoomBuilder.Decorate
// Input data stream
private Stream datastream;
private StreamReader datareader;
private BinaryReader datareader;
private string sourcename;
// Error report
private int errorline;
private string errordesc;
private string errorsource;
#endregion
#region ================== Properties
internal Stream DataStream { get { return datastream; } }
internal StreamReader DataReader { get { return datareader; } }
internal BinaryReader DataReader { get { return datareader; } }
public ICollection<ActorStructure> Actors { get { return actors; } }
public int ErrorLine { get { return errorline; } }
public string ErrorDescription { get { return errordesc; } }
public string ErrorSource { get { return errorsource; } }
public bool HasError { get { return (errordesc != null); } }
#endregion
@ -91,12 +94,14 @@ namespace CodeImp.DoomBuilder.Decorate
// This parses the given decorate stream
// Returns false on errors
public bool Parse(Stream stream)
public bool Parse(Stream stream, string sourcefilename)
{
Stream localstream = stream;
StreamReader localreader = new StreamReader(localstream, Encoding.ASCII);
string localsourcename = sourcefilename;
BinaryReader localreader = new BinaryReader(localstream, Encoding.ASCII);
datastream = localstream;
datareader = localreader;
sourcename = localsourcename;
datastream.Seek(0, SeekOrigin.Begin);
// Continue until at the end of the stream
@ -112,6 +117,8 @@ namespace CodeImp.DoomBuilder.Decorate
// Read actor structure
ActorStructure actor = new ActorStructure(this);
if(this.HasError) break;
General.WriteLogLine("Added actor '" + actor.Name + "' from '" + localsourcename + "'");
actors.Add(actor);
}
else if(objdeclaration == "#include")
{
@ -120,9 +127,16 @@ namespace CodeImp.DoomBuilder.Decorate
string filename = ReadToken();
if(!string.IsNullOrEmpty(filename))
{
if(OnInclude != null) OnInclude(filename);
// Strip the quotes
filename = filename.Replace("\"", "");
// Callback to parse this file now
if(OnInclude != null) OnInclude(this, filename);
// Set our buffers back to continue parsing
datastream = localstream;
datareader = localreader;
sourcename = localsourcename;
if(HasError) break;
}
else
@ -134,8 +148,23 @@ namespace CodeImp.DoomBuilder.Decorate
else
{
// Unknown structure!
ReportError("Unknown declaration type '" + objdeclaration + "'");
break;
// Best we can do now is just find the first { and the follow the scopes until the matching } is found
string token2;
do
{
SkipWhitespace(true);
token2 = ReadToken();
}
while(token2 != "{");
int scopelevel = 1;
do
{
SkipWhitespace(true);
token2 = ReadToken();
if(token2 == "{") scopelevel++;
if(token2 == "}") scopelevel--;
}
while(scopelevel > 0);
}
}
}
@ -170,16 +199,45 @@ namespace CodeImp.DoomBuilder.Decorate
// Returns false when the end of the stream is reached
internal bool SkipWhitespace(bool skipnewline)
{
int offset = skipnewline ? 1 : 0;
char[] cb = new char[1];
int c;
int offset = skipnewline ? 0 : 1;
char c;
do
{
c = datareader.Read(cb, 0, 1);
if(c == -1) return false;
if(datastream.Position == datastream.Length) return false;
c = (char)datareader.ReadByte();
// Check if this is comment
if(c == '/')
{
char c2 = (char)datareader.ReadByte();
if(c2 == '/')
{
// Skip entire line
char c3;
do { c3 = (char)datareader.ReadByte(); } while(c3 != '\n');
c = ' ';
}
else if(c2 == '*')
{
// Skip until */
char c4, c3 = '\0';
do
{
c4 = c3;
c3 = (char)datareader.ReadByte();
}
while((c4 != '*') || (c3 != '/'));
c = ' ';
}
else
{
// Not a comment, rewind from reading c2
datastream.Seek(-1, SeekOrigin.Current);
}
}
}
while(WHITESPACE.IndexOf(unchecked(cb[0]), offset) > -1);
while(WHITESPACE.IndexOf(c, offset) > -1);
// Go one character back so we can read this non-whitespace character again
datastream.Seek(-1, SeekOrigin.Current);
@ -192,25 +250,22 @@ namespace CodeImp.DoomBuilder.Decorate
{
string token = "";
bool quotedstring = false;
int c;
// Return null when the end of the stream has been reached
if(datareader.EndOfStream) return null;
if(datastream.Position == datastream.Length) return null;
// Start reading
c = datareader.Read();
while((c != -1) && (!IsWhitespace(unchecked((char)c)) || quotedstring))
char c = (char)datareader.ReadByte();
while(!IsWhitespace(c) || quotedstring || IsSpecialToken(c))
{
char cc = unchecked((char)c);
// Special token?
if(!quotedstring && IsSpecialToken(cc))
if(!quotedstring && IsSpecialToken(c))
{
// Not reading a token yet?
if(token.Length == 0)
{
// This is our whole token
token += cc;
token += c;
break;
}
else
@ -224,16 +279,19 @@ namespace CodeImp.DoomBuilder.Decorate
else
{
// Quote to end the string?
if(quotedstring && (cc == '"')) quotedstring = false;
if(quotedstring && (c == '"')) quotedstring = false;
// First character is a quote?
if((token.Length == 0) && (cc == '"')) quotedstring = true;
if((token.Length == 0) && (c == '"')) quotedstring = true;
token += cc;
token += c;
}
// Next character
c = datareader.Read();
if(datastream.Position < datastream.Length)
c = (char)datareader.Read();
else
break;
}
return token;
@ -243,14 +301,17 @@ namespace CodeImp.DoomBuilder.Decorate
internal void ReportError(string message)
{
long position = datastream.Position;
long readpos = 0;
int linenumber = 1;
// Find the line on which we found this error
datastream.Seek(0, SeekOrigin.Begin);
while(datastream.Position < position)
StreamReader textreader = new StreamReader(datastream, Encoding.ASCII);
while(readpos < position)
{
string line = datareader.ReadLine();
string line = textreader.ReadLine();
if(line == null) break;
readpos += line.Length + 2;
linenumber++;
}
@ -260,6 +321,7 @@ namespace CodeImp.DoomBuilder.Decorate
// Set error information
errordesc = message;
errorline = linenumber;
errorsource = sourcename;
}
#endregion

View file

@ -53,7 +53,7 @@ namespace CodeImp.DoomBuilder.Decorate
#region ================== Constructor / Disposer
// Constructor
internal StateStructure(DecorateParser parser)
internal StateStructure(DecorateParser parser, string statename)
{
string lasttoken = "";
firstsprite = null;
@ -68,8 +68,7 @@ namespace CodeImp.DoomBuilder.Decorate
// One of the flow control statements?
if((token == "loop") || (token == "stop") || (token == "wait") || (token == "fail"))
{
// Then we leave
break;
// Ignore flow control
}
// Label?
else if(token == ":")
@ -83,6 +82,9 @@ namespace CodeImp.DoomBuilder.Decorate
// End of scope?
else if(token == "}")
{
// Rewind so that this scope end can be read again
parser.DataStream.Seek(-1, SeekOrigin.Current);
// Done here
return;
}
@ -103,6 +105,15 @@ namespace CodeImp.DoomBuilder.Decorate
parser.ReportError("Unexpected end of structure");
return;
}
// Label?
else if(spriteframes == ":")
{
// Rewind so that this label can be read again
parser.DataStream.Seek(-(token.Length + 1), SeekOrigin.Current);
// Done here
return;
}
// No first sprite yet?
if((firstsprite == null) && (spriteframes.Length > 0))