scene::INodePtr Doom3EntityCreator::createEntity(const IEntityClassPtr& eclass) { scene::INodePtr node = getEntityForEClass(eclass); Entity* entity = Node_getEntity(node); assert(entity != NULL); entity->setKeyValue("classname", eclass->getName()); // If this is not a worldspawn or unrecognised entity, generate a unique // name for it const std::string& eclassName = eclass->getName(); if (!eclassName.empty() && eclassName != "worldspawn" && eclassName != "UNKNOWN_CLASS") { /* Clean up the name of the entity that is about the created * so that nothing bad can happen (for example, the colon character * seems to be causing problems in Doom 3 Scripting) */ std::string entityName = boost::algorithm::replace_all_copy(eclassName, ":", "_") + "_1"; entity->setKeyValue("name", entityName); } return node; }
std::string EClassTreeBuilder::getInheritancePathRecursive(const IEntityClassPtr& eclass) { std::string returnValue; try { EntityClassAttribute attribute = eclass->getAttribute(INHERIT_KEY); // Don't use empty or derived "inherit" keys if (!attribute.value.empty() && !attribute.inherited) { // Get the inherited eclass first and resolve the path IEntityClassPtr parent = GlobalEntityClassManager().findClass( attribute.value ); if (parent != NULL) { returnValue += getInheritancePathRecursive(parent); } else { globalErrorStream() << "EClassTreeBuilder: Cannot resolve inheritance path for " << eclass->getName() << std::endl; } returnValue += attribute.value + "/"; } } catch (std::runtime_error&) { // no inherit key } return returnValue; }
std::string DifficultySettings::getInheritanceKey(const std::string& className) { if (className.empty()) return ""; IEntityClassPtr eclass = GlobalEntityClassManager().findClass(className); // Get the inheritance chain of this class std::list<std::string> inheritanceChain; for (const IEntityClass* currentClass = eclass.get(); currentClass != NULL; currentClass = currentClass->getParent()) { inheritanceChain.push_front(currentClass->getName()); } // Build the inheritance key std::string inheritanceKey; for (std::list<std::string>::const_iterator c = inheritanceChain.begin(); c != inheritanceChain.end(); c++) { inheritanceKey += (inheritanceKey.empty()) ? "" : "_"; inheritanceKey += *c; } return inheritanceKey; }
void visit(const IEntityClassPtr& eclass) { if (boost::algorithm::starts_with(eclass->getName(), _prefix)) { // We have a match, store the eclassptr _map[eclass->getName()] = eclass; } }
// Required visit function void EntityClassTreePopulator::visit(const IEntityClassPtr& eclass) { std::string folderPath = eclass->getAttribute(_folderKey).getValue(); if (!folderPath.empty()) { folderPath = "/" + folderPath; } // Create the folder to put this EntityClass in, depending on the value // of the DISPLAY_FOLDER_KEY. addPath(eclass->getModName() + folderPath + "/" + eclass->getName()); }
std::string DifficultySettings::getParentClass(const std::string& className) { // Get the parent eclass IEntityClassPtr eclass = GlobalEntityClassManager().findClass(className); if (eclass == NULL) { return ""; // Invalid! } EntityClassAttribute inheritAttr = eclass->getAttribute("inherit"); return inheritAttr.getValue(); }
scene::INodePtr Doom3EntityCreator::getEntityForEClass(const IEntityClassPtr& eclass) { // Null entityclass check if (!eclass) { throw std::runtime_error( _("Doom3EntityCreator::getEntityForEClass(): " "cannot create entity for NULL entityclass.") ); } // Otherwise create the correct entity subclass based on the entity class // parameters. scene::INodePtr returnValue; if (eclass->isLight()) { LightNodePtr node(new LightNode(eclass)); node->construct(); returnValue = node; } else if (!eclass->isFixedSize()) { // Variable size entity Doom3GroupNodePtr node(new Doom3GroupNode(eclass)); node->construct(); returnValue = node; } else if (!eclass->getAttribute("model").value.empty()) { // Fixed size, has model path EclassModelNodePtr node(new EclassModelNode(eclass)); node->construct(); returnValue = node; } else if (eclass->getName() == "speaker") { SpeakerNodePtr node(new SpeakerNode(eclass)); node->construct(); returnValue = node; } else { // Fixed size, no model path GenericEntityNodePtr node(new GenericEntityNode(eclass)); node->construct(); returnValue = node; } return returnValue; }
void EClassTreeBuilder::visit(IEntityClassPtr eclass) { std::string fullPath; // Prefix mod name fullPath = eclass->getModName() + "/"; // Prefix inheritance path (recursively) fullPath += getInheritancePathRecursive(eclass); // The entityDef name itself fullPath += eclass->getName(); // Let the VFSTreePopulator do the insertion _treePopulator.addPath(fullPath); }
void Doom3EntityClass::buildInheritanceChain() { _inheritanceChain.clear(); // We start with the name of this class _inheritanceChain.push_back(_name); // Walk up the inheritance chain std::string parentClassName = getAttribute("inherit").value; while (!parentClassName.empty()) { _inheritanceChain.push_front(parentClassName); // Get the parent eclass IEntityClassPtr parentClass = GlobalEntityClassManager().findClass(parentClassName); if (parentClass == NULL) { break; } parentClassName = parentClass->getAttribute("inherit").value; } }
void EClassManager::resolveInheritance() { // Resolve inheritance on the model classes for (Models::iterator i = _models.begin(); i != _models.end(); ++i) { resolveModelInheritance(i->first, i->second); } // Resolve inheritance for the entities. At this stage the classes // will have the name of their parent, but not an actual pointer to // it for (EntityClasses::iterator i = _entityClasses.begin(); i != _entityClasses.end(); ++i) { // Tell the class to resolve its own inheritance using the given // map as a source for parent lookup i->second->resolveInheritance(_entityClasses); // If the entity has a model path ("model" key), lookup the actual // model and apply its mesh and skin to this entity. if (i->second->getModelPath().size() > 0) { Models::iterator j = _models.find(i->second->getModelPath()); if (j != _models.end()) { i->second->setModelPath(j->second->mesh); i->second->setSkin(j->second->skin); } } } // greebo: Override the eclass colours of two special entityclasses Vector3 worlspawnColour = ColourSchemes().getColour("default_brush"); Vector3 lightColour = ColourSchemes().getColour("light_volumes"); IEntityClassPtr light = findOrInsert("light", true); light->setColour(lightColour); IEntityClassPtr worldspawn = findOrInsert("worldspawn", true); worldspawn->setColour(worlspawnColour); }
void DifficultySettingsManager::loadDifficultyNames() { // Locate the worldspawn entity Entity* worldspawn = Scene_FindEntityByClass("worldspawn"); // Try to locate the difficulty menu entity, where the default names are defined IEntityClassPtr eclass = GlobalEntityClassManager().findClass( game::current::getValue<std::string>(GKEY_DIFFICULTY_ENTITYDEF_MENU) ); // greebo: Setup the default difficulty levels using the found entityDef int numLevels = game::current::getValue<int>(GKEY_DIFFICULTY_LEVELS); for (int i = 0; i < numLevels; i++) { std::string nameKey = "diff" + string::to_string(i) + "default"; // First, try to find a map-specific name if (worldspawn != NULL) { std::string name = worldspawn->getKeyValue(nameKey); if (!name.empty()) { // Found a setting on worldspawn, take it _difficultyNames.push_back(name); continue; // done for this level } } // If the above failed, try to load the default setting if (eclass != NULL) { EntityClassAttribute attr = eclass->getAttribute(nameKey); if (!attr.getValue().empty()) { _difficultyNames.push_back(attr.getValue()); continue; } } // Fall back to a non-empty default _difficultyNames.push_back(string::to_string(i)); } }
void visit(const IEntityClassPtr& eclass) { if (boost::algorithm::starts_with(eclass->getName(), _prefix)) { // We have a match, create a new structure ConversationCommandInfoPtr commandInfo(new ConversationCommandInfo); // Fill the values from the found entityDef commandInfo->parseFromEntityClass(eclass); // Store the structure to the target map _map[commandInfo->name] = commandInfo; } }
void DifficultySettings::parseFromEntityDef(const IEntityClassPtr& def) { // Construct the prefix for the desired difficulty level std::string diffPrefix = "diff_" + string::to_string(_level) + "_"; std::string prefix = diffPrefix + "change_"; eclass::AttributeList spawnargs = eclass::getSpawnargsWithPrefix(*def, prefix); for (eclass::AttributeList::iterator i = spawnargs.begin(); i != spawnargs.end(); ++i) { EntityClassAttribute& attr = *i; if (attr.getValue().empty()) { continue; // empty spawnarg attribute => invalid } // Get the index from the string's tail std::string indexStr = attr.getName().substr(prefix.length()); const EntityClassAttribute& classAttr = def->getAttribute(diffPrefix + "class_" + indexStr); const EntityClassAttribute& argAttr = def->getAttribute(diffPrefix + "arg_" + indexStr); SettingPtr setting = createSetting(classAttr.getValue()); setting->spawnArg = attr.getValue(); setting->argument = argAttr.getValue(); // This has been parsed from the default entityDef setting->isDefault = true; // Interpret/parse the argument string setting->parseAppType(); } clearTreeModel(); updateTreeModel(); }
void EClassTree::updatePropertyView(const std::string& eclassName) { // Clear the existing list gtk_list_store_clear(_propertyStore); IEntityClassPtr eclass = GlobalEntityClassManager().findClass(eclassName); if (eclass == NULL) { return; } class ListStorePopulator : public EntityClassAttributeVisitor { GtkListStore* _listStore; public: ListStorePopulator(GtkListStore* targetStore) : _listStore(targetStore) {} virtual void visit(const EntityClassAttribute& attr) { // Append the details to the treestore GtkTreeIter iter; gtk_list_store_append(_listStore, &iter); gtk_list_store_set( _listStore, &iter, PROPERTY_NAME_COLUMN, attr.name.c_str(), PROPERTY_VALUE_COLUMN, attr.value.c_str(), PROPERTY_TEXT_COLOUR_COLUMN, attr.inherited ? "#666666" : "black", PROPERTY_INHERITED_FLAG_COLUMN, attr.inherited ? "1" : "0", -1 ); } }; ListStorePopulator populator(_propertyStore); eclass->forEachClassAttribute(populator, true); }
// Required visit function void EntityClassTreePopulator::visit(IEntityClassPtr e) { // Recursively create the folder to put this EntityClass in, // depending on the value of the DISPLAY_FOLDER_KEY. This may return // NULL if the key is unset, in which case we add the entity at // the top level. GtkTreeIter* parIter = addDisplayFolder(e); // Add the new class under the parent folder GtkTreeIter iter; gtk_tree_store_append(_store, &iter, parIter); gtk_tree_store_set(_store, &iter, NAME_COLUMN, e->getName().c_str(), ICON_COLUMN, GlobalUIManager().getLocalPixbuf(ENTITY_ICON), DIR_FLAG_COLUMN, FALSE, -1); }
/** * Create an instance of the given entity at the given position, and return * the Node containing the new entity. * * @returns: the scene::INodePtr referring to the new entity. */ scene::INodePtr createEntityFromSelection(const std::string& name, const Vector3& origin) { // Obtain the structure containing the selection counts const SelectionInfo& info = GlobalSelectionSystem().getSelectionInfo(); IEntityClassPtr entityClass = GlobalEntityClassManager().findOrInsert(name, true); // TODO: to be replaced by inheritance-based class detection bool isModel = (info.totalCount == 0 && name == "func_static"); // Some entities are based on the size of the currently-selected primitive(s) bool primitivesSelected = info.brushCount > 0 || info.patchCount > 0; if (!(entityClass->isFixedSize() || isModel) && !primitivesSelected) { throw EntityCreationException( (boost::format(_("Unable to create entity %s, no brushes selected.")) % name).str() ); } // Get the selection workzone bounds AABB workzone = GlobalSelectionSystem().getWorkZone().bounds; // Create the new node for the entity IEntityNodePtr node(GlobalEntityCreator().createEntity(entityClass)); GlobalSceneGraph().root()->addChildNode(node); // The layer list we're moving the newly created node/subgraph into scene::LayerList targetLayers; if (entityClass->isFixedSize() || (isModel && !primitivesSelected)) { selection::algorithm::deleteSelection(); ITransformablePtr transform = Node_getTransformable(node); if (transform != 0) { transform->setType(TRANSFORM_PRIMITIVE); transform->setTranslation(origin); transform->freezeTransform(); } GlobalSelectionSystem().setSelectedAll(false); // Move the item to the active layer targetLayers.insert(GlobalLayerSystem().getActiveLayer()); Node_setSelected(node, true); } else // brush-based entity { // Add selected brushes as children of non-fixed entity node->getEntity().setKeyValue("model", node->getEntity().getKeyValue("name")); // Take the selection center as new origin Vector3 newOrigin = selection::algorithm::getCurrentSelectionCenter(); node->getEntity().setKeyValue("origin", string::to_string(newOrigin)); // If there is an "editor_material" class attribute, apply this shader // to all of the selected primitives before parenting them std::string material = node->getEntity().getEntityClass()->getAttribute("editor_material").getValue(); if (!material.empty()) { selection::algorithm::applyShaderToSelection(material); } // If we had primitives to reparent, the new entity should inherit the layer info from them if (primitivesSelected) { scene::INodePtr primitive = GlobalSelectionSystem().ultimateSelected(); targetLayers = primitive->getLayers(); } else { // Otherwise move the item to the active layer targetLayers.insert(GlobalLayerSystem().getActiveLayer()); } // Parent the selected primitives to the new node selection::algorithm::ParentPrimitivesToEntityWalker walker(node); GlobalSelectionSystem().foreachSelected(walker); walker.reparent(); // De-select the children and select the newly created parent entity GlobalSelectionSystem().setSelectedAll(false); Node_setSelected(node, true); } // Assign the layers - including all child nodes (#2864) scene::AssignNodeToLayersWalker layerWalker(targetLayers); Node_traverseSubgraph(node, layerWalker); // Set the light radius and origin if (entityClass->isLight() && primitivesSelected) { AABB bounds(Doom3Light_getBounds(workzone)); node->getEntity().setKeyValue("origin", string::to_string(bounds.getOrigin())); node->getEntity().setKeyValue("light_radius", string::to_string(bounds.getExtents())); } // Flag the map as unsaved after creating the entity GlobalMap().setModified(true); // Check for auto-setting key values. TODO: use forEachClassAttribute // directly here. eclass::AttributeList list = eclass::getSpawnargsWithPrefix( *entityClass, "editor_setKeyValue" ); if (!list.empty()) { for (eclass::AttributeList::const_iterator i = list.begin(); i != list.end(); ++i) { // Cut off the "editor_setKeyValueN " string from the key to get the spawnarg name std::string key = i->getName().substr(i->getName().find_first_of(' ') + 1); node->getEntity().setKeyValue(key, i->getValue()); } } // Return the new node return node; }