mirror of
https://git.do.srb2.org/STJr/UltimateZoneBuilder.git
synced 2025-01-31 04:40:55 +00:00
@working on decorate support
This commit is contained in:
parent
1694d828d1
commit
76ec8a8c98
7 changed files with 172 additions and 47 deletions
|
@ -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
|
||||
|
|
|
@ -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!
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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!
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
|
|
Loading…
Reference in a new issue