package net.citizensnpcs.npc; import java.lang.reflect.Constructor; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import net.citizensnpcs.api.npc.NPC; import net.citizensnpcs.api.trait.Trait; import net.citizensnpcs.api.trait.TraitFactory; import net.citizensnpcs.api.trait.TraitManager; import net.citizensnpcs.api.trait.trait.Equipment; import net.citizensnpcs.api.trait.trait.Inventory; import net.citizensnpcs.api.trait.trait.MobType; import net.citizensnpcs.api.trait.trait.Owner; import net.citizensnpcs.api.trait.trait.Spawned; import net.citizensnpcs.trait.Age; import net.citizensnpcs.trait.Behaviour; import net.citizensnpcs.trait.Controllable; import net.citizensnpcs.trait.CurrentLocation; import net.citizensnpcs.trait.LookClose; import net.citizensnpcs.trait.Powered; import net.citizensnpcs.trait.Saddle; import net.citizensnpcs.trait.Sheared; import net.citizensnpcs.trait.VillagerProfession; import net.citizensnpcs.trait.WoolColor; import net.citizensnpcs.trait.text.Text; import net.citizensnpcs.trait.waypoint.Waypoints; import org.bukkit.plugin.Plugin; public class CitizensTraitManager implements TraitManager { private final Map, Constructor> CACHED_CTORS = new HashMap, Constructor>(); private final Map>> registered = new HashMap>>(); // TODO: handle Plugin-setting/names better and avoid cruft. also find a // way to avoid naming conflicts public CitizensTraitManager(Plugin plugin) { registerTrait(new TraitFactory(Age.class).withName("age").withPlugin(plugin)); registerTrait(new TraitFactory(CurrentLocation.class).withName("location").withPlugin(plugin)); registerTrait(new TraitFactory(Equipment.class).withName("equipment").withPlugin(plugin)); registerTrait(new TraitFactory(Inventory.class).withName("inventory").withPlugin(plugin)); registerTrait(new TraitFactory(LookClose.class).withName("lookclose").withPlugin(plugin)); registerTrait(new TraitFactory(MobType.class).withName("type").withPlugin(plugin)); registerTrait(new TraitFactory(Owner.class).withName("owner").withPlugin(plugin)); registerTrait(new TraitFactory(Powered.class).withName("powered").withPlugin(plugin)); registerTrait(new TraitFactory(Saddle.class).withName("saddle").withPlugin(plugin)); registerTrait(new TraitFactory(Sheared.class).withName("sheared").withPlugin(plugin)); registerTrait(new TraitFactory(Spawned.class).withName("spawned").withPlugin(plugin)); registerTrait(new TraitFactory(Text.class).withName("text").withPlugin(plugin)); registerTrait(new TraitFactory(VillagerProfession.class).withName("profession").withPlugin(plugin)); registerTrait(new TraitFactory(Waypoints.class).withName("waypoints").withPlugin(plugin)); registerTrait(new TraitFactory(WoolColor.class).withName("woolcolor").withPlugin(plugin)); registerTrait(new TraitFactory(Controllable.class).withName("controllable").withPlugin(plugin)); registerTrait(new TraitFactory(Behaviour.class).withName("behaviour").withPlugin(plugin)); } @SuppressWarnings("unchecked") private T create(Class trait, NPC npc) { Constructor constructor; if (!CACHED_CTORS.containsKey(trait)) { try { // TODO: replace this fixed constructor with a context class // which can have extra environment variables. constructor = trait.getConstructor(NPC.class); if (constructor == null) constructor = trait.getConstructor(CitizensNPC.class); constructor.setAccessible(true); } catch (Exception ex) { constructor = null; } CACHED_CTORS.put(trait, constructor); } else constructor = CACHED_CTORS.get(trait); try { if (constructor == null || npc == null) return trait.newInstance(); return (T) constructor.newInstance(npc); } catch (Exception ex) { ex.printStackTrace(); return null; } } @Override public T getTrait(Class clazz) { return getTrait(clazz, null); } @SuppressWarnings("unchecked") public T getTrait(Class clazz, NPC npc) { for (Entry>> entry : registered.entrySet()) { for (Entry> subEntry : entry.getValue().entrySet()) { if (!subEntry.getValue().equals(clazz)) continue; Trait trait = create(subEntry.getValue(), npc); if (trait == null) return null; trait.setName(subEntry.getKey()); trait.setPlugin(entry.getKey()); return (T) trait; } } return null; } @SuppressWarnings("unchecked") @Override public T getTrait(String name) { for (Map> entry : registered.values()) { if (!entry.containsKey(name)) continue; return (T) create(entry.get(name), null); } return null; } @SuppressWarnings("unchecked") public T getTrait(String name, NPC npc) { for (Map> entry : registered.values()) { Class clazz = entry.get(name); if (clazz == null) continue; return (T) getTrait(clazz, npc); } return null; } @Override public void registerTrait(TraitFactory factory) { Map> map = registered.get(factory.getTraitPlugin()); if (map == null) map = new HashMap>(); map.put(factory.getTraitName(), factory.getTraitClass()); registered.put(factory.getTraitPlugin(), map); } }