1 /* $Id$ */
2 /***************************************************************************
3  *                      (C) Copyright 2003 - Marauroa                      *
4  ***************************************************************************
5  ***************************************************************************
6  *                                                                         *
7  *   This program 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.                                   *
11  *                                                                         *
12  ***************************************************************************/
13 package games.stendhal.server.core.rule.defaultruleset;
14 
15 import java.net.URI;
16 import java.util.Collection;
17 import java.util.HashMap;
18 import java.util.List;
19 import java.util.Map;
20 
21 import org.apache.log4j.Logger;
22 
23 import games.stendhal.common.parser.ExpressionType;
24 import games.stendhal.common.parser.WordList;
25 import games.stendhal.server.core.config.CreatureGroupsXMLLoader;
26 import games.stendhal.server.core.config.ItemGroupsXMLLoader;
27 import games.stendhal.server.core.config.ShopsXMLLoader;
28 import games.stendhal.server.core.config.SpellGroupsXMLLoader;
29 import games.stendhal.server.core.rule.EntityManager;
30 import games.stendhal.server.entity.Entity;
31 import games.stendhal.server.entity.creature.Creature;
32 import games.stendhal.server.entity.item.Item;
33 import games.stendhal.server.entity.spell.Spell;
34 
35 /**
36  * entity manager for the default ruleset.
37  *
38  * @author Matthias Totz
39  */
40 public class DefaultEntityManager implements EntityManager {
41 
42 	/** the logger instance. */
43 	private static final Logger LOGGER = Logger.getLogger(DefaultEntityManager.class);
44 
45 	/** maps the tile ids to the classes. */
46 	private final Map<String, String> idToClass;
47 
48 	/** maps the item names to the actual item enums. */
49 	private final Map<String, DefaultItem> classToItem;
50 
51 	/** lists all creatures that are being used at least once. */
52 	private final Map<String, Creature> createdCreature;
53 
54 	/** lists all items that are being used at least once . */
55 	private final Map<String, Item> createdItem;
56 
57 	/** lists all spell that are being used at least once . */
58 	private final Map<String, Spell> createdSpell;
59 
60 	/**
61 	 * lists all loaded default spells that are usable
62 	 */
63 	private final Map<String, DefaultSpell> nameToSpell;
64 
65 	private LowerCaseMap<DefaultCreature> classToCreature;
66 
67 	/** no public constructor. */
DefaultEntityManager()68 	public DefaultEntityManager() {
69 		idToClass = new HashMap<String, String>();
70 		createdCreature = new HashMap<String, Creature>();
71 		createdItem = new HashMap<String, Item>();
72 		createdSpell = new HashMap<String, Spell>();
73 		classToItem = new HashMap<String, DefaultItem>();
74 		nameToSpell = new HashMap<String, DefaultSpell>();
75 		buildItemTables();
76 		buildCreatureTables();
77 		buildSpellTables();
78 
79 		ShopsXMLLoader.get().init();
80 	}
81 
82 	/**
83 	 * builds the spell tables
84 	 */
buildSpellTables()85 	private void buildSpellTables() {
86 		try {
87 			final SpellGroupsXMLLoader loader = new SpellGroupsXMLLoader(new URI("/data/conf/spells.xml"));
88 			List<DefaultSpell> loadedDefaultSpells = loader.load();
89 			for (DefaultSpell defaultSpell : loadedDefaultSpells) {
90 				addSpell(defaultSpell);
91 			}
92 		} catch (Exception e) {
93 			LOGGER.error("spells.xml could not be loaded", e);
94 		}
95 	}
96 
97 	/**
98 	 * Build the items tables
99 	 */
buildItemTables()100 	private void buildItemTables() {
101 		try {
102 			final ItemGroupsXMLLoader loader = new ItemGroupsXMLLoader(new URI("/data/conf/items.xml"));
103 			final List<DefaultItem> items = loader.load();
104 
105 			for (final DefaultItem item : items) {
106 				final String clazz = item.getItemName();
107 
108 				if (classToItem.containsKey(clazz)) {
109 					LOGGER.warn("Repeated item name: " + clazz);
110 				}
111 
112 				classToItem.put(clazz, item);
113 
114 				String typeString = ExpressionType.OBJECT;
115 
116 				if (item.getItemClass().equals("food")) {
117 					typeString += ExpressionType.SUFFIX_FOOD;
118 				} else if (item.getItemClass().equals("drink")) {
119 					typeString += ExpressionType.SUFFIX_FOOD;
120 					typeString += ExpressionType.SUFFIX_FLUID;
121 				}
122 
123 				WordList.getInstance().registerName(item.getItemName(), typeString);
124 			}
125 		} catch (final Exception e) {
126 			LOGGER.error("items.xml could not be loaded", e);
127 		}
128 	}
129 
130 	/**
131 	 * Build the creatures tables
132 	 */
buildCreatureTables()133 	private void buildCreatureTables() {
134 		classToCreature = new LowerCaseMap<DefaultCreature>();
135 
136 		final CreatureGroupsXMLLoader loader = new CreatureGroupsXMLLoader("/data/conf/creatures.xml");
137 		final List<DefaultCreature> creatures = loader.load();
138 
139 		for (final DefaultCreature creature : creatures) {
140 			final String id = creature.getTileId();
141 			final String clazz = creature.getCreatureName();
142 
143 			if (classToCreature.containsKey(clazz)) {
144 				LOGGER.warn("Repeated creature name: " + clazz);
145 			}
146 
147 			if (!creature.verifyItems(this)) {
148 				LOGGER.warn("Items dropped by creature name: " + clazz + " doesn't exists");
149 			}
150 
151 			classToCreature.put(clazz, creature);
152 			idToClass.put(id, clazz);
153 
154 			WordList.getInstance().registerName(creature.getCreatureName(), ExpressionType.SUBJECT);
155 		}
156 	}
157 
158 	@Override
addItem(final DefaultItem item)159 	public boolean addItem(final DefaultItem item) {
160 		final String clazz = item.getItemName();
161 
162 		if (classToItem.containsKey(clazz)) {
163 			LOGGER.warn("Repeated item name: " + clazz);
164 			return false;
165 		}
166 
167 		classToItem.put(clazz, item);
168 
169 		return true;
170 	}
171 
172 	@Override
addCreature(final DefaultCreature creature)173 	public boolean addCreature(final DefaultCreature creature) {
174 		final String id = creature.getTileId();
175 		final String clazz = creature.getCreatureName();
176 
177 		if (classToCreature.containsKey(clazz)) {
178 			LOGGER.warn("Repeated creature name: " + clazz);
179 		}
180 
181 		if (!creature.verifyItems(this)) {
182 			LOGGER.warn("Items dropped by creature name: " + clazz + " doesn't exists");
183 		}
184 		classToCreature.put(clazz, creature);
185 		idToClass.put(id, clazz);
186 
187 		return true;
188 	}
189 
190 	/**
191 	 * For manually populating the creature list.
192 	 *
193 	 * Useful for tests.
194 	 */
195 	@Override
populateCreatureList()196 	public void populateCreatureList() {
197 		for (final DefaultCreature cr: getDefaultCreatures()) {
198 			createdCreature.put(cr.getCreatureName(), cr.getCreature());
199 		}
200 	}
201 
202 	@Override
addSpell(DefaultSpell spell)203 	public boolean addSpell(DefaultSpell spell) {
204 		if(nameToSpell.containsKey(spell.getName())) {
205 			LOGGER.warn("Repeated spell name: "+ spell.getName());
206 		}
207 		nameToSpell.put(spell.getName(), spell);
208 		return true;
209 	}
210 
211 	/**
212 	 * @return a list of all Creatures that are instantiated.
213 	 */
214 	@Override
getCreatures()215 	public Collection<Creature> getCreatures() {
216 		return createdCreature.values();
217 	}
218 
219 	/**
220 	 * @return a list of all Items that are instantiated.
221 	 */
222 	@Override
getItems()223 	public Collection<Item> getItems() {
224 		return createdItem.values();
225 	}
226 
227 	/**
228 	 * returns the entity or <code>null</code> if the id is unknown.
229 	 *
230 	 * @param clazz
231 	 *            RPClass
232 	 * @return the new created entity or null if class not found
233 	 *
234 	 * @throws NullPointerException
235 	 *             if clazz is <code>null</code>
236 	 */
237 	@Override
getEntity(final String clazz)238 	public Entity getEntity(final String clazz) {
239 		if (clazz == null) {
240 			throw new IllegalArgumentException("entity class is null");
241 		}
242 
243 		Entity entity;
244 		// Lookup the id in the creature table
245 		entity = getCreature(clazz);
246 		if (entity != null) {
247 			return entity;
248 		}
249 
250 		// Lookup the id in the item table
251 		entity = getItem(clazz);
252 		if (entity != null) {
253 			return entity;
254 		}
255 
256 		return null;
257 	}
258 
259 	/**
260 	 * @param tileset
261 	 * @param id
262 	 * @return the creature or <code>null</code> if the id is unknown.
263 	 */
264 	@Override
getCreature(final String tileset, final int id)265 	public Creature getCreature(final String tileset, final int id) {
266 		final String clazz = idToClass.get(tileset + ":" + id);
267 		if (clazz == null) {
268 			return null;
269 		}
270 
271 		return getCreature(clazz);
272 	}
273 
274 	/**
275 	 * @param clazz
276 	 * @return the creature or <code>null</code> if the clazz is unknown.
277 	 *
278 	 * @throws NullPointerException
279 	 *             if clazz is <code>null</code>
280 	 */
281 	@Override
getCreature(final String clazz)282 	public Creature getCreature(final String clazz) {
283 		if (clazz == null) {
284 			throw new IllegalArgumentException("entity class is null");
285 		}
286 
287 		// Lookup the clazz in the creature table
288 		final DefaultCreature creature = classToCreature.get(clazz);
289 		if (creature != null) {
290 			if (createdCreature.get(clazz) == null) {
291 				createdCreature.put(clazz, creature.getCreature());
292 			}
293 			return creature.getCreature();
294 		}
295 
296 		return null;
297 	}
298 
299 	/**
300 	 * @param clazz
301 	 * @return the DefaultCreature or <code>null</code> if the clazz is
302 	 *         unknown.
303 	 *
304 	 * @throws NullPointerException
305 	 *             if clazz is <code>null</code>
306 	 */
307 	@Override
getDefaultCreature(final String clazz)308 	public DefaultCreature getDefaultCreature(final String clazz) {
309 		if (clazz == null) {
310 			throw new IllegalArgumentException("entity class is null");
311 		}
312 
313 		// Lookup the clazz in the creature table
314 		return classToCreature.get(clazz);
315 	}
316 
317 	/** @param tileset
318 	 * @param id
319 	 * @return true if the Entity is a creature. */
320 	@Override
isCreature(final String tileset, final int id)321 	public boolean isCreature(final String tileset, final int id) {
322 		final String clazz = idToClass.get(tileset + ":" + id);
323 		if (clazz == null) {
324 			return false;
325 		}
326 
327 		return isCreature(clazz);
328 	}
329 
330 	/** @param clazz
331 	 * @return true if the Entity is a creature . */
332 	@Override
isCreature(final String clazz)333 	public boolean isCreature(final String clazz) {
334 		if (clazz == null) {
335 			throw new IllegalArgumentException("entity class is null");
336 		}
337 
338 		return classToCreature.containsKey(clazz);
339 	}
340 
341 	/** @param clazz
342 	 * @return true if the Entity is a creature. */
343 	@Override
isItem(final String clazz)344 	public boolean isItem(final String clazz) {
345 		if (clazz == null) {
346 			throw new IllegalArgumentException("entity class is null");
347 		}
348 
349 		return classToItem.containsKey(clazz);
350 	}
351 
352 	/**
353 	 * @param clazz
354 	 * @return the item or <code>null</code> if the clazz is unknown.
355 	 *
356 	 * @throws NullPointerException
357 	 *             if clazz is <code>null</code>
358 	 */
359 	@Override
getItem(final String clazz)360 	public Item getItem(final String clazz) {
361 		if (clazz == null) {
362 			throw new IllegalArgumentException("entity class is null");
363 		}
364 
365 		// Lookup the clazz in the item table
366 		final DefaultItem item = classToItem.get(clazz);
367 		if (item != null) {
368 			if (createdItem.get(clazz) == null) {
369 				createdItem.put(clazz, item.getItem());
370 			}
371 			return item.getItem();
372 		}
373 
374 		return null;
375 	}
376 
377 	@Override
getSpell(String spell)378 	public Spell getSpell(String spell) {
379 		if(spell == null) {
380 			throw new IllegalArgumentException("spell name is null");
381 		}
382 		DefaultSpell defaultSpell = nameToSpell.get(spell);
383 		if (defaultSpell != null) {
384 			Spell spellEntity = defaultSpell.getSpell();
385 			if(!createdSpell.containsKey(spell)) {
386 				createdSpell.put(spell, spellEntity);
387 			}
388 			return spellEntity;
389 		}
390 		return null;
391 	}
392 
393 	@Override
isSpell(String spellName)394 	public boolean isSpell(String spellName) {
395 		return nameToSpell.containsKey(spellName);
396 	}
397 
398 	@Override
getSpells()399 	public Collection<Spell> getSpells() {
400 		return createdSpell.values();
401 	}
402 
403 	@Override
getDefaultCreatures()404 	public Collection<DefaultCreature> getDefaultCreatures() {
405 		return classToCreature.values();
406 	}
407 
408 	@Override
getDefaultItems()409 	public Collection<DefaultItem> getDefaultItems() {
410 		return classToItem.values();
411 	}
412 
getConfiguredItems()413 	public Collection<String> getConfiguredItems() {
414 		return classToItem.keySet();
415 	}
416 
417 	@Override
getConfiguredSpells()418 	public Collection<String> getConfiguredSpells() {
419 		return nameToSpell.keySet();
420 	}
421 }
422