Пример #1
0
/**
 * @brief searches for the parsed key def
 * @param abstract send abstract to find an abstract key with this name
 * @return NULL if the entity def or key def is not found. call ED_GetLastError to get a relevant message.
 */
const entityKeyDef_t *ED_GetKeyDef (const char *classname, const char *keyname, const int abstract)
{
	const entityDef_t *ed = ED_GetEntityDef(classname);
	return ED_GetKeyDefEntity(ed, keyname, abstract);
}
Пример #2
0
/**
 * @brief Perform an entity check
 */
void CheckEntities (void)
{
	Check_InitEntityDefs();

	for (int i = 0; i < num_entities; i++) {
		entity_t* e = &entities[i];
		const char* name = ValueForKey(e, "classname");
		const entityDef_t* ed = ED_GetEntityDef(name);
		const epair_t* kvp;
		const entityKeyDef_t* kd;

		if (!ed) { /* check that a definition exists */
			Check_Printf(VERB_CHECK, false, i, -1, "Not defined in entities.ufo: %s\n", name);
			continue;
		}

		/* check alignment of info_.+_start */
		if (Check_IsInfoStart(name) && !Check_InfoStartAligned(ed, e))
			Check_Printf(VERB_CHECK, false, i, -1, "Misaligned %s\n", name);

		if (Q_strstart(name, "func_")) /* func_* entities should have brushes */
			Check_EntityWithBrushes(e, name, i);

		/* check all keys in the entity - make sure they are OK */
		for (kvp = e->epairs; kvp; kvp = kvp->next) {
			kd = ED_GetKeyDefEntity(ed, kvp->key, 0); /* zero means ignore abstract (radiant only) keys */

			if (!kd) { /* make sure it has a definition */
				Check_Printf(VERB_CHECK, false, i, -1, "Not defined in entities.ufo: %s in %s\n", kvp->key, name);
				continue;
			}

			if (ED_CheckKey(kd, kvp->value) == ED_ERROR) { /* check values against type and range definitions in entities.ufo */
				Check_Printf(VERB_CHECK, false, i, -1, "%s\n", ED_GetLastError());
				continue;
			}

			if (Q_streq("target", kvp->key) || Q_streq("targetname", kvp->key)) {
				if (!Check_TargetExists(kvp)) {
					Check_Printf(VERB_CHECK, false, i, -1,
						"%s with %s of %s: no corresponding entity with %s with matching value\n",
						ed->classname, kvp->key, kvp->value, Q_streq("target", kvp->key) ? "targetname" : "target");
				}
			}
		}

		/* check keys in the entity definition - make sure mandatory ones are present */
		for (kd = ed->keyDefs; kd->name; kd++) {
			if (kd->flags & ED_MANDATORY) {
				const char* keyNameInEnt = ValueForKey(e, kd->name);
				if (keyNameInEnt[0] == '\0') {
					const char* defaultVal = kd->defaultVal;
					const bool hasDefault = defaultVal ? true : false;
					Check_Printf(VERB_CHECK, hasDefault, i, -1, "Mandatory key missing from entity: %s in %s", kd->name, name);
					if (defaultVal) {
						Check_Printf(VERB_CHECK, hasDefault, i, -1, ", supplying default: %s", defaultVal);
						SetKeyValue(e, kd->name, defaultVal);
					}
					Check_Printf(VERB_CHECK, hasDefault, i, -1, "\n");
				}
			}
		}
	}
}
Пример #3
0
/**
 * @return ED_ERROR or ED_OK
 */
static int ED_ParseEntities (const char **data_p)
{
	int braceLevel = 0;
	int tokensOnLevel0 = 0;
	int mode = ED_ABSTRACT;
	entityKeyDef_t keyDefBuf[ED_MAX_KEYS_PER_ENT];
	char lastTokenBuf[ED_MAX_TOKEN_LEN];
	int keyIndex = 0;
	int toggle = 0; /* many lines should have a pair of tokens on, this toggles 0, 1 to indicate progress */

	while (data_p) {
		const char *parsedToken = Com_Parse(data_p);
		toggle ^= 1;

		if (parsedToken[0] == '\0' && braceLevel == 0)
			break;

		if (parsedToken[0] == '{') {
			braceLevel++;
			ED_TEST_RETURN_ERROR(braceLevel > 2, "Too many open braces, nested %i deep", braceLevel);
			ED_TEST_RETURN_ERROR(!toggle, "ED_ParseEntities: Incorrect number of tokens before '{'");
			toggle ^= 1; /* reset, as toggle is only for counting proper text tokens, not braces */
			tokensOnLevel0 = 0;
			continue;
		}

		if (parsedToken[0] == '}') {
			braceLevel--;
			ED_TEST_RETURN_ERROR(braceLevel < 0, "Too many close braces. after %i entities", numEntityDefs);
			toggle ^= 1; /* reset, as toggle is only for counting proper text tokens, not braces */
			if (braceLevel == 0) { /* finished parsing entity def and prepare for the next one */
				ED_PASS_ERROR(ED_AllocEntityDef(keyDefBuf, keyIndex, numEntityDefs));
				numEntityDefs++;
				ED_TEST_RETURN_ERROR(numEntityDefs >= ED_MAX_DEFS, "ED_ParseEntities: too many entity defs for buffer");
			}
			if (braceLevel == 1) /* ending a default, mandatory, etc block, go back to default parse mode */
				mode = ED_ABSTRACT;

			continue;
		}

		if (braceLevel == 0) {
			if (tokensOnLevel0 == 0 && !Q_streq(parsedToken, "entity"))
				ED_RETURN_ERROR( "Next entity expected, found \"%s\"", parsedToken);

			if (tokensOnLevel0 == 1) {/* classname of entity, start parsing new entity */
				const entityDef_t *prevED = ED_GetEntityDef(parsedToken);
				ED_TEST_RETURN_ERROR(prevED, "ED_ParseEntities: duplicate entity definition \"%s\"", parsedToken);
				OBJZERO(keyDefBuf); /* ensure pointers are not carried over from previous entity */
				keyIndex = 0;
				ED_PASS_ERROR(ED_PairParsed(keyDefBuf, &keyIndex, "classname", parsedToken, ED_MANDATORY));
				mode = ED_ABSTRACT;
			}

			if (tokensOnLevel0 > 1)
				ED_RETURN_ERROR( "Start of entity block expected found \"%s\"", parsedToken);

			tokensOnLevel0++;
		} else { /* braceLevel > 0 */
			const int newMode = ED_Block2Constant(parsedToken);
			if (ED_ERROR == newMode) { /* must be a key name or value */
				if (toggle) { /* store key name til after next token is parsed */
					if ('\0' == parsedToken[0])
						ED_RETURN_ERROR("key name null string, \"\", or missing closing brace");
					strncpy(lastTokenBuf, parsedToken, sizeof(lastTokenBuf));
					lastTokenBuf[sizeof(lastTokenBuf) - 1] = '\0';
				} else { /* store key-value pair in buffer until whole entity is parsed */
					ED_PASS_ERROR(ED_PairParsed(keyDefBuf, &keyIndex, lastTokenBuf, parsedToken, mode));
				}
			} else {
				mode = newMode;
				toggle ^= 1; /* start of a mode changing block is the only time that only one non-brace token is on a line */
			}
		}
	}

	return ED_OK;
}