diff --git a/src/com/massivecraft/mcore4/MCore.java b/src/com/massivecraft/mcore4/MCore.java index 2f5bdfbf..fb150ae6 100644 --- a/src/com/massivecraft/mcore4/MCore.java +++ b/src/com/massivecraft/mcore4/MCore.java @@ -47,7 +47,7 @@ public class MCore extends MPlugin // CONSTRUCT // -------------------------------------------- // - protected static MCore p; + public static MCore p; public MCore() { p = this; diff --git a/src/com/massivecraft/mcore4/cmd/arg/AHPlayerWrapperNew.java b/src/com/massivecraft/mcore4/cmd/arg/AHPlayerWrapperColl.java similarity index 89% rename from src/com/massivecraft/mcore4/cmd/arg/AHPlayerWrapperNew.java rename to src/com/massivecraft/mcore4/cmd/arg/AHPlayerWrapperColl.java index 994e9749..5c79a108 100644 --- a/src/com/massivecraft/mcore4/cmd/arg/AHPlayerWrapperNew.java +++ b/src/com/massivecraft/mcore4/cmd/arg/AHPlayerWrapperColl.java @@ -9,12 +9,12 @@ import com.massivecraft.mcore4.store.Coll; import com.massivecraft.mcore4.util.PlayerUtil; import com.massivecraft.mcore4.util.Txt; -public class AHPlayerWrapperNew extends AHBase +public class AHPlayerWrapperColl extends AHBase { final Coll coll; public Coll coll() { return this.coll; }; - public AHPlayerWrapperNew(Coll coll) + public AHPlayerWrapperColl(Coll coll) { this.coll = coll; } diff --git a/src/com/massivecraft/mcore4/cmd/arg/AHPlayerWrapperColls.java b/src/com/massivecraft/mcore4/cmd/arg/AHPlayerWrapperColls.java new file mode 100644 index 00000000..e448e35b --- /dev/null +++ b/src/com/massivecraft/mcore4/cmd/arg/AHPlayerWrapperColls.java @@ -0,0 +1,28 @@ +package com.massivecraft.mcore4.cmd.arg; + +import org.bukkit.command.CommandSender; + +import com.massivecraft.mcore4.MPlugin; +import com.massivecraft.mcore4.store.Coll; +import com.massivecraft.mcore4.store.Colls; +public class AHPlayerWrapperColls extends AHBase +{ + protected final Colls, E, ?> colls; + public Colls, E, ?> colls() { return this.colls; }; + + @SuppressWarnings("unchecked") + public AHPlayerWrapperColls(Object colls) + { + this.colls = (Colls, E, ?>) colls; + } + + @Override + public E parse(String str, String style, CommandSender sender, MPlugin p) + { + Coll coll = colls.get(sender); + AHPlayerWrapperColl ahinner = new AHPlayerWrapperColl(coll); + E ret = ahinner.parse(str, style, sender, p); + this.error.addAll(ahinner.error); + return ret; + } +} diff --git a/src/com/massivecraft/mcore4/store/Coll.java b/src/com/massivecraft/mcore4/store/Coll.java index c02681bf..caa7dd39 100644 --- a/src/com/massivecraft/mcore4/store/Coll.java +++ b/src/com/massivecraft/mcore4/store/Coll.java @@ -14,6 +14,7 @@ import java.util.concurrent.CopyOnWriteArrayList; import com.massivecraft.mcore4.MCore; import com.massivecraft.mcore4.MPlugin; import com.massivecraft.mcore4.Predictate; +import com.massivecraft.mcore4.store.accessor.Accessor; import com.massivecraft.mcore4.store.idstrategy.IdStrategy; import com.massivecraft.mcore4.store.storeadapter.StoreAdapter; @@ -121,9 +122,14 @@ public class Coll implements CollInterface @Override public boolean isDefault(E entity) { return false; } // -------------------------------------------- // - // CREATE + // COPY AND CREATE // -------------------------------------------- // + public void copy(Object ofrom, Object oto) + { + Accessor.get(this.entityClass()).copy(ofrom, oto); + } + // This simply creates and returns a new instance // It does not detach/attach or anything. Just creates a new instance. @Override @@ -176,6 +182,7 @@ public class Coll implements CollInterface return this.attach(entity, oid, true); } + @SuppressWarnings({ "unchecked", "rawtypes" }) protected synchronized L attach(E entity, Object oid, boolean noteChange) { // Check entity @@ -201,6 +208,12 @@ public class Coll implements CollInterface this.id2entity.put(id, entity); this.entity2id.put(entity, id); + // Set this as the coll if possible. + if (entity instanceof Entity) + { + ((Entity)entity).setColl(this); + } + // Make note of the change if (noteChange) { diff --git a/src/com/massivecraft/mcore4/store/CollInterface.java b/src/com/massivecraft/mcore4/store/CollInterface.java index 24cc09fd..87e6fdbc 100644 --- a/src/com/massivecraft/mcore4/store/CollInterface.java +++ b/src/com/massivecraft/mcore4/store/CollInterface.java @@ -60,9 +60,11 @@ public interface CollInterface public boolean isDefault(E entity); // -------------------------------------------- // - // CREATE + // COPY AND CREATE // -------------------------------------------- // + public void copy(Object fromo, Object too); + // This simply creates and returns a new instance // It does not detach/attach or anything. Just creates a new instance. public E createNewInstance(); diff --git a/src/com/massivecraft/mcore4/store/Colls.java b/src/com/massivecraft/mcore4/store/Colls.java new file mode 100644 index 00000000..818264d7 --- /dev/null +++ b/src/com/massivecraft/mcore4/store/Colls.java @@ -0,0 +1,41 @@ +package com.massivecraft.mcore4.store; + +import java.util.HashMap; +import java.util.Map; + +import com.massivecraft.mcore4.util.MUtil; + +public abstract class Colls, E, L> +{ + public abstract String name(); + public abstract C createColl(String collName); + + public String collNameFromCategory(String category) + { + return this.name() + "_" + category; + } + + protected Map name2coll = new HashMap(); + public C get(Object worldNameExtractable) + { + String worldName = MUtil.extract(String.class, "worldName", worldNameExtractable); + String category = WCatColl.i.get(this.name()).categorize(worldName); + String collName = this.collNameFromCategory(category); + + C ret = this.name2coll.get(collName); + if (ret == null) + { + ret = this.createColl(collName); + this.name2coll.put(collName, ret); + } + + return ret; + } + + public E get2(Object worldNameExtractable) + { + C coll = this.get(worldNameExtractable); + if (coll == null) return null; + return coll.get(worldNameExtractable); + } +} diff --git a/src/com/massivecraft/mcore4/store/Entity.java b/src/com/massivecraft/mcore4/store/Entity.java index b1860833..4b910fb8 100644 --- a/src/com/massivecraft/mcore4/store/Entity.java +++ b/src/com/massivecraft/mcore4/store/Entity.java @@ -1,6 +1,8 @@ package com.massivecraft.mcore4.store; +import com.massivecraft.mcore4.MCore; import com.massivecraft.mcore4.store.accessor.Accessor; +import com.massivecraft.mcore4.xlib.gson.Gson; /** * Usage of this class is highly optional. You may persist anything. If you are @@ -12,23 +14,34 @@ import com.massivecraft.mcore4.store.accessor.Accessor; // http://www.angelikalanger.com/GenericsFAQ/FAQSections/ProgrammingIdioms.html#FAQ206 public abstract class Entity, L> { - public abstract Coll getColl(); + protected transient Coll coll; + protected void setColl(Coll val) { this.coll = val; } + public Coll getColl() { return this.coll; } protected abstract E getThis(); + protected abstract Class getClazz(); - public L attach() + public abstract E getDefaultInstance(); + + public L attach(Coll coll) { - return this.getColl().attach(getThis()); + return coll.attach(getThis()); } public E detach() { - return this.getColl().detach(getThis()); + Coll coll = this.getColl(); + if (coll == null) return null; + + return coll.detach(getThis()); } public boolean attached() { - return this.getColl().getAll().contains(getThis()); + Coll coll = this.getColl(); + if (coll == null) return false; + + return coll.getAll().contains(getThis()); } public boolean detached() @@ -38,15 +51,16 @@ public abstract class Entity, L> public L getId() { - return this.getColl().id(getThis()); + Coll coll = this.getColl(); + if (coll == null) return null; + return coll.id(this.getThis()); } - // TODO: Perhaps even brute force methods to save or load from remote. - public void changed() { L id = this.getId(); if (id == null) return; + this.getColl().changedIds.add(id); } @@ -54,6 +68,7 @@ public abstract class Entity, L> { L id = this.getId(); if (id == null) return; + this.getColl().syncId(id); } @@ -61,6 +76,7 @@ public abstract class Entity, L> { L id = this.getId(); if (id == null) return; + this.getColl().saveToRemote(id); } @@ -68,29 +84,29 @@ public abstract class Entity, L> { L id = this.getId(); if (id == null) return; + this.getColl().loadFromRemote(id); } @Override public String toString() { - return this.getClass().getSimpleName()+this.getColl().mplugin().gson.toJson(this, this.getColl().entityClass()); - } - - public E getDefaultInstance() - { - return this.getColl().createNewInstance(); + Gson gson = MCore.gson; + Coll coll = this.getColl(); + if (coll != null) gson = coll.mplugin().gson; + + return this.getClazz().getSimpleName()+gson.toJson(this, this.getClazz()); } public E loadDefaults() { - Accessor.get(this.getColl().entityClass()).copy(this.getDefaultInstance(), this.getThis()); + Accessor.get(this.getClazz()).copy(this.getDefaultInstance(), this.getThis()); return this.getThis(); } public E load(E entity) { - Accessor.get(this.getColl().entityClass()).copy(entity, this.getThis()); + Accessor.get(this.getClazz()).copy(entity, this.getThis()); return this.getThis(); } } diff --git a/src/com/massivecraft/mcore4/store/WCat.java b/src/com/massivecraft/mcore4/store/WCat.java new file mode 100644 index 00000000..8197ce22 --- /dev/null +++ b/src/com/massivecraft/mcore4/store/WCat.java @@ -0,0 +1,92 @@ +package com.massivecraft.mcore4.store; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +import com.massivecraft.mcore4.util.MUtil; + +/** + * WCat stands for World Categorizer. + * They provide a recursive matching system. + */ +public class WCat extends Entity +{ + public final static transient String RETURN = "_return"; + public final static transient String RUN = "_run"; + public final static transient String _DEFAULT = "_default"; + public final static transient String DEFAULT = "default"; + public final static transient List DEFAULT_RULES = MUtil.list(new WCatRule(RUN, _DEFAULT)); + public final static transient List DEFAULT_DEFAULT_RULES = MUtil.list(new WCatRule(RETURN, DEFAULT)); + + // -------------------------------------------- // + // META + // -------------------------------------------- // + + @Override public Coll getColl() { return WCatColl.i; } + @Override protected WCat getThis() { return this; } + + private final static transient WCat defaultInstance = new WCat(); + @Override public WCat getDefaultInstance(){ return defaultInstance; } + @Override protected Class getClazz() { return WCat.class; } + + + // -------------------------------------------- // + // FIELDS + // -------------------------------------------- // + + protected List rules; + public List rules() { return this.rules; }; + public void rules(List val) { this.rules = new ArrayList(val); }; + public void rules(String... namesAndParams) + { + this.rules = new ArrayList(); + Iterator iter = Arrays.asList(namesAndParams).iterator(); + while (iter.hasNext()) + { + String name = iter.next(); + String param = iter.next(); + this.rules.add(new WCatRule(name, param)); + } + } + + // -------------------------------------------- // + // CONSTRUCT + // -------------------------------------------- // + + public WCat() + { + this.rules(DEFAULT_RULES); + } + + // -------------------------------------------- // + // THAT SPECIAL LOGIC + // -------------------------------------------- // + + public String categorize(String worldName) + { + for (WCatRule rule : this.rules()) + { + String name = rule.name(); + String param = rule.param(); + if (name.equals(RETURN)) + { + return param; + } + else if (name.equals(RUN)) + { + WCat subcat = WCatColl.i.get(param); + String subcatresult = subcat.categorize(worldName); + if (subcatresult != null) return subcatresult; + } + else if (name.equalsIgnoreCase(worldName)) + { + return param; + } + } + return null; + } + + +} diff --git a/src/com/massivecraft/mcore4/store/WCatColl.java b/src/com/massivecraft/mcore4/store/WCatColl.java new file mode 100644 index 00000000..aa42a542 --- /dev/null +++ b/src/com/massivecraft/mcore4/store/WCatColl.java @@ -0,0 +1,41 @@ +package com.massivecraft.mcore4.store; + +import com.massivecraft.mcore4.MCore; + +public class WCatColl extends Coll +{ + // -------------------------------------------- // + // META + // -------------------------------------------- // + public static WCatColl i = new WCatColl(); + + private WCatColl() + { + super(MCore.p, "ai", "mcore_wcat", WCat.class, String.class, true); + } + + @Override + public void copy(Object ofrom, Object oto) + { + WCat from = (WCat)ofrom; + WCat to = (WCat)oto; + to.rules = from.rules; + } + + @Override + public void init() + { + super.init(); + + // Ensure the default WorldCategorizer is present. + WCat d = this.get(WCat._DEFAULT); + d.rules(WCat.DEFAULT_DEFAULT_RULES); + } + + @Override + public boolean isDefault(WCat entity) + { + return entity.rules().equals(WCat.DEFAULT_RULES); + } + +} diff --git a/src/com/massivecraft/mcore4/store/WCatRule.java b/src/com/massivecraft/mcore4/store/WCatRule.java new file mode 100644 index 00000000..e82da987 --- /dev/null +++ b/src/com/massivecraft/mcore4/store/WCatRule.java @@ -0,0 +1,22 @@ +package com.massivecraft.mcore4.store; + +public class WCatRule +{ + protected final String name; + public String name() { return this.name; } + + protected final String param; + public String param() { return this.param; } + + public WCatRule() + { + this.name = null; + this.param = null; + } + + public WCatRule(String name, String param) + { + this.name = name; + this.param = param; + } +} diff --git a/src/com/massivecraft/mcore4/store/storeadapter/StoreAdapterGson.java b/src/com/massivecraft/mcore4/store/storeadapter/StoreAdapterGson.java index 95170d37..7c7bff70 100644 --- a/src/com/massivecraft/mcore4/store/storeadapter/StoreAdapterGson.java +++ b/src/com/massivecraft/mcore4/store/storeadapter/StoreAdapterGson.java @@ -1,7 +1,6 @@ package com.massivecraft.mcore4.store.storeadapter; import com.massivecraft.mcore4.store.Coll; -import com.massivecraft.mcore4.store.accessor.Accessor; import com.massivecraft.mcore4.xlib.gson.JsonElement; public class StoreAdapterGson extends StoreAdapterAbstract @@ -21,7 +20,7 @@ public class StoreAdapterGson extends StoreAdapterAbstract public void write(Coll coll, Object raw, Object entity) { Object temp = coll.mplugin().gson.fromJson((JsonElement)raw, coll.entityClass()); - Accessor.get(coll.entityClass()).copy(temp, entity); + coll.copy(temp, entity); } // -------------------------------------------- // diff --git a/src/com/massivecraft/mcore4/util/MUtil.java b/src/com/massivecraft/mcore4/util/MUtil.java index 59f8e668..ceed877f 100644 --- a/src/com/massivecraft/mcore4/util/MUtil.java +++ b/src/com/massivecraft/mcore4/util/MUtil.java @@ -3,6 +3,7 @@ package com.massivecraft.mcore4.util; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; +import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; @@ -23,6 +24,8 @@ import org.bukkit.event.entity.EntityDamageEvent.DamageCause; import org.bukkit.event.player.PlayerInteractEvent; import com.massivecraft.mcore4.MCore; +import com.massivecraft.mcore4.util.extractor.Extractor; +import com.massivecraft.mcore4.util.extractor.ExtractorWorldName; public class MUtil { @@ -171,4 +174,58 @@ public class MUtil if (MCore.random.nextDouble() < prob) ret += 1; return ret; } + + // -------------------------------------------- // + // EXTRACTION + // -------------------------------------------- // + + protected static Map, Map>> classesPropertiesExtractors = new HashMap, Map>>(); + protected static Map> getPropertiesExtractors(Class propertyClass) + { + Map> ret = classesPropertiesExtractors.get(propertyClass); + if (ret == null) + { + ret = new HashMap>(); + classesPropertiesExtractors.put(propertyClass, ret); + } + return ret; + } + + protected static Set getExtractors(Class propertyClass, String propertyName) + { + Map> propertiesExtractors = getPropertiesExtractors(propertyClass); + Set ret = propertiesExtractors.get(propertyName); + if (ret == null) + { + ret = new HashSet(); + propertiesExtractors.put(propertyName, ret); + } + return ret; + } + + @SuppressWarnings("unchecked") + public static T extract(Class propertyClass, String propertyName, Object o) + { + Object ret = null; + for (Extractor extractor : getExtractors(propertyClass, propertyName)) + { + ret = extractor.extract(o); + if (ret != null) break; + } + return (T) ret; + } + + public static void registerExtractor(Class clazz, String propertyName, Extractor extractor) + { + getExtractors(clazz, propertyName).add(extractor); + } + + // -------------------------------------------- // + // STATIC CONSTRUCT + // -------------------------------------------- // + + static + { + registerExtractor(String.class, "worldName", new ExtractorWorldName()); + } } diff --git a/src/com/massivecraft/mcore4/util/Txt.java b/src/com/massivecraft/mcore4/util/Txt.java index 2700dc26..edd13c54 100644 --- a/src/com/massivecraft/mcore4/util/Txt.java +++ b/src/com/massivecraft/mcore4/util/Txt.java @@ -226,7 +226,7 @@ public class Txt } else { - ret.append(list[i].toString()); + ret.append(str); } } return ret.toString(); diff --git a/src/com/massivecraft/mcore4/util/extractor/Extractor.java b/src/com/massivecraft/mcore4/util/extractor/Extractor.java new file mode 100644 index 00000000..cf43d67a --- /dev/null +++ b/src/com/massivecraft/mcore4/util/extractor/Extractor.java @@ -0,0 +1,6 @@ +package com.massivecraft.mcore4.util.extractor; + +public interface Extractor +{ + public Object extract(Object o); +} diff --git a/src/com/massivecraft/mcore4/util/extractor/ExtractorWorldName.java b/src/com/massivecraft/mcore4/util/extractor/ExtractorWorldName.java new file mode 100644 index 00000000..bd599519 --- /dev/null +++ b/src/com/massivecraft/mcore4/util/extractor/ExtractorWorldName.java @@ -0,0 +1,22 @@ +package com.massivecraft.mcore4.util.extractor; + +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.entity.Entity; +import org.bukkit.event.player.PlayerEvent; + +public class ExtractorWorldName implements Extractor +{ + @Override + public Object extract(Object o) + { + if (o instanceof String) return o; + if (o instanceof World) return ((World)o).getName(); + if (o instanceof Block) return ((Block)o).getWorld().getName(); + if (o instanceof Location) return ((Location)o).getWorld().getName(); + if (o instanceof Entity) return ((Entity)o).getWorld().getName(); + if (o instanceof PlayerEvent) return ((PlayerEvent)o).getPlayer().getWorld().getName(); + return null; + } +}