2 Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
5 This file is part of GtkRadiant.
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 #include "debugging/debugging.h"
28 #include "ifilesystem.h"
30 #include "string/string.h"
31 #include "eclasslib.h"
34 #include "stream/stringstream.h"
35 #include "moduleobservers.h"
39 #include "preferences.h"
40 #include "mainframe.h"
45 typedef std::map<const char*, EntityClass*, RawStringLessNoCase> EntityClasses;
46 EntityClasses g_entityClasses;
47 EntityClass *eclass_bad = 0;
48 char eclass_directory[1024];
49 typedef std::map<CopiedString, ListAttributeType> ListAttributeTypes;
50 ListAttributeTypes g_listTypes;
53 EClassModules& EntityClassManager_getEClassModules();
56 implementation of the EClass manager API
59 void CleanEntityList(EntityClasses& entityClasses)
61 for(EntityClasses::iterator i = entityClasses.begin(); i != entityClasses.end(); ++i)
63 (*i).second->free((*i).second);
65 entityClasses.clear();
70 CleanEntityList(g_entityClasses);
74 EntityClass* EClass_InsertSortedList(EntityClasses& entityClasses, EntityClass *entityClass)
76 std::pair<EntityClasses::iterator, bool> result = entityClasses.insert(EntityClasses::value_type(entityClass->name(), entityClass));
79 entityClass->free(entityClass);
81 return (*result.first).second;
84 EntityClass* Eclass_InsertAlphabetized (EntityClass *e)
86 return EClass_InsertSortedList(g_entityClasses, e);
89 void Eclass_forEach(EntityClassVisitor& visitor)
91 for(EntityClasses::iterator i = g_entityClasses.begin(); i != g_entityClasses.end(); ++i)
93 visitor.visit((*i).second);
98 class RadiantEclassCollector : public EntityClassCollector
101 void insert(EntityClass* eclass)
103 Eclass_InsertAlphabetized(eclass);
105 void insert(const char* name, const ListAttributeType& list)
107 g_listTypes.insert(ListAttributeTypes::value_type(name, list));
111 RadiantEclassCollector g_collector;
113 const ListAttributeType* EntityClass_findListType(const char* name)
115 ListAttributeTypes::iterator i = g_listTypes.find(name);
116 if(i != g_listTypes.end())
124 class EntityClassFilterMode
128 const char* mp_ignore_prefix;
129 const char* sp_ignore_prefix;
131 EntityClassFilterMode() :
132 filter_mp_sp(!string_empty(g_pGameDescription->getKeyValue("eclass_filter_gamemode"))),
133 mp_ignore_prefix(g_pGameDescription->getKeyValue("eclass_sp_prefix")),
134 sp_ignore_prefix(g_pGameDescription->getKeyValue("eclass_mp_prefix"))
136 if(string_empty(mp_ignore_prefix))
138 mp_ignore_prefix = "sp_";
140 if(string_empty(sp_ignore_prefix))
142 sp_ignore_prefix = "mp_";
147 class EntityClassesLoadFile
149 const EntityClassScanner& scanner;
150 const char* m_directory;
152 EntityClassesLoadFile(const EntityClassScanner& scanner, const char* directory) : scanner(scanner), m_directory(directory)
155 void operator()(const char* name) const
157 EntityClassFilterMode filterMode;
159 if(filterMode.filter_mp_sp)
161 if(string_empty(GlobalRadiant().getGameMode()) || string_equal(GlobalRadiant().getGameMode(), "sp"))
163 if(string_equal_n(name, filterMode.sp_ignore_prefix, strlen(filterMode.sp_ignore_prefix)))
165 globalOutputStream() << "Ignoring '" << name << "'\n";
171 if(string_equal_n(name, filterMode.mp_ignore_prefix, strlen(filterMode.mp_ignore_prefix)))
173 globalOutputStream() << "Ignoring '" << name << "'\n";
179 // for a given name, we grab the first .def in the vfs
180 // this allows to override baseq3/scripts/entities.def for instance
181 StringOutputStream relPath(256);
182 relPath << m_directory << name;
184 scanner.scanFile(g_collector, relPath.c_str());
190 bool operator()(const CopiedString& path, const CopiedString& other) const
192 return path_less(path.c_str(), other.c_str());
196 typedef std::map<CopiedString, const char*, PathLess> Paths;
201 const char* m_directory;
203 PathsInsert(Paths& paths, const char* directory) : m_paths(paths), m_directory(directory)
206 void operator()(const char* name) const
208 m_paths.insert(Paths::value_type(name, m_directory));
213 void EntityClassQuake3_constructDirectory(const char* directory, const char* extension, Paths& paths)
215 globalOutputStream() << "EntityClass: searching " << makeQuoted(directory) << " for *." << extension << '\n';
216 Directory_forEach(directory, matchFileExtension(extension, PathsInsert(paths, directory)));
220 void EntityClassQuake3_Construct()
222 StringOutputStream baseDirectory(256);
223 StringOutputStream gameDirectory(256);
224 const char* basegame = GlobalRadiant().getRequiredGameDescriptionKeyValue("basegame");
225 const char* gamename = GlobalRadiant().getGameName();
226 baseDirectory << GlobalRadiant().getGameToolsPath() << basegame << '/';
227 gameDirectory << GlobalRadiant().getGameToolsPath() << gamename << '/';
229 class LoadEntityDefinitionsVisitor : public EClassModules::Visitor
231 const char* baseDirectory;
232 const char* gameDirectory;
234 LoadEntityDefinitionsVisitor(const char* baseDirectory, const char* gameDirectory)
235 : baseDirectory(baseDirectory), gameDirectory(gameDirectory)
238 void visit(const char* name, const EntityClassScanner& table) const
241 EntityClassQuake3_constructDirectory(baseDirectory, table.getExtension(), paths);
242 if(!string_equal(baseDirectory, gameDirectory))
244 EntityClassQuake3_constructDirectory(gameDirectory, table.getExtension(), paths);
247 for(Paths::iterator i = paths.begin(); i != paths.end(); ++i)
249 EntityClassesLoadFile(table, (*i).second)((*i).first.c_str());
254 EntityClassManager_getEClassModules().foreachModule(LoadEntityDefinitionsVisitor(baseDirectory.c_str(), gameDirectory.c_str()));
257 EntityClass *Eclass_ForName(const char *name, bool has_brushes)
259 ASSERT_NOTNULL(name);
261 if(string_empty(name))
266 EntityClasses::iterator i = g_entityClasses.find(name);
267 if(i != g_entityClasses.end() && string_equal((*i).first, name))
272 EntityClass* e = EntityClass_Create_Default(name, has_brushes);
273 return Eclass_InsertAlphabetized(e);
276 class EntityClassQuake3 : public ModuleObserver
278 std::size_t m_unrealised;
279 ModuleObservers m_observers;
281 EntityClassQuake3() : m_unrealised(4)
286 if(--m_unrealised == 0)
288 //globalOutputStream() << "Entity Classes: realise\n";
289 EntityClassQuake3_Construct();
290 m_observers.realise();
295 if(++m_unrealised == 1)
297 m_observers.unrealise();
298 //globalOutputStream() << "Entity Classes: unrealise\n";
302 void attach(ModuleObserver& observer)
304 m_observers.attach(observer);
306 void detach(ModuleObserver& observer)
308 m_observers.detach(observer);
312 EntityClassQuake3 g_EntityClassQuake3;
314 void EntityClass_attach(ModuleObserver& observer)
316 g_EntityClassQuake3.attach(observer);
318 void EntityClass_detach(ModuleObserver& observer)
320 g_EntityClassQuake3.detach(observer);
323 void EntityClass_realise()
325 g_EntityClassQuake3.realise();
327 void EntityClass_unrealise()
329 g_EntityClassQuake3.unrealise();
332 void EntityClassQuake3_construct()
334 // start by creating the default unknown eclass
335 eclass_bad = EClass_Create("UNKNOWN_CLASS", Vector3(0.0f, 0.5f, 0.0f), "");
337 EntityClass_realise();
340 void EntityClassQuake3_destroy()
342 EntityClass_unrealise();
344 eclass_bad->free(eclass_bad);
347 #include "modulesystem/modulesmap.h"
349 class EntityClassQuake3Dependencies :
350 public GlobalRadiantModuleRef,
351 public GlobalFileSystemModuleRef,
352 public GlobalShaderCacheModuleRef
354 EClassModulesRef m_eclass_modules;
356 EntityClassQuake3Dependencies() :
357 m_eclass_modules(GlobalRadiant().getRequiredGameDescriptionKeyValue("entityclasstype"))
360 EClassModules& getEClassModules()
362 return m_eclass_modules.get();
366 class EclassManagerAPI
368 EntityClassManager m_eclassmanager;
370 typedef EntityClassManager Type;
371 STRING_CONSTANT(Name, "quake3");
375 EntityClassQuake3_construct();
377 m_eclassmanager.findOrInsert = &Eclass_ForName;
378 m_eclassmanager.findListType = &EntityClass_findListType;
379 m_eclassmanager.forEach = &Eclass_forEach;
380 m_eclassmanager.attach = &EntityClass_attach;
381 m_eclassmanager.detach = &EntityClass_detach;
382 m_eclassmanager.realise = &EntityClass_realise;
383 m_eclassmanager.unrealise = &EntityClass_unrealise;
385 GlobalRadiant().attachGameToolsPathObserver(g_EntityClassQuake3);
386 GlobalRadiant().attachGameModeObserver(g_EntityClassQuake3);
387 GlobalRadiant().attachGameNameObserver(g_EntityClassQuake3);
391 GlobalRadiant().detachGameNameObserver(g_EntityClassQuake3);
392 GlobalRadiant().detachGameModeObserver(g_EntityClassQuake3);
393 GlobalRadiant().detachGameToolsPathObserver(g_EntityClassQuake3);
395 EntityClassQuake3_destroy();
397 EntityClassManager* getTable()
399 return &m_eclassmanager;
403 #include "modulesystem/singletonmodule.h"
404 #include "modulesystem/moduleregistry.h"
406 typedef SingletonModule<EclassManagerAPI, EntityClassQuake3Dependencies> EclassManagerModule;
407 typedef Static<EclassManagerModule> StaticEclassManagerModule;
408 StaticRegisterModule staticRegisterEclassManager(StaticEclassManagerModule::instance());
410 EClassModules& EntityClassManager_getEClassModules()
412 return StaticEclassManagerModule::instance().getDependencies().getEClassModules();