mirror of
https://github.com/TTimo/GtkRadiant.git
synced 2024-11-10 07:11:54 +00:00
fixed crash loading quake4 1.3 entity definitions
git-svn-id: svn://svn.icculus.org/gtkradiant/GtkRadiant/trunk@100 8a3a26a2-13c4-0310-b231-cf6edde360e5
This commit is contained in:
parent
3e076b28de
commit
3f1cbdde23
3 changed files with 223 additions and 106 deletions
10
CHANGES
10
CHANGES
|
@ -1,6 +1,16 @@
|
|||
This is the changelog for developers, != changelog for the end user
|
||||
that we distribute with the binaries. (see changelog)
|
||||
|
||||
22/08/2006
|
||||
SPoG
|
||||
- Added VFS support for locating the archive a file was loaded from.
|
||||
- Changed Doom3 entity definition parser to gracefully handle parse errors.
|
||||
- Fixed crash when loading entity definitions in quake4 1.3 point release.
|
||||
|
||||
13/08/2006
|
||||
SPoG
|
||||
- Disabled 'detail' content flag checkbox in quake2 Surface Inspector.
|
||||
|
||||
22/07/2006
|
||||
SPoG
|
||||
- Fixed doom3 func_static with model not appearing to move when dragged.
|
||||
|
|
|
@ -57,6 +57,7 @@ ArchiveModules& FileSystemQ3API_getArchiveModules();
|
|||
|
||||
#include "generic/callback.h"
|
||||
#include "string/string.h"
|
||||
#include "container/array.h"
|
||||
#include "stream/stringstream.h"
|
||||
#include "os/path.h"
|
||||
#include "moduleobservers.h"
|
||||
|
@ -141,7 +142,14 @@ static void InitPakFile (ArchiveModules& archiveModules, const char *filename)
|
|||
if(table != 0)
|
||||
{
|
||||
archive_entry_t entry;
|
||||
entry.name = filename;
|
||||
|
||||
std::size_t length = string_length(filename);
|
||||
Array<char> tmp(length + 2);
|
||||
std::copy(filename, filename + length, tmp.begin());
|
||||
tmp[length] = ':';
|
||||
tmp[length + 1] = '\0';
|
||||
entry.name = tmp.begin();
|
||||
|
||||
entry.archive = table->m_pfnOpenArchive(filename);
|
||||
entry.is_pakfile = true;
|
||||
g_archives.push_back(entry);
|
||||
|
@ -520,7 +528,7 @@ const char* FindFile(const char* relative)
|
|||
{
|
||||
for(archives_t::iterator i = g_archives.begin(); i != g_archives.end(); ++i)
|
||||
{
|
||||
if(!(*i).is_pakfile && (*i).archive->containsFile(relative))
|
||||
if((*i).archive->containsFile(relative))
|
||||
{
|
||||
return (*i).name.c_str();
|
||||
}
|
||||
|
@ -533,7 +541,7 @@ const char* FindPath(const char* absolute)
|
|||
{
|
||||
for(archives_t::iterator i = g_archives.begin(); i != g_archives.end(); ++i)
|
||||
{
|
||||
if(!(*i).is_pakfile && path_equal_n(absolute, (*i).name.c_str(), string_length((*i).name.c_str())))
|
||||
if(path_equal_n(absolute, (*i).name.c_str(), string_length((*i).name.c_str())))
|
||||
{
|
||||
return (*i).name.c_str();
|
||||
}
|
||||
|
|
|
@ -86,21 +86,66 @@ void EntityClassDoom3_forEach(EntityClassVisitor& visitor)
|
|||
}
|
||||
}
|
||||
|
||||
void EntityClassDoom3_parseUnknown(Tokeniser& tokeniser)
|
||||
inline void printParseError(const char* message)
|
||||
{
|
||||
globalErrorStream() << message;
|
||||
}
|
||||
|
||||
#define PARSE_RETURN_FALSE_IF_FAIL(expression) if(!(expression)) { printParseError(FILE_LINE "\nparse failed: " #expression "\n"); return false; } else
|
||||
|
||||
bool EntityClassDoom3_parseToken(Tokeniser& tokeniser)
|
||||
{
|
||||
const char* token = tokeniser.getToken();
|
||||
PARSE_RETURN_FALSE_IF_FAIL(token != 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EntityClassDoom3_parseToken(Tokeniser& tokeniser, const char* string)
|
||||
{
|
||||
const char* token = tokeniser.getToken();
|
||||
PARSE_RETURN_FALSE_IF_FAIL(token != 0);
|
||||
return string_equal(token, string);
|
||||
}
|
||||
|
||||
bool EntityClassDoom3_parseString(Tokeniser& tokeniser, const char*& s)
|
||||
{
|
||||
const char* token = tokeniser.getToken();
|
||||
PARSE_RETURN_FALSE_IF_FAIL(token != 0);
|
||||
s = token;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EntityClassDoom3_parseString(Tokeniser& tokeniser, CopiedString& s)
|
||||
{
|
||||
const char* token = tokeniser.getToken();
|
||||
PARSE_RETURN_FALSE_IF_FAIL(token != 0);
|
||||
s = token;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EntityClassDoom3_parseString(Tokeniser& tokeniser, StringOutputStream& s)
|
||||
{
|
||||
const char* token = tokeniser.getToken();
|
||||
PARSE_RETURN_FALSE_IF_FAIL(token != 0);
|
||||
s << token;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EntityClassDoom3_parseUnknown(Tokeniser& tokeniser)
|
||||
{
|
||||
//const char* name =
|
||||
tokeniser.getToken();
|
||||
PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser));
|
||||
|
||||
//globalOutputStream() << "parsing unknown block " << makeQuoted(name) << "\n";
|
||||
|
||||
const char* token = tokeniser.getToken();
|
||||
ASSERT_MESSAGE(string_equal(token, "{"), "error parsing entity definition");
|
||||
PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser, "{"));
|
||||
tokeniser.nextLine();
|
||||
|
||||
std::size_t depth = 1;
|
||||
for(;;)
|
||||
{
|
||||
const char* token = tokeniser.getToken();
|
||||
const char* token;
|
||||
PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, token));
|
||||
if(string_equal(token, "}"))
|
||||
{
|
||||
if(--depth == 0)
|
||||
|
@ -115,6 +160,7 @@ void EntityClassDoom3_parseUnknown(Tokeniser& tokeniser)
|
|||
}
|
||||
tokeniser.nextLine();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -159,19 +205,20 @@ void Model_resolveInheritance(const char* name, Model& model)
|
|||
}
|
||||
}
|
||||
|
||||
void EntityClassDoom3_parseModel(Tokeniser& tokeniser)
|
||||
bool EntityClassDoom3_parseModel(Tokeniser& tokeniser)
|
||||
{
|
||||
const char* name = tokeniser.getToken();
|
||||
const char* name;
|
||||
PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, name));
|
||||
|
||||
Model& model = g_models[name];
|
||||
|
||||
const char* token = tokeniser.getToken();
|
||||
ASSERT_MESSAGE(string_equal(token, "{"), "error parsing model definition");
|
||||
PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser, "{"));
|
||||
tokeniser.nextLine();
|
||||
|
||||
for(;;)
|
||||
{
|
||||
const char* parameter = tokeniser.getToken();
|
||||
const char* parameter;
|
||||
PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, parameter));
|
||||
if(string_equal(parameter, "}"))
|
||||
{
|
||||
tokeniser.nextLine();
|
||||
|
@ -179,38 +226,43 @@ void EntityClassDoom3_parseModel(Tokeniser& tokeniser)
|
|||
}
|
||||
else if(string_equal(parameter, "inherit"))
|
||||
{
|
||||
model.m_parent = tokeniser.getToken();
|
||||
PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, model.m_parent));
|
||||
tokeniser.nextLine();
|
||||
}
|
||||
else if(string_equal(parameter, "remove"))
|
||||
{
|
||||
//const char* remove =
|
||||
tokeniser.getToken();
|
||||
PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser));
|
||||
tokeniser.nextLine();
|
||||
}
|
||||
else if(string_equal(parameter, "mesh"))
|
||||
{
|
||||
model.m_mesh = tokeniser.getToken();
|
||||
PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, model.m_mesh));
|
||||
tokeniser.nextLine();
|
||||
}
|
||||
else if(string_equal(parameter, "skin"))
|
||||
{
|
||||
model.m_skin = tokeniser.getToken();
|
||||
PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, model.m_skin));
|
||||
tokeniser.nextLine();
|
||||
}
|
||||
else if(string_equal(parameter, "offset"))
|
||||
{
|
||||
tokeniser.getToken(); // (
|
||||
tokeniser.getToken();
|
||||
tokeniser.getToken();
|
||||
tokeniser.getToken();
|
||||
tokeniser.getToken(); // )
|
||||
PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser, "("));
|
||||
PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser));
|
||||
PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser));
|
||||
PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser));
|
||||
PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser, ")"));
|
||||
tokeniser.nextLine();
|
||||
}
|
||||
else if(string_equal(parameter, "channel"))
|
||||
{
|
||||
//const char* channelName =
|
||||
tokeniser.getToken();
|
||||
tokeniser.getToken(); // (
|
||||
PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser));
|
||||
PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser, "("));
|
||||
for(;;)
|
||||
{
|
||||
const char* end = tokeniser.getToken();
|
||||
const char* end;
|
||||
PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, end));
|
||||
if(string_equal(end, ")"))
|
||||
{
|
||||
tokeniser.nextLine();
|
||||
|
@ -220,23 +272,27 @@ void EntityClassDoom3_parseModel(Tokeniser& tokeniser)
|
|||
}
|
||||
else if(string_equal(parameter, "anim"))
|
||||
{
|
||||
CopiedString animName(tokeniser.getToken());
|
||||
const char* animFile = tokeniser.getToken();
|
||||
CopiedString animName;
|
||||
PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, animName));
|
||||
const char* animFile;
|
||||
PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, animFile));
|
||||
model.m_anims.insert(Model::Anims::value_type(animName, animFile));
|
||||
|
||||
const char* token = tokeniser.getToken();
|
||||
const char* token;
|
||||
PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, token));
|
||||
|
||||
while(string_equal(token, ","))
|
||||
{
|
||||
animFile = tokeniser.getToken();
|
||||
token = tokeniser.getToken();
|
||||
PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, animFile));
|
||||
PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, token));
|
||||
}
|
||||
|
||||
if(string_equal(token, "{"))
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
const char* end = tokeniser.getToken();
|
||||
const char* end;
|
||||
PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, end));
|
||||
if(string_equal(end, "}"))
|
||||
{
|
||||
tokeniser.nextLine();
|
||||
|
@ -252,10 +308,12 @@ void EntityClassDoom3_parseModel(Tokeniser& tokeniser)
|
|||
}
|
||||
else
|
||||
{
|
||||
ERROR_MESSAGE("unknown model parameter: " << makeQuoted(parameter));
|
||||
globalErrorStream() << "unknown model parameter: " << makeQuoted(parameter) << "\n";
|
||||
return false;
|
||||
}
|
||||
tokeniser.nextLine();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool char_isSpaceOrTab(char c)
|
||||
|
@ -292,15 +350,11 @@ inline const char* string_findFirstNonSpaceOrTab(const char* string)
|
|||
}
|
||||
|
||||
|
||||
void EntityClassDoom3_parseEntityDef(Tokeniser& tokeniser)
|
||||
static bool EntityClass_parse(EntityClass& entityClass, Tokeniser& tokeniser)
|
||||
{
|
||||
EntityClass* entityClass = Eclass_Alloc();
|
||||
entityClass->free = &Eclass_Free;
|
||||
PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, entityClass.m_name));
|
||||
|
||||
entityClass->m_name = tokeniser.getToken();
|
||||
|
||||
const char* token = tokeniser.getToken();
|
||||
ASSERT_MESSAGE(string_equal(token, "{"), "error parsing entity definition");
|
||||
PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser, "{"));
|
||||
tokeniser.nextLine();
|
||||
|
||||
StringOutputStream usage(256);
|
||||
|
@ -310,7 +364,8 @@ void EntityClassDoom3_parseEntityDef(Tokeniser& tokeniser)
|
|||
|
||||
for(;;)
|
||||
{
|
||||
const char* key = tokeniser.getToken();
|
||||
const char* key;
|
||||
PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, key));
|
||||
|
||||
const char* last = string_findFirstSpaceOrTab(key);
|
||||
CopiedString first(StringRange(key, last));
|
||||
|
@ -323,7 +378,8 @@ void EntityClassDoom3_parseEntityDef(Tokeniser& tokeniser)
|
|||
if(currentString != 0 && string_equal(key, "\\"))
|
||||
{
|
||||
tokeniser.nextLine();
|
||||
*currentString << " " << tokeniser.getToken();
|
||||
*currentString << " ";
|
||||
PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, *currentString));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -342,58 +398,62 @@ void EntityClassDoom3_parseEntityDef(Tokeniser& tokeniser)
|
|||
}
|
||||
else if(string_equal(key, "model"))
|
||||
{
|
||||
entityClass->fixedsize = true;
|
||||
const char* token;
|
||||
PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, token));
|
||||
entityClass.fixedsize = true;
|
||||
StringOutputStream buffer(256);
|
||||
buffer << PathCleaned(tokeniser.getToken());
|
||||
entityClass->m_modelpath = buffer.c_str();
|
||||
buffer << PathCleaned(token);
|
||||
entityClass.m_modelpath = buffer.c_str();
|
||||
}
|
||||
else if(string_equal(key, "editor_color"))
|
||||
{
|
||||
const char* value = tokeniser.getToken();
|
||||
const char* value;
|
||||
PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, value));
|
||||
if(!string_empty(value))
|
||||
{
|
||||
entityClass->colorSpecified = true;
|
||||
bool success = string_parse_vector3(value, entityClass->color);
|
||||
entityClass.colorSpecified = true;
|
||||
bool success = string_parse_vector3(value, entityClass.color);
|
||||
ASSERT_MESSAGE(success, "editor_color: parse error");
|
||||
}
|
||||
}
|
||||
else if(string_equal(key, "editor_ragdoll"))
|
||||
{
|
||||
//bool ragdoll = atoi(tokeniser.getToken()) != 0;
|
||||
tokeniser.getToken();
|
||||
PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser));
|
||||
}
|
||||
else if(string_equal(key, "editor_mins"))
|
||||
{
|
||||
entityClass->sizeSpecified = true;
|
||||
const char* value = tokeniser.getToken();
|
||||
entityClass.sizeSpecified = true;
|
||||
const char* value;
|
||||
PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, value));
|
||||
if(!string_empty(value) && !string_equal(value, "?"))
|
||||
{
|
||||
entityClass->fixedsize = true;
|
||||
bool success = string_parse_vector3(value, entityClass->mins);
|
||||
entityClass.fixedsize = true;
|
||||
bool success = string_parse_vector3(value, entityClass.mins);
|
||||
ASSERT_MESSAGE(success, "editor_mins: parse error");
|
||||
}
|
||||
}
|
||||
else if(string_equal(key, "editor_maxs"))
|
||||
{
|
||||
entityClass->sizeSpecified = true;
|
||||
const char* value = tokeniser.getToken();
|
||||
entityClass.sizeSpecified = true;
|
||||
const char* value;
|
||||
PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, value));
|
||||
if(!string_empty(value) && !string_equal(value, "?"))
|
||||
{
|
||||
entityClass->fixedsize = true;
|
||||
bool success = string_parse_vector3(value, entityClass->maxs);
|
||||
entityClass.fixedsize = true;
|
||||
bool success = string_parse_vector3(value, entityClass.maxs);
|
||||
ASSERT_MESSAGE(success, "editor_maxs: parse error");
|
||||
}
|
||||
}
|
||||
else if(string_equal(key, "editor_usage"))
|
||||
{
|
||||
const char* value = tokeniser.getToken();
|
||||
usage << value;
|
||||
PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, usage));
|
||||
currentString = &usage;
|
||||
}
|
||||
else if(string_equal_n(key, "editor_usage", 12))
|
||||
{
|
||||
const char* value = tokeniser.getToken();
|
||||
usage << "\n" << value;
|
||||
usage << "\n";
|
||||
PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, usage));
|
||||
currentString = &usage;
|
||||
}
|
||||
else if(string_equal(key, "editor_rotatable")
|
||||
|
@ -405,139 +465,167 @@ void EntityClassDoom3_parseEntityDef(Tokeniser& tokeniser)
|
|||
|| (!string_empty(last) && string_equal(first.c_str(), "editor_gui"))
|
||||
|| string_equal_n(key, "editor_copy", 11))
|
||||
{
|
||||
tokeniser.getToken();
|
||||
PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser));
|
||||
}
|
||||
else if(!string_empty(last) && (string_equal(first.c_str(), "editor_var") || string_equal(first.c_str(), "editor_string")))
|
||||
{
|
||||
EntityClassAttribute& attribute = EntityClass_insertAttribute(*entityClass, last).second;
|
||||
EntityClassAttribute& attribute = EntityClass_insertAttribute(entityClass, last).second;
|
||||
attribute.m_type = "string";
|
||||
currentDescription = &attribute.m_description;
|
||||
currentString = &description;
|
||||
description << tokeniser.getToken();
|
||||
PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, description));
|
||||
}
|
||||
else if(!string_empty(last) && string_equal(first.c_str(), "editor_float"))
|
||||
{
|
||||
EntityClassAttribute& attribute = EntityClass_insertAttribute(*entityClass, last).second;
|
||||
EntityClassAttribute& attribute = EntityClass_insertAttribute(entityClass, last).second;
|
||||
attribute.m_type = "string";
|
||||
currentDescription = &attribute.m_description;
|
||||
currentString = &description;
|
||||
description << tokeniser.getToken();
|
||||
PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, description));
|
||||
}
|
||||
else if(!string_empty(last) && string_equal(first.c_str(), "editor_snd"))
|
||||
{
|
||||
EntityClassAttribute& attribute = EntityClass_insertAttribute(*entityClass, last).second;
|
||||
EntityClassAttribute& attribute = EntityClass_insertAttribute(entityClass, last).second;
|
||||
attribute.m_type = "sound";
|
||||
currentDescription = &attribute.m_description;
|
||||
currentString = &description;
|
||||
description << tokeniser.getToken();
|
||||
PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, description));
|
||||
}
|
||||
else if(!string_empty(last) && string_equal(first.c_str(), "editor_bool"))
|
||||
{
|
||||
EntityClassAttribute& attribute = EntityClass_insertAttribute(*entityClass, last).second;
|
||||
EntityClassAttribute& attribute = EntityClass_insertAttribute(entityClass, last).second;
|
||||
attribute.m_type = "boolean";
|
||||
currentDescription = &attribute.m_description;
|
||||
currentString = &description;
|
||||
description << tokeniser.getToken();
|
||||
PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, description));
|
||||
}
|
||||
else if(!string_empty(last) && string_equal(first.c_str(), "editor_int"))
|
||||
{
|
||||
EntityClassAttribute& attribute = EntityClass_insertAttribute(*entityClass, last).second;
|
||||
EntityClassAttribute& attribute = EntityClass_insertAttribute(entityClass, last).second;
|
||||
attribute.m_type = "integer";
|
||||
currentDescription = &attribute.m_description;
|
||||
currentString = &description;
|
||||
description << tokeniser.getToken();
|
||||
PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, description));
|
||||
}
|
||||
else if(!string_empty(last) && string_equal(first.c_str(), "editor_model"))
|
||||
{
|
||||
EntityClassAttribute& attribute = EntityClass_insertAttribute(*entityClass, last).second;
|
||||
EntityClassAttribute& attribute = EntityClass_insertAttribute(entityClass, last).second;
|
||||
attribute.m_type = "model";
|
||||
currentDescription = &attribute.m_description;
|
||||
currentString = &description;
|
||||
description << tokeniser.getToken();
|
||||
PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, description));
|
||||
}
|
||||
else if(!string_empty(last) && string_equal(first.c_str(), "editor_color"))
|
||||
{
|
||||
EntityClassAttribute& attribute = EntityClass_insertAttribute(*entityClass, last).second;
|
||||
EntityClassAttribute& attribute = EntityClass_insertAttribute(entityClass, last).second;
|
||||
attribute.m_type = "color";
|
||||
currentDescription = &attribute.m_description;
|
||||
currentString = &description;
|
||||
description << tokeniser.getToken();
|
||||
PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, description));
|
||||
}
|
||||
else if(!string_empty(last) && (string_equal(first.c_str(), "editor_material") || string_equal(first.c_str(), "editor_mat")))
|
||||
{
|
||||
EntityClassAttribute& attribute = EntityClass_insertAttribute(*entityClass, last).second;
|
||||
EntityClassAttribute& attribute = EntityClass_insertAttribute(entityClass, last).second;
|
||||
attribute.m_type = "shader";
|
||||
currentDescription = &attribute.m_description;
|
||||
currentString = &description;
|
||||
description << tokeniser.getToken();
|
||||
PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, description));
|
||||
}
|
||||
else if(string_equal(key, "inherit"))
|
||||
{
|
||||
entityClass->inheritanceResolved = false;
|
||||
ASSERT_MESSAGE(entityClass->m_parent.empty(), "only one 'inherit' supported per entityDef");
|
||||
entityClass->m_parent.push_back(tokeniser.getToken());
|
||||
entityClass.inheritanceResolved = false;
|
||||
ASSERT_MESSAGE(entityClass.m_parent.empty(), "only one 'inherit' supported per entityDef");
|
||||
const char* token;
|
||||
PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, token));
|
||||
entityClass.m_parent.push_back(token);
|
||||
}
|
||||
// begin quake4-specific keys
|
||||
else if(string_equal(key, "editor_targetonsel"))
|
||||
{
|
||||
//const char* value =
|
||||
tokeniser.getToken();
|
||||
PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser));
|
||||
}
|
||||
else if(string_equal(key, "editor_menu"))
|
||||
{
|
||||
//const char* value =
|
||||
tokeniser.getToken();
|
||||
PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser));
|
||||
}
|
||||
else if(string_equal(key, "editor_ignore"))
|
||||
{
|
||||
//const char* value =
|
||||
tokeniser.getToken();
|
||||
PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser));
|
||||
}
|
||||
// end quake4-specific keys
|
||||
else
|
||||
{
|
||||
CopiedString tmp(key);
|
||||
ASSERT_MESSAGE(!string_equal_n(key, "editor_", 7), "unsupported editor key: " << makeQuoted(key));
|
||||
EntityClassAttribute& attribute = EntityClass_insertAttribute(*entityClass, key).second;
|
||||
EntityClassAttribute& attribute = EntityClass_insertAttribute(entityClass, key).second;
|
||||
attribute.m_type = "string";
|
||||
attribute.m_value = tokeniser.getToken();
|
||||
const char* value;
|
||||
PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, value));
|
||||
if(string_equal(value, "}")) // hack for quake4 powerups.def bug
|
||||
{
|
||||
globalErrorStream() << "entityDef " << makeQuoted(entityClass.m_name.c_str()) << " key " << makeQuoted(tmp.c_str()) << " has no value\n";
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
attribute.m_value = value;
|
||||
}
|
||||
}
|
||||
tokeniser.nextLine();
|
||||
}
|
||||
|
||||
entityClass->m_comments = usage.c_str();
|
||||
entityClass.m_comments = usage.c_str();
|
||||
|
||||
if(string_equal(entityClass->m_name.c_str(), "light"))
|
||||
if(string_equal(entityClass.m_name.c_str(), "light"))
|
||||
{
|
||||
{
|
||||
EntityClassAttribute& attribute = EntityClass_insertAttribute(*entityClass, "light_radius").second;
|
||||
EntityClassAttribute& attribute = EntityClass_insertAttribute(entityClass, "light_radius").second;
|
||||
attribute.m_type = "vector3";
|
||||
attribute.m_value = "300 300 300";
|
||||
}
|
||||
{
|
||||
EntityClassAttribute& attribute = EntityClass_insertAttribute(*entityClass, "light_center").second;
|
||||
EntityClassAttribute& attribute = EntityClass_insertAttribute(entityClass, "light_center").second;
|
||||
attribute.m_type = "vector3";
|
||||
}
|
||||
{
|
||||
EntityClassAttribute& attribute = EntityClass_insertAttribute(*entityClass, "noshadows").second;
|
||||
EntityClassAttribute& attribute = EntityClass_insertAttribute(entityClass, "noshadows").second;
|
||||
attribute.m_type = "boolean";
|
||||
attribute.m_value = "0";
|
||||
}
|
||||
{
|
||||
EntityClassAttribute& attribute = EntityClass_insertAttribute(*entityClass, "nospecular").second;
|
||||
EntityClassAttribute& attribute = EntityClass_insertAttribute(entityClass, "nospecular").second;
|
||||
attribute.m_type = "boolean";
|
||||
attribute.m_value = "0";
|
||||
}
|
||||
{
|
||||
EntityClassAttribute& attribute = EntityClass_insertAttribute(*entityClass, "nodiffuse").second;
|
||||
EntityClassAttribute& attribute = EntityClass_insertAttribute(entityClass, "nodiffuse").second;
|
||||
attribute.m_type = "boolean";
|
||||
attribute.m_value = "0";
|
||||
}
|
||||
{
|
||||
EntityClassAttribute& attribute = EntityClass_insertAttribute(*entityClass, "falloff").second;
|
||||
EntityClassAttribute& attribute = EntityClass_insertAttribute(entityClass, "falloff").second;
|
||||
attribute.m_type = "real";
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EntityClassDoom3_parseEntityDef(Tokeniser& tokeniser)
|
||||
{
|
||||
EntityClass* entityClass = Eclass_Alloc();
|
||||
entityClass->free = &Eclass_Free;
|
||||
|
||||
if(!EntityClass_parse(*entityClass, tokeniser))
|
||||
{
|
||||
eclass_capture_state(entityClass); // finish constructing the entity so that it can be destroyed cleanly.
|
||||
entityClass->free(entityClass);
|
||||
return false;
|
||||
}
|
||||
|
||||
EntityClass* inserted = EntityClassDoom3_insertUnique(entityClass);
|
||||
if(inserted != entityClass)
|
||||
{
|
||||
|
@ -545,9 +633,26 @@ void EntityClassDoom3_parseEntityDef(Tokeniser& tokeniser)
|
|||
eclass_capture_state(entityClass); // finish constructing the entity so that it can be destroyed cleanly.
|
||||
entityClass->free(entityClass);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void EntityClassDoom3_parse(TextInputStream& inputStream)
|
||||
bool EntityClassDoom3_parseBlock(Tokeniser& tokeniser, const char* blockType)
|
||||
{
|
||||
if(string_equal(blockType, "entityDef"))
|
||||
{
|
||||
return EntityClassDoom3_parseEntityDef(tokeniser);
|
||||
}
|
||||
else if(string_equal(blockType, "model"))
|
||||
{
|
||||
return EntityClassDoom3_parseModel(tokeniser);
|
||||
}
|
||||
else
|
||||
{
|
||||
return EntityClassDoom3_parseUnknown(tokeniser);
|
||||
}
|
||||
}
|
||||
|
||||
bool EntityClassDoom3_parse(TextInputStream& inputStream, const char* filename)
|
||||
{
|
||||
Tokeniser& tokeniser = GlobalScriptLibrary().m_pfnNewScriptTokeniser(inputStream);
|
||||
|
||||
|
@ -558,19 +663,13 @@ void EntityClassDoom3_parse(TextInputStream& inputStream)
|
|||
const char* blockType = tokeniser.getToken();
|
||||
if(blockType == 0)
|
||||
{
|
||||
break;
|
||||
return true;
|
||||
}
|
||||
if(string_equal(blockType, "entityDef"))
|
||||
CopiedString tmp(blockType);
|
||||
if(!EntityClassDoom3_parseBlock(tokeniser, tmp.c_str()))
|
||||
{
|
||||
EntityClassDoom3_parseEntityDef(tokeniser);
|
||||
}
|
||||
else if(string_equal(blockType, "model"))
|
||||
{
|
||||
EntityClassDoom3_parseModel(tokeniser);
|
||||
}
|
||||
else
|
||||
{
|
||||
EntityClassDoom3_parseUnknown(tokeniser);
|
||||
globalErrorStream() << GlobalFileSystem().findFile(filename) << filename << ":" << tokeniser.getLine() << ": " << tmp.c_str() << " parse failed, skipping rest of file\n";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -588,7 +687,7 @@ void EntityClassDoom3_loadFile(const char* filename)
|
|||
ArchiveTextFile* file = GlobalFileSystem().openTextFile(fullname.c_str());
|
||||
if(file != 0)
|
||||
{
|
||||
EntityClassDoom3_parse(file->getInputStream());
|
||||
EntityClassDoom3_parse(file->getInputStream(), fullname.c_str());
|
||||
file->release();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue