This commit is contained in:
Olof Larsson
2012-11-11 13:07:30 +01:00
parent 822db7a308
commit 000a9e628a
353 changed files with 1292 additions and 1291 deletions

View File

@@ -0,0 +1,29 @@
package com.massivecraft.mcore5;
import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import com.massivecraft.mcore5.usys.cmd.CmdUsys;
import com.massivecraft.mcore5.util.MUtil;
public class Conf extends SimpleConfig
{
// -------------------------------------------- //
// CONTENT
// -------------------------------------------- //
public static String dburi = "gson://./mstore";
public static String serverid = UUID.randomUUID().toString();
public static Map<String, List<String>> cmdaliases = MUtil.map(CmdUsys.USYS, MUtil.list(CmdUsys.USYS));
// -------------------------------------------- //
// META
// -------------------------------------------- //
public static transient Conf i = new Conf();
private Conf()
{
super(MCore.p, new File("plugins/mcore/conf.json"));
}
}

View File

@@ -0,0 +1,154 @@
package com.massivecraft.mcore5;
import java.util.HashMap;
import java.util.Map;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerKickEvent;
import org.bukkit.event.player.PlayerLoginEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.player.PlayerRespawnEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
import com.massivecraft.mcore5.event.MCoreAfterPlayerRespawnEvent;
import com.massivecraft.mcore5.event.MCoreAfterPlayerTeleportEvent;
import com.massivecraft.mcore5.event.MCorePlayerLeaveEvent;
import com.massivecraft.mcore5.store.Coll;
import com.massivecraft.mcore5.store.PlayerColl;
public class InternalListener implements Listener
{
MCore p;
public InternalListener(MCore p)
{
this.p = p;
MCorePlayerLeaveEvent.player2event.clear();
Bukkit.getServer().getPluginManager().registerEvents(this, this.p);
}
/*
@EventHandler(priority = EventPriority.LOW)
public void onPlayerLogin(PlayerLoginEvent event)
{
String id = event.getPlayer().getName();
for (Persist instance : Persist.instances)
{
for (IClassManager<?> manager : instance.getClassManagers().values())
{
if (manager.idCanFix(Player.class) == false) continue;
if (manager.containsId(id)) continue;
manager.create(id);
}
}
}*/
// -------------------------------------------- //
// AFTER EVENTS
// -------------------------------------------- //
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void after(PlayerTeleportEvent event)
{
Bukkit.getScheduler().scheduleSyncDelayedTask(p, new MCoreAfterPlayerTeleportEvent(event), 0);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void after(PlayerRespawnEvent event)
{
Bukkit.getScheduler().scheduleSyncDelayedTask(p, new MCoreAfterPlayerRespawnEvent(event, event.getPlayer().getLocation()), 0);
}
// -------------------------------------------- //
// EVENT TOOL: causedByKick
// -------------------------------------------- //
public static Map<String,String> kickedPlayerReasons = new HashMap<String,String>();
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void causedByKick(PlayerKickEvent event)
{
final String name = event.getPlayer().getName();
kickedPlayerReasons.put(name, event.getReason());
}
@EventHandler(priority = EventPriority.MONITOR)
public void causedByKick(PlayerQuitEvent event)
{
// We do the schedule in order for the set to be correct through out the whole MONITOR priority state.
final String name = event.getPlayer().getName();
Bukkit.getScheduler().scheduleSyncDelayedTask(MCore.p, new Runnable()
{
@Override
public void run()
{
kickedPlayerReasons.remove(name);
}
});
}
// -------------------------------------------- //
// PLAYER LEAVE EVENT
// -------------------------------------------- //
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void leaveEventKickCall(PlayerKickEvent event)
{
new MCorePlayerLeaveEvent(event.getPlayer(), true, "kick", event.getReason()).run();
}
@EventHandler(priority = EventPriority.MONITOR)
public void leaveEventQuitCall(PlayerQuitEvent event)
{
new MCorePlayerLeaveEvent(event.getPlayer(), false, "quit", null).run();
}
@EventHandler(priority = EventPriority.MONITOR)
public void leaveEventQuitClear(PlayerQuitEvent event)
{
// We do the schedule in order for the set to be correct through out the whole MONITOR priority state.
final String name = event.getPlayer().getName();
Bukkit.getScheduler().scheduleSyncDelayedTask(MCore.p, new Runnable()
{
@Override
public void run()
{
MCorePlayerLeaveEvent.player2event.remove(name);
}
});
}
// -------------------------------------------- //
// SYNC PLAYER ON LOGON AND LEAVE
// -------------------------------------------- //
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
public void syncOnPlayerLogin(PlayerLoginEvent event)
{
//p.log("syncOnPlayerLogin", event.getPlayer().getName());
this.syncAllForPlayer(event.getPlayer());
}
@EventHandler(priority = EventPriority.MONITOR)
public void syncOnPlayerLeave(MCorePlayerLeaveEvent event)
{
//p.log("syncOnPlayerLeave", event.getPlayer().getName());
this.syncAllForPlayer(event.getPlayer());
}
public void syncAllForPlayer(Player player)
{
String playerName = player.getName();
for (Coll<?, ?> coll : Coll.instances)
{
if (!(coll instanceof PlayerColl)) continue;
PlayerColl<?> pcoll = (PlayerColl<?>)coll;
pcoll.syncId(playerName);
}
}
}

View File

@@ -0,0 +1,12 @@
package com.massivecraft.mcore5;
public class Lang
{
public static final String permForbidden = "<b>You don't have permission to %s.";
public static final String permDoThat = "do that";
public static final String commandSenderMustBePlayer = "<b>This command can only be used by ingame players.";
public static final String commandToFewArgs = "<b>To few arguments. <i>Use like this:";
public static final String commandToManyArgs = "<b>Strange arguments %s<b>.";
public static final String commandToManyArgs2 = "<i>Use the command like this:";
}

View File

@@ -0,0 +1,119 @@
package com.massivecraft.mcore5;
import java.lang.reflect.Modifier;
import java.util.Random;
import org.bukkit.Bukkit;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import com.massivecraft.mcore5.adapter.InventoryAdapter;
import com.massivecraft.mcore5.adapter.ItemStackAdapter;
import com.massivecraft.mcore5.adapter.MongoURIAdapter;
import com.massivecraft.mcore5.adapter.PSAdapter;
import com.massivecraft.mcore5.store.Coll;
import com.massivecraft.mcore5.store.Db;
import com.massivecraft.mcore5.store.MStore;
import com.massivecraft.mcore5.usys.AspectColl;
import com.massivecraft.mcore5.usys.MultiverseColl;
import com.massivecraft.mcore5.usys.cmd.CmdUsys;
import com.massivecraft.mcore5.util.PlayerUtil;
import com.massivecraft.mcore5.xlib.gson.Gson;
import com.massivecraft.mcore5.xlib.gson.GsonBuilder;
import com.massivecraft.mcore5.xlib.mongodb.MongoURI;
public class MCore extends MPlugin
{
// -------------------------------------------- //
// COMMON CONSTANTS
// -------------------------------------------- //
public final static String INSTANCE = "instance";
public final static String DEFAULT = "default";
// -------------------------------------------- //
// STATIC
// -------------------------------------------- //
public static Random random = new Random();
public static Gson gson = getMCoreGsonBuilder().create();
public static GsonBuilder getMCoreGsonBuilder()
{
return new GsonBuilder()
.setPrettyPrinting()
.disableHtmlEscaping()
.excludeFieldsWithModifiers(Modifier.TRANSIENT)
.registerTypeAdapter(MongoURI.class, MongoURIAdapter.get())
.registerTypeAdapter(ItemStack.class, new ItemStackAdapter())
.registerTypeAdapter(Inventory.class, new InventoryAdapter())
.registerTypeAdapter(PS.class, new PSAdapter());
}
public static String getServerId() { return Conf.serverid; }
private static Db<?> db;
public static Db<?> getDb() { return db; }
// -------------------------------------------- //
// CONSTRUCT
// -------------------------------------------- //
public static MCore p;
public MCore()
{
p = this;
}
// -------------------------------------------- //
// NON STATIC :)
// -------------------------------------------- //
private Runnable collTickTask = new Runnable()
{
public void run()
{
for (Coll<?, ?> coll : Coll.instances)
{
coll.onTick();
}
}
};
public InternalListener internalListener;
public CmdUsys cmdUsys;
@Override
public void onEnable()
{
// This is safe since all plugins using Persist should bukkit-depend this plugin.
// Note this one must be before preEnable. dooh.
Coll.instances.clear();
if ( ! preEnable()) return;
Conf.i.load();
// Setup the default database
db = MStore.getDb(Conf.dburi);
// Setup PlayerUtil and it's events
new PlayerUtil(this);
// Register events
this.internalListener = new InternalListener(this);
// Schedule the collection ticker.
Bukkit.getScheduler().scheduleSyncRepeatingTask(this, this.collTickTask, 1, 1);
// Init internal collections
MultiverseColl.i.init();
AspectColl.i.init();
// Register commands
this.cmdUsys = new CmdUsys();
this.cmdUsys.register(true);
this.postEnable();
}
}

View File

@@ -0,0 +1,116 @@
package com.massivecraft.mcore5;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.event.Listener;
import org.bukkit.plugin.java.JavaPlugin;
import com.massivecraft.mcore5.integration.Integration;
import com.massivecraft.mcore5.integration.IntegrationFeatures;
import com.massivecraft.mcore5.store.Coll;
import com.massivecraft.mcore5.util.Txt;
import com.massivecraft.mcore5.xlib.gson.Gson;
import com.massivecraft.mcore5.xlib.gson.GsonBuilder;
public abstract class MPlugin extends JavaPlugin implements Listener
{
// Gson
public Gson gson;
// -------------------------------------------- //
// ENABLE
// -------------------------------------------- //
private long timeEnableStart;
public boolean preEnable()
{
timeEnableStart = System.currentTimeMillis();
this.logPrefixColored = Txt.parse("<teal>[<aqua>%s %s<teal>] <i>", this.getDescription().getName(), this.getDescription().getVersion());
this.logPrefixPlain = ChatColor.stripColor(this.logPrefixColored);
log("=== ENABLE START ===");
// Create Gson
this.gson = this.getGsonBuilder().create();
return true;
}
public void postEnable()
{
log(Txt.parse("=== ENABLE <g>COMPLETE <i>(Took <h>"+(System.currentTimeMillis()-timeEnableStart)+"ms<i>) ==="));
}
// -------------------------------------------- //
// DISABLE
// -------------------------------------------- //
public void onDisable()
{
// Collection shutdowns.
for (Coll<?, ?> coll : Coll.instances)
{
if (coll.getMplugin() != this) continue;
coll.examineThread().interrupt();
coll.syncAll(); // TODO: Save outwards only? We may want to avoid loads at this stage...
Coll.instances.remove(coll);
}
log("Disabled");
}
// -------------------------------------------- //
// GSON
// -------------------------------------------- //
public GsonBuilder getGsonBuilder()
{
return MCore.getMCoreGsonBuilder();
}
// -------------------------------------------- //
// CONVENIENCE
// -------------------------------------------- //
public void suicide()
{
log(Txt.parse("<b>Now I suicide!"));
Bukkit.getPluginManager().disablePlugin(this);
}
public void integrate(IntegrationFeatures... features)
{
for (IntegrationFeatures f : features)
{
new Integration(this, f);
}
}
// -------------------------------------------- //
// LOGGING
// -------------------------------------------- //
private String logPrefixColored = null;
private String logPrefixPlain = null;
public void log(Object... msg)
{
log(Level.INFO, msg);
}
public void log(Level level, Object... msg)
{
String imploded = Txt.implode(msg, " ");
ConsoleCommandSender sender = Bukkit.getConsoleSender();
if (level == Level.INFO && sender != null)
{
Bukkit.getConsoleSender().sendMessage(this.logPrefixColored + imploded);
}
else
{
Logger.getLogger("Minecraft").log(level, this.logPrefixPlain + imploded);
}
}
}

View File

@@ -0,0 +1,614 @@
package com.massivecraft.mcore5;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
import org.bukkit.util.Vector;
import com.massivecraft.mcore5.util.Txt;
import com.massivecraft.mcore5.xlib.gson.annotations.SerializedName;
/**
* PS stands for PhysicalState.
* This class stores data related to just that.
* When coding plugins you may find yourself wanting to store a player location.
* Another time you may want to store the player location but without the worldName info.
* Another time you may want to store pitch and yaw only.
* This class is supposed to be usable in all those cases.
* Hopefully this class will save you from implementing special classes for all those combinations.
*/
@EqualsAndHashCode
public class PS implements Cloneable
{
// -------------------------------------------- //
// TELEPORTER
// -------------------------------------------- //
public static transient PSTeleporter teleporter = PSTeleporterDefault.get();
// -------------------------------------------- //
// FIELDS
// -------------------------------------------- //
// Field: worldName
@SerializedName("w")
@Getter @Setter protected String worldName = null;
// FakeField: world
public World getWorld()
{
if (this.worldName == null) return null;
return Bukkit.getWorld(this.worldName);
}
public void setWorld(World val)
{
this.worldName = val.getName();
}
// ---------------------
// Field: blockX
@SerializedName("bx")
@Getter @Setter protected Integer blockX = null;
public Integer calcBlockX()
{
return calcBlock(this.locationX, this.blockX, this.chunkX);
}
// Field: blockY
@SerializedName("by")
@Getter @Setter protected Integer blockY = null;
public Integer calcBlockY()
{
return calcBlock(this.locationY, this.blockY, null);
}
// Field: blockZ
@SerializedName("bz")
@Getter @Setter protected Integer blockZ = null;
public Integer calcBlockZ()
{
return calcBlock(this.locationZ, this.blockZ, this.chunkZ);
}
protected static synchronized Integer calcBlock(Double location, Integer block, Integer chunk)
{
if (block != null) return block;
if (location != null) return (int) Math.floor(location);
if (chunk != null) return chunk * 16;
return null;
}
// ---------------------
// Field: locationX
@SerializedName("lx")
@Getter @Setter protected Double locationX = null;
public Double calcLocationX()
{
return calcLocation(this.locationX, this.blockX, this.chunkX);
}
// Field: locationY
@SerializedName("ly")
@Getter @Setter protected Double locationY = null;
public Double calcLocationY()
{
return calcLocation(this.locationY, this.blockY, null);
}
// Field: locationZ
@SerializedName("lz")
@Getter @Setter protected Double locationZ = null;
public Double calclocationZ()
{
return calcLocation(this.locationZ, this.blockZ, this.chunkZ);
}
protected static synchronized Double calcLocation(Double location, Integer block, Integer chunk)
{
if (location != null) return location;
if (block != null) return (double) block;
if (chunk != null) return chunk * 16D;
return null;
}
// ---------------------
// Field: chunkX
@SerializedName("cx")
@Getter @Setter protected Integer chunkX = null;
public Integer calcChunkX()
{
return calcChunk(this.locationX, this.blockX, this.chunkX);
}
// Field: chunkZ
@SerializedName("xz")
@Getter @Setter protected Integer chunkZ = null;
public Integer calcChunkZ()
{
return calcChunk(this.locationZ, this.blockZ, this.chunkZ);
}
protected static synchronized Integer calcChunk(Double location, Integer block, Integer chunk)
{
if (chunk != null) return chunk;
if (location != null) return location.intValue() >> 4;
if (block != null) return block >> 4;
return null;
}
// ---------------------
// Field: pitch
@SerializedName("p")
@Getter protected Float pitch = null;
public void setPitch(Float val)
{
if (val == null)
{
this.pitch = null;
}
else
{
this.pitch = (val + 360F) % 360F;
}
}
// Field: yaw
@SerializedName("y")
@Getter @Setter protected Float yaw = null;
// ---------------------
// Field: velocityX
@SerializedName("vx")
@Getter @Setter protected Double velocityX = null;
public Double calcVelocityX()
{
return calcVelocity(this.locationX, this.blockX, this.chunkX, this.velocityX);
}
// Field: velocityY
@SerializedName("vy")
@Getter @Setter protected Double velocityY = null;
public Double calcVelocityY()
{
return calcVelocity(this.locationY, this.blockY, 0, this.velocityY);
}
// Field: velocityZ
@SerializedName("vz")
@Getter @Setter protected Double velocityZ = null;
public Double calcVelocityZ()
{
return calcVelocity(this.locationZ, this.blockZ, this.chunkZ, this.velocityZ);
}
protected static synchronized Double calcVelocity(Double location, Integer block, Integer chunk, Double velocity)
{
if (velocity != null) return velocity;
if (location != null) return location;
if (block != null) return (double) block;
if (chunk != null) return chunk * 16D;
return null;
}
//----------------------------------------------//
// GET / CALC
//----------------------------------------------//
public synchronized Location getLocation()
{
return this.innerLocation(this.getLocationX(), this.getLocationY(), this.getLocationZ());
}
public synchronized Location calcLocation()
{
return this.innerLocation(this.calcLocationX(), this.calcLocationY(), this.calclocationZ());
}
protected synchronized Location innerLocation(Double x, Double y, Double z)
{
World world = this.getWorld();
if (x == null) return null;
if (y == null) return null;
if (z == null) return null;
Float pitch = this.getPitch();
if (pitch == null) pitch = 0F;
Float yaw = this.getYaw();
if (yaw == null) yaw = 0F;
return new Location(world, x, y, z, pitch, yaw);
}
public synchronized Block getBlock()
{
return this.innerBlock(this.getBlockX(), this.getBlockY(), this.getBlockZ());
}
public synchronized Block calcBlock()
{
return this.innerBlock(this.calcBlockX(), this.calcBlockY(), this.calcBlockZ());
}
protected synchronized Block innerBlock(Integer x, Integer y, Integer z)
{
World world = this.getWorld();
if (world == null) return null;
if (x == null) return null;
if (y == null) return null;
if (z == null) return null;
return world.getBlockAt(x, y, z);
}
public synchronized Chunk getChunk()
{
return this.innerChunk(this.getChunkX(), this.getChunkZ());
}
public synchronized Chunk calcChunk()
{
return this.innerChunk(this.calcChunkX(), this.calcChunkZ());
}
protected synchronized Chunk innerChunk(Integer x, Integer z)
{
World world = this.getWorld();
if (world == null) return null;
if (x == null) return null;
if (z == null) return null;
return world.getChunkAt(x, z);
}
public synchronized Vector getVelocity()
{
return this.innerVelocity(this.getVelocityX(), this.getVelocityY(), this.getVelocityZ());
}
public synchronized Vector calcVelocity()
{
return this.innerVelocity(this.calcVelocityX(), this.calcVelocityY(), this.calcVelocityZ());
}
protected synchronized Vector innerVelocity(Double x, Double y, Double z)
{
if (x == null) return null;
if (y == null) return null;
if (z == null) return null;
return new Vector(x, y, z);
}
//----------------------------------------------//
// SET
//----------------------------------------------//
public synchronized void setDefault()
{
this.worldName = null;
this.blockX = null;
this.blockY = null;
this.blockZ = null;
this.locationX = null;
this.locationY = null;
this.locationZ = null;
this.chunkX = null;
this.chunkZ = null;
this.pitch = null;
this.yaw = null;
this.velocityX = null;
this.velocityY = null;
this.velocityZ = null;
}
public synchronized void setPSTransparent(PS ps)
{
if (ps.worldName != null) this.worldName = ps.worldName;
if (ps.blockX != null) this.blockX = ps.blockX;
if (ps.blockY != null) this.blockY = ps.blockY;
if (ps.blockZ != null) this.blockZ = ps.blockZ;
if (ps.locationX != null) this.locationX = ps.locationX;
if (ps.locationY != null) this.locationY = ps.locationY;
if (ps.locationZ != null) this.locationZ = ps.locationZ;
if (ps.chunkX != null) this.chunkX = ps.chunkX;
if (ps.chunkZ != null) this.chunkZ = ps.chunkZ;
if (ps.pitch != null) this.pitch = ps.pitch;
if (ps.yaw != null) this.yaw = ps.yaw;
if (ps.velocityX != null) this.velocityX = ps.velocityX;
if (ps.velocityY != null) this.velocityY = ps.velocityY;
if (ps.velocityZ != null) this.velocityZ = ps.velocityZ;
}
public synchronized void setPS(PS ps)
{
this.worldName = ps.worldName;
this.blockX = ps.blockX;
this.blockY = ps.blockY;
this.blockZ = ps.blockZ;
this.locationX = ps.locationX;
this.locationY = ps.locationY;
this.locationZ = ps.locationZ;
this.chunkX = ps.chunkX;
this.chunkZ = ps.chunkZ;
this.pitch = ps.pitch;
this.yaw = ps.yaw;
this.velocityX = ps.velocityX;
this.velocityY = ps.velocityY;
this.velocityZ = ps.velocityZ;
}
// ---------------------
public synchronized void setLocation(Location location)
{
this.setDefault();
this.setLocationTransparent(location);
}
public synchronized void setLocationTransparent(Location location)
{
this.worldName = location.getWorld().getName();
this.locationX = location.getX();
this.locationY = location.getY();
this.locationZ = location.getZ();
this.setPitch(location.getPitch());
this.yaw = location.getYaw();
}
// ---------------------
public synchronized void setVelocity(Vector vector)
{
this.setDefault();
this.setVelocityTransparent(vector);
}
public synchronized void setVelocityTransparent(Vector vector)
{
this.velocityX = vector.getX();
this.velocityY = vector.getY();
this.velocityZ = vector.getZ();
}
// ---------------------
public synchronized void setEntity(Entity entity)
{
this.setDefault();
this.setEntityTransparent(entity);
}
public synchronized void setEntityTransparent(Entity entity)
{
this.setLocationTransparent(entity.getLocation());
this.setVelocityTransparent(entity.getVelocity());
}
// ---------------------
public synchronized void setBlock(Block block)
{
this.setDefault();
this.setBlockTransparent(block);
}
public synchronized void setBlockTransparent(Block block)
{
this.worldName = block.getWorld().getName();
this.blockX = block.getX();
this.blockY = block.getY();
this.blockZ = block.getZ();
}
// ---------------------
public synchronized void setChunk(Chunk chunk)
{
this.setDefault();
this.setChunkTransparent(chunk);
}
public synchronized void setChunkTransparent(Chunk chunk)
{
this.worldName = chunk.getWorld().getName();
this.chunkX = chunk.getX();
this.chunkZ = chunk.getZ();
}
// ---------------------
public synchronized void setOldString(String str)
{
this.setDefault();
this.setOldStringTransparent(str);
}
public synchronized void setOldStringTransparent(String str)
{
String[] parts = str.split("\\|");
if (parts.length == 4)
{
this.worldName = parts[0];
this.blockX = Integer.parseInt(parts[1]);
this.blockY = Integer.parseInt(parts[2]);
this.blockZ = Integer.parseInt(parts[3]);
}
else if (parts.length == 6)
{
this.worldName = parts[0];
this.locationX = Double.parseDouble(parts[1]);
this.locationY = Double.parseDouble(parts[2]);
this.locationZ = Double.parseDouble(parts[3]);
this.pitch = Float.parseFloat(parts[4]);
this.yaw = Float.parseFloat(parts[5]);
}
}
//----------------------------------------------//
// WRITERS
//----------------------------------------------//
public synchronized void write(Entity entity)
{
teleporter.teleport(entity, this);
}
//----------------------------------------------//
// CONSTRUCTORS
//----------------------------------------------//
public PS()
{
}
public PS(PS ps)
{
this.setPS(ps);
}
public PS(Location location)
{
this.setLocationTransparent(location);
}
public PS(Vector velocity)
{
this.setVelocityTransparent(velocity);
}
public PS(Entity entity)
{
this.setEntityTransparent(entity);
}
public PS(Block block)
{
this.setBlockTransparent(block);
}
public PS(Chunk chunk)
{
this.setChunkTransparent(chunk);
}
public PS(String oldString)
{
this.setOldStringTransparent(oldString);
}
//----------------------------------------------//
// TO STRING
//----------------------------------------------//
@Override
public synchronized String toString()
{
return this.getClass().getSimpleName()+MCore.gson.toJson(this);
}
protected final transient static DecimalFormat twoDForm = new DecimalFormat("#.##");
public List<String> getDesc()
{
// ret.add("<h>World <a>"+this.worldName);
return this.getDesc("<k>%s <v>%s");
}
public List<String> getDesc(String format)
{
List<String> ret = new ArrayList<String>();
if (this.worldName != null) ret.add(Txt.parse(format, "World", this.worldName));
if (this.blockX != null) ret.add(Txt.parse(format, "Block X", this.blockX));
if (this.blockY != null) ret.add(Txt.parse(format, "Block Y", this.blockY));
if (this.blockZ != null) ret.add(Txt.parse(format, "Block Z", this.blockZ));
if (this.locationX != null) ret.add(Txt.parse(format, "Location X", twoDForm.format(this.locationX)));
if (this.locationY != null) ret.add(Txt.parse(format, "Location Y", twoDForm.format(this.locationY)));
if (this.locationZ != null) ret.add(Txt.parse(format, "Location Z", twoDForm.format(this.locationZ)));
if (this.chunkX != null) ret.add(Txt.parse(format, "Chunk X", this.chunkX));
if (this.chunkZ != null) ret.add(Txt.parse(format, "Chunk Z", this.chunkZ));
if (this.pitch != null) ret.add(Txt.parse(format, "Pitch", twoDForm.format(this.pitch)));
if (this.yaw != null) ret.add(Txt.parse(format, "Yaw", twoDForm.format(this.yaw)));
if (this.velocityX != null) ret.add(Txt.parse(format, "Velocity X", twoDForm.format(this.velocityX)));
if (this.velocityY != null) ret.add(Txt.parse(format, "Velocity Y", twoDForm.format(this.velocityY)));
if (this.velocityZ != null) ret.add(Txt.parse(format, "Velocity Z", twoDForm.format(this.velocityZ)));
return ret;
}
public String getShortDesc()
{
return this.getShortDesc("<k>%s <v>%s ");
}
public String getShortDesc(String format)
{
List<String> ret = new ArrayList<String>();
if (this.worldName != null) ret.add(Txt.parse(format, "w", this.worldName));
if (this.blockX != null) ret.add(Txt.parse(format, "bx", this.blockX));
if (this.blockY != null) ret.add(Txt.parse(format, "by", this.blockY));
if (this.blockZ != null) ret.add(Txt.parse(format, "bz", this.blockZ));
if (this.locationX != null) ret.add(Txt.parse(format, "lx", twoDForm.format(this.locationX)));
if (this.locationY != null) ret.add(Txt.parse(format, "ly", twoDForm.format(this.locationY)));
if (this.locationZ != null) ret.add(Txt.parse(format, "lz", twoDForm.format(this.locationZ)));
if (this.chunkX != null) ret.add(Txt.parse(format, "cx", this.chunkX));
if (this.chunkZ != null) ret.add(Txt.parse(format, "cz", this.chunkZ));
if (this.pitch != null) ret.add(Txt.parse(format, "p", twoDForm.format(this.pitch)));
if (this.yaw != null) ret.add(Txt.parse(format, "y", twoDForm.format(this.yaw)));
if (this.velocityX != null) ret.add(Txt.parse(format, "vx", twoDForm.format(this.velocityX)));
if (this.velocityY != null) ret.add(Txt.parse(format, "vy", twoDForm.format(this.velocityY)));
if (this.velocityZ != null) ret.add(Txt.parse(format, "vz", twoDForm.format(this.velocityZ)));
return Txt.implode(ret, "").trim();
}
//----------------------------------------------//
// CLONE
//----------------------------------------------//
@Override
public PS clone()
{
return new PS(this);
}
}

View File

@@ -0,0 +1,8 @@
package com.massivecraft.mcore5;
import org.bukkit.entity.Entity;
public interface PSTeleporter
{
public void teleport(Entity entity, PS ps);
}

View File

@@ -0,0 +1,28 @@
package com.massivecraft.mcore5;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.bukkit.util.Vector;
public class PSTeleporterDefault implements PSTeleporter
{
@Override
public void teleport(Entity entity, PS ps)
{
Location location = ps.calcLocation();
if (location != null) entity.teleport(location);
Vector velocity = ps.getVelocity();
if (velocity != null) entity.setVelocity(velocity);
}
// -------------------------------------------- //
// INSTANCE
// -------------------------------------------- //
protected static PSTeleporterDefault instance = new PSTeleporterDefault();
public static PSTeleporterDefault get()
{
return instance;
}
}

View File

@@ -0,0 +1,42 @@
package com.massivecraft.mcore5;
import org.bukkit.command.CommandSender;
import com.massivecraft.mcore5.util.Perm;
public enum Permission
{
USYS("usys"),
USYS_MULTIVERSE("usys.multiverse"),
USYS_MULTIVERSE_LIST("usys.multiverse.list"),
USYS_MULTIVERSE_SHOW("usys.multiverse.show"),
USYS_MULTIVERSE_NEW("usys.multiverse.new"),
USYS_MULTIVERSE_DEL("usys.multiverse.del"),
USYS_UNIVERSE("usys.universe"),
USYS_UNIVERSE_NEW("usys.universe.new"),
USYS_UNIVERSE_DEL("usys.universe.del"),
USYS_UNIVERSE_CLEAR("usys.universe.clear"),
USYS_WORLD("usys.world"),
USYS_ASPECT("usys.aspect"),
USYS_ASPECT_LIST("usys.aspect.list"),
USYS_ASPECT_SHOW("usys.aspect.show"),
USYS_ASPECT_USE("usys.aspect.use"),
;
public final String node;
Permission(final String permissionNode)
{
this.node = "mcore."+permissionNode;
}
public boolean has(CommandSender sender, boolean informSenderIfNot)
{
return Perm.has(sender, this.node, informSenderIfNot);
}
public boolean has(CommandSender sender)
{
return has(sender, false);
}
}

View File

@@ -0,0 +1,6 @@
package com.massivecraft.mcore5;
public interface Predictate<T>
{
public boolean apply(T type);
}

View File

@@ -0,0 +1,81 @@
package com.massivecraft.mcore5;
import java.io.File;
import com.massivecraft.mcore5.store.accessor.Accessor;
import com.massivecraft.mcore5.util.DiscUtil;
public class SimpleConfig
{
// -------------------------------------------- //
// FIELDS
// -------------------------------------------- //
protected transient MPlugin mplugin;
protected MPlugin getMplugin() { return this.mplugin; }
protected transient File file;
protected File getFile() { return this.file; }
public SimpleConfig(MPlugin mplugin, File file)
{
this.mplugin = mplugin;
this.file = file;
}
public SimpleConfig(MPlugin mplugin, String confname)
{
this(mplugin, new File(mplugin.getDataFolder(), confname+".json"));
}
public SimpleConfig(MPlugin mplugin)
{
this(mplugin, "conf");
}
// -------------------------------------------- //
// IO
// -------------------------------------------- //
protected static boolean contentRequestsDefaults(String content)
{
if (content == null) return false;
char c = content.charAt(0);
return c == 'd' || c == 'D';
}
public void load()
{
if (this.getFile().isFile())
{
String content = DiscUtil.readCatch(this.getFile());
Object toShallowLoad = null;
if (contentRequestsDefaults(content))
{
try
{
toShallowLoad = this.getClass().newInstance();
}
catch (Exception e)
{
e.printStackTrace();
return;
}
}
else
{
toShallowLoad = this.getMplugin().gson.fromJson(content, this.getClass());
}
Accessor.get(this.getClass()).copy(toShallowLoad, this);
}
save();
}
public void save()
{
String content = DiscUtil.readCatch(this.getFile());
if (contentRequestsDefaults(content)) return;
content = this.getMplugin().gson.toJson(this);
DiscUtil.writeCatch(file, content);
}
}

View File

@@ -0,0 +1,104 @@
package com.massivecraft.mcore5.adapter;
import java.lang.reflect.Type;
import org.bukkit.craftbukkit.inventory.CraftInventoryCustom;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import com.massivecraft.mcore5.xlib.gson.JsonDeserializationContext;
import com.massivecraft.mcore5.xlib.gson.JsonDeserializer;
import com.massivecraft.mcore5.xlib.gson.JsonElement;
import com.massivecraft.mcore5.xlib.gson.JsonObject;
import com.massivecraft.mcore5.xlib.gson.JsonParseException;
import com.massivecraft.mcore5.xlib.gson.JsonPrimitive;
import com.massivecraft.mcore5.xlib.gson.JsonSerializationContext;
import com.massivecraft.mcore5.xlib.gson.JsonSerializer;
public class InventoryAdapter implements JsonDeserializer<Inventory>, JsonSerializer<Inventory>
{
// -------------------------------------------- //
// FIELD NAME CONSTANTS
// -------------------------------------------- //
public static final String SIZE = "size";
// -------------------------------------------- //
// IMPLEMENTATION
// -------------------------------------------- //
@Override
public JsonElement serialize(Inventory src, Type typeOfSrc, JsonSerializationContext context)
{
return toJson(src);
}
@Override
public Inventory deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
{
return fromJson(json);
}
// -------------------------------------------- //
// JSON
// -------------------------------------------- //
public static JsonElement toJson(Inventory src)
{
JsonObject jsonInventory = new JsonObject();
ItemStack[] itemStacks = src.getContents();
jsonInventory.add(SIZE, new JsonPrimitive(itemStacks.length));
for (int i = 0; i < itemStacks.length; i++)
{
ItemStack itemStack = itemStacks[i];
JsonObject jsonItemStack = ItemStackAdapter.toJson(itemStack);
if (jsonItemStack == null) continue;
jsonInventory.add(String.valueOf(i), jsonItemStack);
}
return jsonInventory;
}
public static Inventory fromJson(JsonElement json)
{
if ( ! json.isJsonObject()) return null;
JsonObject jsonInventory = json.getAsJsonObject();
if ( ! jsonInventory.has(SIZE)) return null;
int size = jsonInventory.get(SIZE).getAsInt();
ItemStack[] itemStacks = new ItemStack[size];
for (int i = 0; i < size; i++)
{
// Fetch the jsonItemStack or mark it as empty and continue
String stackIdx = String.valueOf(i);
JsonElement jsonItemStack = jsonInventory.get(stackIdx);
ItemStack itemStack = ItemStackAdapter.fromJson(jsonItemStack);
itemStacks[i] = itemStack;
}
Inventory ret = new CraftInventoryCustom(null, size, "items");
ret.setContents(itemStacks);
return ret;
}
// -------------------------------------------- //
// UTIL
// -------------------------------------------- //
// This utility is nice to have in many cases :)
public static boolean isInventoryEmpty(Inventory inv)
{
if (inv == null) return true;
for (ItemStack stack : inv.getContents())
{
if (stack == null) continue;
if (stack.getAmount() == 0) continue;
if (stack.getTypeId() == 0) continue;
return false;
}
return true;
}
}

View File

@@ -0,0 +1,171 @@
package com.massivecraft.mcore5.adapter;
import java.lang.reflect.Type;
import java.util.Map.Entry;
import net.minecraft.server.NBTBase;
import net.minecraft.server.NBTTagCompound;
import org.bukkit.craftbukkit.inventory.CraftItemStack;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemStack;
import com.massivecraft.mcore5.xlib.gson.JsonDeserializationContext;
import com.massivecraft.mcore5.xlib.gson.JsonDeserializer;
import com.massivecraft.mcore5.xlib.gson.JsonElement;
import com.massivecraft.mcore5.xlib.gson.JsonObject;
import com.massivecraft.mcore5.xlib.gson.JsonParseException;
import com.massivecraft.mcore5.xlib.gson.JsonSerializationContext;
import com.massivecraft.mcore5.xlib.gson.JsonSerializer;
public class ItemStackAdapter implements JsonDeserializer<ItemStack>, JsonSerializer<ItemStack>
{
// -------------------------------------------- //
// FIELD NAME CONSTANTS
// -------------------------------------------- //
public static final String TYPE = "type";
public static final String AMOUNT = "amount";
public static final String DAMAGE = "damage";
public static final String ENCHANTMENTS = "enchantments";
public static final String TAG = "tag";
// -------------------------------------------- //
// IMPLEMENTATION
// -------------------------------------------- //
@Override
public JsonElement serialize(ItemStack itemStack, Type typeOfSrc, JsonSerializationContext context)
{
return toJson(itemStack);
}
@Override
public ItemStack deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
{
return fromJson(json);
}
// -------------------------------------------- //
// JSON
// -------------------------------------------- //
public static JsonObject toJson(ItemStack stack)
{
// Check for "nothing"
if (stack == null || stack.getTypeId() == 0 || stack.getAmount() == 0)
{
return null;
}
JsonObject jsonItemStack = new JsonObject();
// Add type id
jsonItemStack.addProperty(TYPE, stack.getTypeId());
// Add amount
if (stack.getAmount() != 1)
{
jsonItemStack.addProperty(AMOUNT, stack.getAmount());
}
// Add damage
if (stack.getDurability() != 0) // Durability is a weird name since it is the amount of damage.
{
jsonItemStack.addProperty(DAMAGE, stack.getDurability());
}
// Add enchantments
if (stack.getEnchantments().size() > 0)
{
JsonObject jsonEnchantments = new JsonObject();
for (Entry<Enchantment, Integer> entry : stack.getEnchantments().entrySet())
{
jsonEnchantments.addProperty(String.valueOf(entry.getKey().getId()), entry.getValue());
}
jsonItemStack.add(ItemStackAdapter.ENCHANTMENTS, jsonEnchantments);
}
// Add the tag if there is one
JsonObject tag = getEnchFreeGsonTagFromItemStack(stack);
if (tag != null)
{
jsonItemStack.add(TAG, tag);
}
return jsonItemStack;
}
// Used by method toJson
public static JsonObject getEnchFreeGsonTagFromItemStack(ItemStack stack)
{
if (!(stack instanceof CraftItemStack)) return null;
CraftItemStack craftItemStack = (CraftItemStack)stack;
NBTTagCompound nbt = craftItemStack.getHandle().tag;
if (nbt == null) return null;
JsonObject gsonbt = (JsonObject) NbtGsonConverter.nbtToGsonVal(nbt);
gsonbt.remove("ench");
if (gsonbt.entrySet().size() == 0) return null;
return gsonbt;
}
public static ItemStack fromJson(JsonElement json)
{
// Check for "nothing"
if (json == null || ! json.isJsonObject()) return null;
JsonObject jsonItemStack = json.getAsJsonObject();
// Populate values
int type = 0;
int amount = 1;
short damage = 0;
if (jsonItemStack.has(TYPE))
{
type = jsonItemStack.get(TYPE).getAsInt();
}
if (jsonItemStack.has(AMOUNT))
{
amount = jsonItemStack.get(AMOUNT).getAsInt();
}
if (jsonItemStack.has(DAMAGE))
{
damage = jsonItemStack.get(DAMAGE).getAsShort();
}
// Create Non enchanted stack
ItemStack stack = new ItemStack(type, amount, damage);
// Add tag
if (jsonItemStack.has(TAG))
{
JsonObject jsonbt = jsonItemStack.get(TAG).getAsJsonObject();
CraftItemStack craftItemStack = new CraftItemStack(stack);
stack = craftItemStack;
NBTBase nbt = NbtGsonConverter.gsonValToNbt(jsonbt, null, NBType.COMPOUND, NBType.UNKNOWN);
craftItemStack.getHandle().tag = (NBTTagCompound) nbt;
}
// Add enchantments if there are any
if (jsonItemStack.has(ENCHANTMENTS))
{
JsonObject jsonEnchantments = jsonItemStack.get(ENCHANTMENTS).getAsJsonObject();
for (Entry<String, JsonElement> enchantmentEntry: jsonEnchantments.entrySet())
{
int enchantmentId = Integer.valueOf(enchantmentEntry.getKey());
Integer enchantmentLevel = Integer.valueOf(enchantmentEntry.getValue().getAsString());
stack.addUnsafeEnchantment(Enchantment.getById(enchantmentId), enchantmentLevel);
}
}
return stack;
}
}

View File

@@ -0,0 +1,55 @@
package com.massivecraft.mcore5.adapter;
import java.lang.reflect.Type;
import com.massivecraft.mcore5.xlib.gson.JsonDeserializationContext;
import com.massivecraft.mcore5.xlib.gson.JsonDeserializer;
import com.massivecraft.mcore5.xlib.gson.JsonElement;
import com.massivecraft.mcore5.xlib.gson.JsonParseException;
import com.massivecraft.mcore5.xlib.gson.JsonPrimitive;
import com.massivecraft.mcore5.xlib.gson.JsonSerializationContext;
import com.massivecraft.mcore5.xlib.gson.JsonSerializer;
import com.massivecraft.mcore5.xlib.mongodb.MongoURI;
public class MongoURIAdapter implements JsonDeserializer<MongoURI>, JsonSerializer<MongoURI>
{
// -------------------------------------------- //
// IMPLEMENTATION
// -------------------------------------------- //
@Override
public JsonElement serialize(MongoURI mongoURI, Type typeOfSrc, JsonSerializationContext context)
{
return serialize(mongoURI);
}
@Override
public MongoURI deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
{
return deserialize(json);
}
// -------------------------------------------- //
// STATIC LOGIC
// -------------------------------------------- //
public static JsonElement serialize(MongoURI mongoURI)
{
return new JsonPrimitive(mongoURI.toString());
}
public static MongoURI deserialize(JsonElement json)
{
return new MongoURI(json.getAsString());
}
// -------------------------------------------- //
// INSTANCE
// -------------------------------------------- //
protected static MongoURIAdapter instance = new MongoURIAdapter();
public static MongoURIAdapter get()
{
return instance;
}
}

View File

@@ -0,0 +1,93 @@
package com.massivecraft.mcore5.adapter;
import java.util.HashMap;
import java.util.Map;
import net.minecraft.server.NBTBase;
import lombok.Getter;
public enum NBType
{
// -------------------------------------------- //
// VALUES
// -------------------------------------------- //
END(0, "end"),
BYTE(1, "byte"),
SHORT(2, "short"),
INT(3, "int"),
LONG(4, "long"),
FLOAT(5, "float"),
DOUBLE(6, "double"),
BYTEARRAY(7, "bytearray"),
STRING(8, "string"),
LIST(9, "list"),
COMPOUND(10, "compound"),
INTARRAY(11, "intarray"),
UNKNOWN(-1, "unknown"),
;
// -------------------------------------------- //
// FIELDS
// -------------------------------------------- //
@Getter final byte id;
@Getter final String name;
// -------------------------------------------- //
// CONSTRUCT
// -------------------------------------------- //
private NBType(int id, String name)
{
this.id = (byte)id;
this.name = name;
}
// -------------------------------------------- //
// STATIC UTILS
// -------------------------------------------- //
protected final static transient Map<String, NBType> tagnameToEnum = new HashMap<String, NBType>();
protected final static transient Map<Byte, NBType> byteToEnum = new HashMap<Byte, NBType>();
static
{
for (NBType value : values())
{
tagnameToEnum.put(value.getName(), value);
byteToEnum.put(value.getId(), value);
}
}
public static NBType getByName(String name)
{
NBType ret = tagnameToEnum.get(name);
if (ret == null)
{
ret = UNKNOWN;
}
return ret;
}
public static NBType getById(byte id)
{
NBType ret = byteToEnum.get(id);
if (ret == null)
{
ret = UNKNOWN;
}
return ret;
}
public static NBType getByTag(NBTBase tag)
{
NBType ret = byteToEnum.get(tag.getTypeId());
if (ret == null)
{
ret = UNKNOWN;
}
return ret;
}
}

View File

@@ -0,0 +1,328 @@
package com.massivecraft.mcore5.adapter;
import net.minecraft.server.NBTBase;
import net.minecraft.server.NBTTagByte;
import net.minecraft.server.NBTTagByteArray;
import net.minecraft.server.NBTTagCompound;
import net.minecraft.server.NBTTagDouble;
import net.minecraft.server.NBTTagEnd;
import net.minecraft.server.NBTTagFloat;
import net.minecraft.server.NBTTagInt;
import net.minecraft.server.NBTTagIntArray;
import net.minecraft.server.NBTTagList;
import net.minecraft.server.NBTTagLong;
import net.minecraft.server.NBTTagShort;
import net.minecraft.server.NBTTagString;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map.Entry;
import com.massivecraft.mcore5.xlib.gson.JsonArray;
import com.massivecraft.mcore5.xlib.gson.JsonElement;
import com.massivecraft.mcore5.xlib.gson.JsonObject;
import com.massivecraft.mcore5.xlib.gson.JsonPrimitive;
public class NbtGsonConverter
{
// -------------------------------------------- //
// CONSTANTS
// -------------------------------------------- //
public final static String TYPE = "type";
public final static String ELEMTYPE = "elemtype";
public final static String VAL = "val";
public final static String NAME = "name";
// -------------------------------------------- //
// GSON TO NBT
// -------------------------------------------- //
public static NBTBase gsonToNbt(JsonElement jsonElement)
{
return gsonToNbt(jsonElement, null);
}
public static NBTBase gsonToNbt(JsonElement jsonElement, String name)
{
// Verify and cast the jsonElement into a jsonObject.
// We could have used jsonObject as parameter type but this method signature is more flexible.
if (!jsonElement.isJsonObject())
{
// must be a json object
return null;
}
JsonObject jsonObject = jsonElement.getAsJsonObject();
// Use the internal name if there is one
JsonElement nameElement = jsonObject.get(NAME);
if (nameElement != null)
{
name = nameElement.getAsString();
}
// Fetch the type-info
JsonElement typeElement = jsonObject.get(TYPE);
if (typeElement == null)
{
// must have a type
return null;
}
NBType type = NBType.getByName(typeElement.getAsString());
// Fetch the elemtype-info (used by NBTTagList only)
NBType elemtype = NBType.UNKNOWN;
if (type == NBType.LIST)
{
JsonElement elemtypeElement = jsonObject.get(ELEMTYPE);
if (elemtypeElement == null)
{
// must have an elemtype
return null;
}
elemtype = NBType.getByName(elemtypeElement.getAsString());
}
// Fetch the value field
JsonElement val = jsonObject.get(VAL);
// Convert the value based on the info we gathered
return gsonValToNbt(val, name, type, elemtype);
}
public static NBTBase gsonValToNbt(JsonElement val, String name, NBType type, NBType elemtype)
{
NBTBase ret = null;
switch (type)
{
case END:
ret = new NBTTagEnd();
break;
case BYTE:
ret = new NBTTagByte(name, val.getAsByte());
break;
case SHORT:
ret = new NBTTagShort(name, val.getAsShort());
break;
case INT:
ret = new NBTTagInt(name, val.getAsInt());
break;
case LONG:
ret = new NBTTagLong(name, val.getAsLong());
break;
case FLOAT:
ret = new NBTTagFloat(name, val.getAsFloat());
break;
case DOUBLE:
ret = new NBTTagDouble(name, val.getAsDouble());
break;
case BYTEARRAY:
JsonArray jsonBytes = val.getAsJsonArray();
int jsonBytesSize = jsonBytes.size();
byte[] byteArray = new byte[jsonBytesSize];
for (int index = 0 ; index < jsonBytesSize ; index++)
{
byte b = jsonBytes.get(index).getAsByte();
byteArray[index] = b;
}
ret = new NBTTagByteArray(name, byteArray);
break;
case INTARRAY:
JsonArray jsonInts = val.getAsJsonArray();
int jsonIntsSize = jsonInts.size();
int[] intArray = new int[jsonIntsSize];
for (int index = 0 ; index < jsonIntsSize ; index++)
{
int i = jsonInts.get(index).getAsInt();
intArray[index] = i;
}
ret = new NBTTagIntArray(name, intArray);
break;
case STRING:
ret = new NBTTagString(name, val.getAsString());
break;
case LIST:
NBTTagList nbtlist = new NBTTagList(name);
if (!val.isJsonArray())
{
// must be an array
return null;
}
Iterator<JsonElement> iter = val.getAsJsonArray().iterator();
while (iter.hasNext())
{
nbtlist.add(gsonValToNbt(iter.next(), null, elemtype, NBType.UNKNOWN));
}
ret = nbtlist;
break;
case COMPOUND:
NBTTagCompound compound = new NBTTagCompound(name);
if (!val.isJsonObject())
{
// must be an object
return null;
}
JsonObject jsonCompound = val.getAsJsonObject();
for(Entry<String, JsonElement> entry : jsonCompound.entrySet())
{
String childName = entry.getKey();
JsonElement childJson = entry.getValue();
NBTBase child = gsonToNbt(childJson, childName);
if (child == null) continue;
compound.set(childName, child);
}
ret = compound;
break;
}
return ret;
}
// -------------------------------------------- //
// NBT TO GSON
// -------------------------------------------- //
public static JsonObject nbtToGson(NBTBase nbt, boolean includeName)
{
JsonObject ret = new JsonObject();
String name = nbt.getName();
if (includeName && name != null)
{
ret.addProperty(NAME, name);
}
NBType type = NBType.getById(nbt.getTypeId());
ret.addProperty(TYPE, type.getName());
if (type == NBType.LIST)
{
ret.addProperty(ELEMTYPE, NBType.getByTag(((NBTTagList)nbt).get(0)).getName());
}
JsonElement val = nbtToGsonVal(nbt);
if (val == null)
{
return null;
}
ret.add(VAL, val);
return ret;
}
public static JsonElement nbtToGsonVal(NBTBase nbt)
{
JsonElement val = null;
NBType type = NBType.getByTag(nbt);
switch (type)
{
case END:
// this should never happen
break;
case BYTE:
val = new JsonPrimitive(((NBTTagByte) nbt).data);
break;
case SHORT:
val = new JsonPrimitive(((NBTTagShort) nbt).data);
break;
case INT:
val = new JsonPrimitive(((NBTTagInt) nbt).data);
break;
case LONG:
val = new JsonPrimitive(((NBTTagLong) nbt).data);
break;
case FLOAT:
val = new JsonPrimitive(((NBTTagFloat) nbt).data);
break;
case DOUBLE:
val = new JsonPrimitive(((NBTTagDouble) nbt).data);
break;
case BYTEARRAY:
JsonArray jsonBytes = new JsonArray();
for (byte elem : ((NBTTagByteArray) nbt).data)
{
jsonBytes.add(new JsonPrimitive(elem));
}
val = jsonBytes;
break;
case INTARRAY:
JsonArray jsonInts = new JsonArray();
for (int elem : ((NBTTagIntArray) nbt).data)
{
jsonInts.add(new JsonPrimitive(elem));
}
val = jsonInts;
break;
case STRING:
val = new JsonPrimitive(((NBTTagString) nbt).data);
break;
case LIST:
NBTTagList nbtlist = (NBTTagList)nbt;
int size = nbtlist.size();
if (size <= 0)
{
// NBTTagList may not be empty
return null;
}
JsonArray jsonElems = new JsonArray();
for (int i = 0 ; i < size ; i++)
{
jsonElems.add(nbtToGsonVal(nbtlist.get(i)));
}
val = jsonElems;
break;
case COMPOUND:
JsonObject jsonObject = new JsonObject();
for (NBTBase child : getCompoundChildren((NBTTagCompound)nbt))
{
jsonObject.add(child.getName(), nbtToGson(child, false));
}
val = jsonObject;
break;
}
return val;
}
// -------------------------------------------- //
// UTILS
// -------------------------------------------- //
@SuppressWarnings("unchecked")
public static Collection<NBTBase> getCompoundChildren(NBTTagCompound compound)
{
return (Collection<NBTBase>)compound.c();
}
}

View File

@@ -0,0 +1,53 @@
package com.massivecraft.mcore5.adapter;
import java.lang.reflect.Type;
import com.massivecraft.mcore5.PS;
import com.massivecraft.mcore5.xlib.gson.Gson;
import com.massivecraft.mcore5.xlib.gson.JsonDeserializationContext;
import com.massivecraft.mcore5.xlib.gson.JsonDeserializer;
import com.massivecraft.mcore5.xlib.gson.JsonElement;
import com.massivecraft.mcore5.xlib.gson.JsonParseException;
import com.massivecraft.mcore5.xlib.gson.JsonPrimitive;
import com.massivecraft.mcore5.xlib.mongodb.MongoURI;
public class PSAdapter implements JsonDeserializer<PS>
{
// -------------------------------------------- //
// IMPLEMENTATION
// -------------------------------------------- //
@Override
public PS deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
{
if (json.isJsonPrimitive())
{
return new PS(json.getAsString());
}
return new Gson().fromJson(json, typeOfT);
}
// -------------------------------------------- //
// STATIC LOGIC
// -------------------------------------------- //
public static JsonElement serialize(MongoURI mongoURI)
{
return new JsonPrimitive(mongoURI.toString());
}
public static MongoURI deserialize(JsonElement json)
{
return new MongoURI(json.getAsString());
}
// -------------------------------------------- //
// INSTANCE
// -------------------------------------------- //
protected static PSAdapter instance = new PSAdapter();
public static PSAdapter get()
{
return instance;
}
}

View File

@@ -0,0 +1,28 @@
package com.massivecraft.mcore5.cmd;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import com.massivecraft.mcore5.util.Txt;
public class BukkitGlueCommand extends Command
{
protected MCommand mcommand;
public BukkitGlueCommand(MCommand mcommand)
{
super(mcommand.getAliases().get(0), mcommand.getDesc(), mcommand.getUseageTemplate(), mcommand.getAliases());
this.mcommand = mcommand;
}
@Override
public boolean execute(CommandSender sender, String commandLabel, String[] args)
{
if ( ! mcommand.p().isEnabled())
{
return false;
}
this.mcommand.execute(sender, Txt.tokenizeArguments(Txt.implode(args, " ")));
return true;
}
}

View File

@@ -0,0 +1,58 @@
package com.massivecraft.mcore5.cmd;
import java.util.ArrayList;
import com.massivecraft.mcore5.MPlugin;
import com.massivecraft.mcore5.cmd.MCommand;
import com.massivecraft.mcore5.cmd.arg.ARInteger;
import com.massivecraft.mcore5.util.Txt;
public class HelpCommand extends MCommand
{
private HelpCommand()
{
super();
this.addAliases("?", "h", "help");
this.setDesc("");
this.addOptionalArg("page","1");
}
@Override
public void perform()
{
if (this.commandChain.size() == 0) return;
MCommand parentCommand = this.commandChain.get(this.commandChain.size()-1);
ArrayList<String> lines = new ArrayList<String>();
for (String helpline : parentCommand.getHelp())
{
lines.add(Txt.parse("<a>#<i> "+helpline));
}
for(MCommand subCommand : parentCommand.getSubCommands())
{
if (subCommand.visibleTo(sender))
{
lines.add(subCommand.getUseageTemplate(this.commandChain, true, true));
}
}
Integer pagenumber = this.arg(0, ARInteger.get(), 1);
if (pagenumber == null) return;
sendMessage(Txt.getPage(lines, pagenumber, "Help for command \""+parentCommand.getAliases().get(0)+"\""));
}
@Override
public MPlugin p()
{
if (this.commandChain.size() == 0) return null;
return this.commandChain.get(this.commandChain.size()-1).p();
}
private static HelpCommand instance = new HelpCommand();
public static HelpCommand getInstance()
{
return instance;
}
}

View File

@@ -0,0 +1,520 @@
package com.massivecraft.mcore5.cmd;
import java.util.*;
import java.util.Map.Entry;
import lombok.Getter;
import lombok.Setter;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.SimpleCommandMap;
import org.bukkit.entity.Player;
import com.massivecraft.mcore5.Lang;
import com.massivecraft.mcore5.MPlugin;
import com.massivecraft.mcore5.cmd.arg.ArgReader;
import com.massivecraft.mcore5.cmd.arg.ArgResult;
import com.massivecraft.mcore5.cmd.req.IReq;
import com.massivecraft.mcore5.cmd.req.ReqHasPerm;
import com.massivecraft.mcore5.util.BukkitCommandUtil;
import com.massivecraft.mcore5.util.Perm;
import com.massivecraft.mcore5.util.Txt;
public abstract class MCommand
{
public abstract MPlugin p();
// -------------------------------------------- //
// COMMAND BEHAVIOR
// -------------------------------------------- //
// FIELD: subCommands
// The sub-commands to this command
@Getter @Setter protected List<MCommand> subCommands;
public void addSubCommand(MCommand subCommand)
{
subCommand.commandChain.addAll(this.commandChain);
subCommand.commandChain.add(this);
this.subCommands.add(subCommand);
}
// FIELD: aliases
// The different names this commands will react to
@Getter @Setter protected List<String> aliases;
public void addAliases(String... aliases) { this.aliases.addAll(Arrays.asList(aliases)); }
public void addAliases(List<String> aliases) { this.aliases.addAll(aliases); }
// FIELD: requiredArgs
// These args must always be sent
@Getter @Setter protected List<String> requiredArgs;
public void addRequiredArg(String arg) { this.requiredArgs.add(arg); }
// FIELD: optionalArgs
// These args are optional
@Getter @Setter protected Map<String, String> optionalArgs;
public void addOptionalArg(String arg, String def) { this.optionalArgs.put(arg, def); }
// FIELD: errorOnToManyArgs
// Should an error be thrown if "to many" args are sent.
protected boolean errorOnToManyArgs;
public boolean getErrorOnToManyArgs() { return this.errorOnToManyArgs; }
public void setErrorOnToManyArgs(boolean val) { this.errorOnToManyArgs = val; }
// FIELD: requirements
// All these requirements must be met for the command to be executable;
@Getter @Setter protected List<IReq> requirements;
public void addRequirements(IReq... requirements) { this.requirements.addAll(Arrays.asList(requirements)); }
// FIELD: desc
// This field may be left blank and will in such case be loaded from the permissions node instead.
// Thus make sure the permissions node description is an action description like "eat hamburgers" or "do admin stuff".
@Setter protected String desc = null;
public String getDesc()
{
if (this.desc != null) return this.desc;
String perm = this.getDescPermission();
if (perm != null)
{
String pdesc = Perm.getPermissionDescription(this.getDescPermission());
if (pdesc != null)
{
return pdesc;
}
}
return "*info unavailable*";
}
// FIELD: descPermission
// This permission node IS NOT TESTED AT ALL. It is rather used in the method above.
@Setter protected String descPermission;
public String getDescPermission()
{
if (this.descPermission != null) return this.descPermission;
// Otherwise we try to find one.
for (IReq req : this.requirements)
{
if ( ! (req instanceof ReqHasPerm)) continue;
return ((ReqHasPerm)req).getPerm();
}
return null;
}
// FIELD: help
// This is a multi-line help text for the command.
protected List<String> help = new ArrayList<String>();
public void setHelp(List<String> val) { this.help = val; }
public void setHelp(String... val) { this.help = Arrays.asList(val); }
public List<String> getHelp() { return this.help; }
// FIELD: visibilityMode
@Getter @Setter protected VisibilityMode visibilityMode;
// -------------------------------------------- //
// EXECUTION INFO
// -------------------------------------------- //
// FIELD: args
// Will contain the arguments, or and empty list if there are none.
@Getter @Setter protected List<String> args;
// FIELD: commandChain
// The command chain used to execute this command
@Getter @Setter protected List<MCommand> commandChain = new ArrayList<MCommand>();
// FIELDS: sender, me, senderIsConsole
public CommandSender sender;
public Player me;
public boolean senderIsConsole;
// -------------------------------------------- //
// BUKKIT INTEGRATION
// -------------------------------------------- //
public boolean register()
{
return register(false);
}
public boolean register(boolean override)
{
BukkitGlueCommand bgc = new BukkitGlueCommand(this);
SimpleCommandMap scm = BukkitCommandUtil.getBukkitCommandMap();
if (override)
{
// Our commands are more important than your commands :P
Map<String, Command> knownCommands = BukkitCommandUtil.getKnownCommandsFromSimpleCommandMap(scm);
String lowerLabel = bgc.getName().trim().toLowerCase();
knownCommands.remove(lowerLabel);
}
return scm.register("mcore", bgc);
}
// -------------------------------------------- //
// CONSTRUCTORS AND EXECUTOR
// -------------------------------------------- //
public MCommand()
{
this.descPermission = null;
this.subCommands = new ArrayList<MCommand>();
this.aliases = new ArrayList<String>();
this.requiredArgs = new ArrayList<String>();
this.optionalArgs = new LinkedHashMap<String, String>();
this.requirements = new ArrayList<IReq>();
this.errorOnToManyArgs = true;
this.desc = null;
this.visibilityMode = VisibilityMode.VISIBLE;
}
// The commandChain is a list of the parent command chain used to get to this command.
public void execute(CommandSender sender, List<String> args, List<MCommand> commandChain)
{
// Set the execution-time specific variables
this.sender = sender;
this.senderIsConsole = true;
this.me = null;
if (sender instanceof Player)
{
this.me = (Player) sender;
this.senderIsConsole = false;
}
this.fixSenderVars();
this.args = args;
this.commandChain = commandChain;
// Is there a matching sub command?
if (args.size() > 0 )
{
for (MCommand subCommand: this.subCommands)
{
if (subCommand.aliases.contains(args.get(0)))
{
args.remove(0);
commandChain.add(this);
subCommand.execute(sender, args, commandChain);
return;
}
}
}
if ( ! validCall(this.sender, this.args)) return;
perform();
}
public void fixSenderVars() {};
public void execute(CommandSender sender, List<String> args)
{
execute(sender, args, new ArrayList<MCommand>());
}
// This is where the command action is performed.
public abstract void perform();
// -------------------------------------------- //
// Call Validation
// -------------------------------------------- //
/**
* In this method we validate that all prerequisites to perform this command has been met.
*/
public boolean validCall(CommandSender sender, List<String> args)
{
if ( ! this.requirementsAreMet(sender, true))
{
return false;
}
if ( ! this.validArgs(args, sender))
{
return false;
}
return true;
}
public boolean visibleTo(CommandSender sender)
{
if (this.getVisibilityMode() == VisibilityMode.VISIBLE) return true;
if (this.getVisibilityMode() == VisibilityMode.INVISIBLE) return false;
return this.requirementsAreMet(sender, false);
}
public boolean requirementsAreMet(CommandSender sender, boolean informSenderIfNot)
{
for (IReq req : this.getRequirements())
{
if ( ! req.test(sender, this))
{
if (informSenderIfNot)
{
this.msg(req.createErrorMessage(sender, this));
}
return false;
}
}
return true;
}
public boolean validArgs(List<String> args, CommandSender sender)
{
if (args.size() < this.requiredArgs.size())
{
if (sender != null)
{
msg(Lang.commandToFewArgs);
sender.sendMessage(this.getUseageTemplate());
}
return false;
}
if (args.size() > this.requiredArgs.size() + this.optionalArgs.size() && this.errorOnToManyArgs)
{
if (sender != null)
{
// Get the to many string slice
List<String> theToMany = args.subList(this.requiredArgs.size() + this.optionalArgs.size(), args.size());
msg(Lang.commandToManyArgs, Txt.implodeCommaAndDot(theToMany, Txt.parse("<aqua>%s"), Txt.parse("<b>, "), Txt.parse("<b> and "), ""));
msg(Lang.commandToManyArgs2);
sender.sendMessage(this.getUseageTemplate());
}
return false;
}
return true;
}
public boolean validArgs(List<String> args)
{
return this.validArgs(args, null);
}
// -------------------------------------------- //
// Help and Usage information
// -------------------------------------------- //
public String getUseageTemplate(List<MCommand> commandChain, boolean addDesc, boolean onlyFirstAlias)
{
StringBuilder ret = new StringBuilder();
ret.append(Txt.parse("<c>"));
ret.append('/');
boolean first = true;
for (MCommand mc : commandChain)
{
if (first && onlyFirstAlias)
{
ret.append(mc.aliases.get(0));
}
else
{
ret.append(Txt.implode(mc.aliases, ","));
}
ret.append(' ');
first = false;
}
ret.append(Txt.implode(this.aliases, ","));
List<String> args = new ArrayList<String>();
for (String requiredArg : this.requiredArgs)
{
args.add("<"+requiredArg+">");
}
for (Entry<String, String> optionalArg : this.optionalArgs.entrySet())
{
String val = optionalArg.getValue();
if (val == null)
{
val = "";
}
else
{
val = "="+val;
}
args.add("["+optionalArg.getKey()+val+"]");
}
if (args.size() > 0)
{
ret.append(Txt.parse("<p>"));
ret.append(' ');
ret.append(Txt.implode(args, " "));
}
if (addDesc)
{
ret.append(' ');
ret.append(Txt.parse("<i>"));
ret.append(this.getDesc());
}
return ret.toString();
}
public String getUseageTemplate(List<MCommand> commandChain, boolean addDesc)
{
return getUseageTemplate(commandChain, addDesc, false);
}
public String getUseageTemplate(boolean addDesc)
{
return getUseageTemplate(this.commandChain, addDesc);
}
public String getUseageTemplate()
{
return getUseageTemplate(false);
}
// -------------------------------------------- //
// Message Sending Helpers
// -------------------------------------------- //
public void msg(String str, Object... args)
{
sender.sendMessage(Txt.parse(str, args));
}
public void msg(String str)
{
sender.sendMessage(Txt.parse(str));
}
public void msg(Collection<String> msgs)
{
for(String msg : msgs)
{
this.msg(msg);
}
}
public void sendMessage(String msg)
{
sender.sendMessage(msg);
}
public void sendMessage(Collection<String> msgs)
{
for(String msg : msgs)
{
this.sendMessage(msg);
}
}
// -------------------------------------------- //
// Argument Readers
// -------------------------------------------- //
public String argConcatFrom(int idx)
{
if ( ! this.argIsSet(idx)) return null;
int from = idx;
int to = args.size();
if (to <= from) return "";
return Txt.implode(this.args.subList(from, to), " ");
}
public boolean argIsSet(int idx)
{
if (this.args.size() < idx+1)
{
return false;
}
return true;
}
public String arg(int idx)
{
if ( ! this.argIsSet(idx)) return null;
return this.args.get(idx);
}
public <T> T arg(int idx, ArgReader<T> ar)
{
return this.arg(idx, ar, null);
}
public <T> T arg(int idx, ArgReader<T> argReader, T defaultNotSet)
{
String str = this.arg(idx);
if (str == null) return defaultNotSet;
ArgResult<T> result = argReader.read(str, this);
if (result.hasErrors()) this.msg(result.getErrors());
return result.getResult();
}
// -------------------------------------------- //
// Argument Readers DEPRACATED TODO
// -------------------------------------------- //
/*@Deprecated
public synchronized <T> T argAs(int idx, Class<T> clazz, String style, T defaultNotSet, T defaultNotFound)
{
if ( ! this.argIsSet(idx))
{
return defaultNotSet;
}
IArgHandler<T> handler = p().cmd.getArgHandler(clazz);
if (handler == null)
{
p().log(Level.SEVERE, "There is no ArgHandler for " + clazz.getName());
}
T ret = handler.parse(this.arg(idx), style, this.sender, p());
if (ret == null)
{
this.msg(handler.getErrors());
return defaultNotFound;
}
return ret;
}
@Deprecated
public <T> T argAs(int idx, Class<T> clazz, T defaultNotSet, T defaultNotFound)
{
return this.argAs(idx, clazz, null, defaultNotSet, defaultNotFound);
}
@Deprecated
public <T> T argAs(int idx, Class<T> clazz, String style, T defaultNotSet)
{
return this.argAs(idx, clazz, style, defaultNotSet, null);
}
@Deprecated
public <T> T argAs(int idx, Class<T> clazz, T defaultNotSet)
{
return this.argAs(idx, clazz, null, defaultNotSet, null);
}
@Deprecated
public <T> T argAs(int idx, Class<T> clazz, String style)
{
return this.argAs(idx, clazz, style, null, null);
}
@Deprecated
public <T> T argAs(int idx, Class<T> clazz)
{
return this.argAs(idx, clazz, (T)null, null);
}
*/
}

View File

@@ -0,0 +1,9 @@
package com.massivecraft.mcore5.cmd;
public enum VisibilityMode
{
VISIBLE, // Visible commands are visible to anyone. Even those who don't have permission to use it or is of invalid sender type.
SECRET, // Secret commands are visible only to those who can use the command. These commands are usually some kind of admin commands.
INVISIBLE, // Invisible commands are invisible to everyone, even those who can use the command.
;
}

View File

@@ -0,0 +1,26 @@
package com.massivecraft.mcore5.cmd.arg;
import com.massivecraft.mcore5.cmd.MCommand;
public abstract class ARAbstractPrimitive<T> implements ArgReader<T>
{
public abstract String typename();
public abstract T convert(String str) throws Exception;
@Override
public ArgResult<T> read(String str, MCommand mcommand)
{
ArgResult<T> result = new ArgResult<T>();
try
{
result.setResult(this.convert(str));
}
catch (Exception e)
{
result.getErrors().add("<b>Invalid "+this.typename()+" \"<h>"+str+"\"<b>.");
}
return result;
}
}

View File

@@ -0,0 +1,39 @@
package com.massivecraft.mcore5.cmd.arg;
import java.util.Collection;
import com.massivecraft.mcore5.cmd.MCommand;
import com.massivecraft.mcore5.util.Txt;
public abstract class ARAbstractSelect<T> implements ArgReader<T>
{
public abstract String typename();
public abstract T select(String str, MCommand mcommand);
public abstract Collection<String> altNames(MCommand mcommand);
public boolean canList(MCommand mcommand) { return true; }
@Override
public ArgResult<T> read(String str, MCommand mcommand)
{
ArgResult<T> result = new ArgResult<T>(this.select(str, mcommand));
if (!result.hasResult())
{
result.getErrors().add("<b>No "+this.typename()+" matches \"<h>"+str+"<b>\".");
if (this.canList(mcommand))
{
Collection<String> names = this.altNames(mcommand);
if (names.size() == 0)
{
result.getErrors().add("<i>Note: There is no "+this.typename()+" available.");
}
else
{
result.getErrors().add("<i>Use "+Txt.implodeCommaAndDot(names, "<h>%s", "<i>, ", " <i>or ", "<i>."));
}
}
}
return result;
}
}

View File

@@ -0,0 +1,94 @@
package com.massivecraft.mcore5.cmd.arg;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import com.massivecraft.mcore5.cmd.MCommand;
import com.massivecraft.mcore5.util.Txt;
public abstract class ARAbstractStringMatch implements ArgReader<String>
{
// -------------------------------------------- //
// IMPLEMENTATION
// -------------------------------------------- //
@Override
public ArgResult<String> read(String str, MCommand mcommand)
{
ArgResult<String> result = new ArgResult<String>();
// Find all matches
Set<String> matches = new HashSet<String>();
String perfectMatch = null;
outerloop:
for (Collection<String> altColl : this.altColls())
{
for (String alt : altColl)
{
Integer matchDistance = this.matches(str, alt);
if (matchDistance == null) continue;
if (matchDistance == 0)
{
perfectMatch = alt;
break outerloop;
}
else
{
matches.add(alt);
}
}
}
// Set result and errors
if (perfectMatch != null)
{
result.setResult(perfectMatch);
}
else if (matches.size() == 1)
{
result.setResult(matches.iterator().next());
}
else if (matches.size() > 1)
{
result.getErrors().add("<b>"+Txt.upperCaseFirst(this.typename())+" matching \"<h>"+str+"<b>\" is ambigious.");
result.getErrors().add("<b>Did you mean "+Txt.implodeCommaAndDot(matches, "<h>%s", "<b>, ", " <b>or ", "<b>?"));
}
else if (matches.size() == 0)
{
result.getErrors().add("<b>No "+this.typename()+" matching \"<h>"+str+"<b>\".");
}
return result;
}
// -------------------------------------------- //
// ABSTRACT
// -------------------------------------------- //
// return null if no match
// return 0 if perfect match
// return >0 to declare distance from perfect match
public abstract Integer matches(String arg, String alt);
// -------------------------------------------- //
// FIELDS
// -------------------------------------------- //
protected String typename;
public String typename() { return this.typename; }
protected Collection<Collection<String>> altColls;
public Collection<Collection<String>> altColls() { return this.altColls; }
// -------------------------------------------- //
// CONSTRUCT
// -------------------------------------------- //
public ARAbstractStringMatch(String typename, Collection<Collection<String>> altColls)
{
this.typename = typename;
this.altColls = altColls;
}
}

View File

@@ -0,0 +1,43 @@
package com.massivecraft.mcore5.cmd.arg;
import java.util.Collection;
import com.massivecraft.mcore5.Permission;
import com.massivecraft.mcore5.cmd.MCommand;
import com.massivecraft.mcore5.usys.Aspect;
import com.massivecraft.mcore5.usys.AspectColl;
public class ARAspect extends ARAbstractSelect<Aspect>
{
@Override
public String typename()
{
return "aspect";
}
@Override
public Aspect select(String str, MCommand mcommand)
{
return AspectColl.i.get(str);
}
@Override
public boolean canList(MCommand mcommand)
{
return Permission.USYS_ASPECT_LIST.has(mcommand.sender, false);
}
@Override
public Collection<String> altNames(MCommand mcommand)
{
return AspectColl.i.getIds();
}
// -------------------------------------------- //
// INSTANCE
// -------------------------------------------- //
private static ARAspect i = new ARAspect();
public static ARAspect get() { return i; }
}

View File

@@ -0,0 +1,29 @@
package com.massivecraft.mcore5.cmd.arg;
public class ARBoolean extends ARAbstractPrimitive<Boolean>
{
@Override
public String typename()
{
return "boolean";
}
@Override
public Boolean convert(String str) throws Exception
{
str = str.toLowerCase();
if (str.startsWith("y") || str.startsWith("t") || str.startsWith("on") || str.startsWith("+") || str.startsWith("1"))
{
return true;
}
return false;
}
// -------------------------------------------- //
// INSTANCE
// -------------------------------------------- //
private static ARBoolean i = new ARBoolean();
public static ARBoolean get() { return i; }
}

View File

@@ -0,0 +1,24 @@
package com.massivecraft.mcore5.cmd.arg;
public class ARByte extends ARAbstractPrimitive<Byte>
{
@Override
public String typename()
{
return "byte";
}
@Override
public Byte convert(String str) throws Exception
{
return Byte.parseByte(str);
}
// -------------------------------------------- //
// INSTANCE
// -------------------------------------------- //
private static ARByte i = new ARByte();
public static ARByte get() { return i; }
}

View File

@@ -0,0 +1,30 @@
package com.massivecraft.mcore5.cmd.arg;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ARDate extends ARAbstractPrimitive<Date>
{
protected static DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
@Override
public String typename()
{
return "YYYY-MM-DD date";
}
@Override
public Date convert(String str) throws Exception
{
return df.parse(str);
}
// -------------------------------------------- //
// INSTANCE
// -------------------------------------------- //
private static ARDate i = new ARDate();
public static ARDate get() { return i; }
}

View File

@@ -0,0 +1,24 @@
package com.massivecraft.mcore5.cmd.arg;
public class ARDouble extends ARAbstractPrimitive<Double>
{
@Override
public String typename()
{
return "double";
}
@Override
public Double convert(String str) throws Exception
{
return Double.parseDouble(str);
}
// -------------------------------------------- //
// INSTANCE
// -------------------------------------------- //
private static ARDouble i = new ARDouble();
public static ARDouble get() { return i; }
}

View File

@@ -0,0 +1,60 @@
package com.massivecraft.mcore5.cmd.arg;
import java.util.Collection;
import org.bukkit.World.Environment;
import com.massivecraft.mcore5.cmd.MCommand;
import com.massivecraft.mcore5.util.MUtil;
public class AREnvironment extends ARAbstractSelect<Environment>
{
@Override
public String typename()
{
return "environment";
}
@Override
public Environment select(String str, MCommand mcommand)
{
Environment ret = null;
// "THE_END" --> "end"
str = str.toLowerCase();
str = str.replace("_", "");
str = str.replace("the", "");
if (str.startsWith("no") || str.startsWith("d"))
{
// "normal" or "default"
ret = Environment.NORMAL;
}
else if (str.startsWith("ne"))
{
// "nether"
ret = Environment.NETHER;
}
else if (str.startsWith("e"))
{
// "end"
ret = Environment.THE_END;
}
return ret;
}
@Override
public Collection<String> altNames(MCommand mcommand)
{
return MUtil.list("normal", "end", "nether");
}
// -------------------------------------------- //
// INSTANCE
// -------------------------------------------- //
private static AREnvironment i = new AREnvironment();
public static AREnvironment get() { return i; }
}

View File

@@ -0,0 +1,24 @@
package com.massivecraft.mcore5.cmd.arg;
public class ARFloat extends ARAbstractPrimitive<Float>
{
@Override
public String typename()
{
return "integer";
}
@Override
public Float convert(String str) throws Exception
{
return Float.parseFloat(str);
}
// -------------------------------------------- //
// INSTANCE
// -------------------------------------------- //
private static ARFloat i = new ARFloat();
public static ARFloat get() { return i; }
}

View File

@@ -0,0 +1,24 @@
package com.massivecraft.mcore5.cmd.arg;
public class ARInteger extends ARAbstractPrimitive<Integer>
{
@Override
public String typename()
{
return "integer";
}
@Override
public Integer convert(String str) throws Exception
{
return Integer.parseInt(str);
}
// -------------------------------------------- //
// INSTANCE
// -------------------------------------------- //
private static ARInteger i = new ARInteger();
public static ARInteger get() { return i; }
}

View File

@@ -0,0 +1,24 @@
package com.massivecraft.mcore5.cmd.arg;
public class ARLong extends ARAbstractPrimitive<Long>
{
@Override
public String typename()
{
return "long";
}
@Override
public Long convert(String str) throws Exception
{
return Long.parseLong(str);
}
// -------------------------------------------- //
// INSTANCE
// -------------------------------------------- //
private static ARLong i = new ARLong();
public static ARLong get() { return i; }
}

View File

@@ -0,0 +1,28 @@
package com.massivecraft.mcore5.cmd.arg;
import org.bukkit.Material;
import com.massivecraft.mcore5.cmd.MCommand;
public class ARMaterial implements ArgReader<Material>
{
@Override
public ArgResult<Material> read(String str, MCommand mcommand)
{
ArgResult<Material> result = new ArgResult<Material>(Material.matchMaterial(str));
if (!result.hasResult())
{
result.getErrors().add("<b>No material matches <h>"+str+"<b>.");
result.getErrors().add("<i>Suggestion: <aqua>http://www.minecraftwiki.net/wiki/Data_values");
}
return result;
}
// -------------------------------------------- //
// INSTANCE
// -------------------------------------------- //
private static ARMaterial i = new ARMaterial();
public static ARMaterial get() { return i; }
}

View File

@@ -0,0 +1,43 @@
package com.massivecraft.mcore5.cmd.arg;
import java.util.Collection;
import com.massivecraft.mcore5.Permission;
import com.massivecraft.mcore5.cmd.MCommand;
import com.massivecraft.mcore5.usys.Multiverse;
import com.massivecraft.mcore5.usys.MultiverseColl;
public class ARMultiverse extends ARAbstractSelect<Multiverse>
{
@Override
public String typename()
{
return "multiverse";
}
@Override
public Multiverse select(String str, MCommand mcommand)
{
return MultiverseColl.i.get(str);
}
@Override
public boolean canList(MCommand mcommand)
{
return Permission.USYS_MULTIVERSE_LIST.has(mcommand.sender, false);
}
@Override
public Collection<String> altNames(MCommand mcommand)
{
return MultiverseColl.i.getIds();
}
// -------------------------------------------- //
// INSTANCE
// -------------------------------------------- //
private static ARMultiverse i = new ARMultiverse();
public static ARMultiverse get() { return i; }
}

View File

@@ -0,0 +1,32 @@
package com.massivecraft.mcore5.cmd.arg;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import com.massivecraft.mcore5.cmd.MCommand;
public class AROnlinePlayerExact implements ArgReader<Player>
{
@Override
public ArgResult<Player> read(String str, MCommand mcommand)
{
ArgResult<Player> result = new ArgResult<Player>();
Player player = Bukkit.getServer().getPlayerExact(str);
result.setResult(player);
if (!result.hasResult())
{
result.getErrors().add("<b>No online player with exact name \"<h>"+str+"<b\">.");
}
return result;
}
// -------------------------------------------- //
// INSTANCE
// -------------------------------------------- //
private static AROnlinePlayerExact i = new AROnlinePlayerExact();
public static AROnlinePlayerExact get() { return i; }
}

View File

@@ -0,0 +1,49 @@
package com.massivecraft.mcore5.cmd.arg;
import java.util.ArrayList;
import java.util.List;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import com.massivecraft.mcore5.cmd.MCommand;
import com.massivecraft.mcore5.util.Txt;
public class AROnlinePlayerMatch implements ArgReader<Player>
{
@Override
public ArgResult<Player> read(String str, MCommand mcommand)
{
ArgResult<Player> result = new ArgResult<Player>();
List<Player> players = Bukkit.getServer().matchPlayer(str);
if (players.size() == 1)
{
result.setResult(players.get(0));
}
else if (players.size() > 1)
{
List<String> names = new ArrayList<String>();
for (Player player : players)
{
names.add(player.getName());
}
result.getErrors().add("<b>Online player matching \"<h>"+str+"<b>\" is ambigious.");
result.getErrors().add("<b>Did you mean "+Txt.implodeCommaAndDot(names, "<h>%s", "<b>, ", " <b>or ", "<b>?"));
}
else if (players.size() == 0)
{
result.getErrors().add("<b>No online player matching \"<h>"+str+"<b\">.");
}
return result;
}
// -------------------------------------------- //
// INSTANCE
// -------------------------------------------- //
private static AROnlinePlayerMatch i = new AROnlinePlayerMatch();
public static AROnlinePlayerMatch get() { return i; }
}

View File

@@ -0,0 +1,24 @@
package com.massivecraft.mcore5.cmd.arg;
public class ARString extends ARAbstractPrimitive<String>
{
@Override
public String typename()
{
return "string";
}
@Override
public String convert(String str) throws Exception
{
return str;
}
// -------------------------------------------- //
// INSTANCE
// -------------------------------------------- //
private static ARString i = new ARString();
public static ARString get() { return i; }
}

View File

@@ -0,0 +1,53 @@
package com.massivecraft.mcore5.cmd.arg;
import com.massivecraft.mcore5.cmd.MCommand;
import com.massivecraft.mcore5.store.Coll;
import com.massivecraft.mcore5.store.Entity;
public class ARStringEntity<E extends Entity<E, String>> implements ArgReader<E>
{
// -------------------------------------------- //
// IMPLEMENTATION
// -------------------------------------------- //
@Override
public ArgResult<E> read(String str, MCommand mcommand)
{
ArgResult<E> result = new ArgResult<E>();
ArgResult<String> innerResult = this.stringReader().read(str, mcommand);
if (innerResult.hasResult())
{
String playerName = innerResult.getResult();
E entity = this.coll().get(playerName);
result.setResult(entity);
}
else
{
result.setErrors(innerResult.getErrors());
}
return result;
}
// -------------------------------------------- //
// FIELDS
// -------------------------------------------- //
protected ArgReader<String> stringReader;
public ArgReader<String> stringReader() { return this.stringReader; }
protected Coll<E, String> coll;
public Coll<E, String> coll() { return this.coll; }
// -------------------------------------------- //
// CONSTRUCT
// -------------------------------------------- //
public ARStringEntity(ArgReader<String> stringReader, Coll<E, String> coll)
{
this.stringReader = stringReader;
this.coll = coll;
}
}

View File

@@ -0,0 +1,25 @@
package com.massivecraft.mcore5.cmd.arg;
import java.util.Collection;
public class ARStringMatchFullCI extends ARAbstractStringMatch
{
// -------------------------------------------- //
// IMPLEMENTATION
// -------------------------------------------- //
@Override
public Integer matches(String arg, String alt)
{
return alt.equalsIgnoreCase(arg) ? 0 : null;
}
// -------------------------------------------- //
// CONSTRUCT
// -------------------------------------------- //
public ARStringMatchFullCI(String typename, Collection<Collection<String>> altColls)
{
super(typename, altColls);
}
}

View File

@@ -0,0 +1,25 @@
package com.massivecraft.mcore5.cmd.arg;
import java.util.Collection;
public class ARStringMatchFullCS extends ARAbstractStringMatch
{
// -------------------------------------------- //
// IMPLEMENTATION
// -------------------------------------------- //
@Override
public Integer matches(String arg, String alt)
{
return alt.equals(arg) ? 0 : null;
}
// -------------------------------------------- //
// CONSTRUCT
// -------------------------------------------- //
public ARStringMatchFullCS(String typename, Collection<Collection<String>> altColls)
{
super(typename, altColls);
}
}

View File

@@ -0,0 +1,34 @@
package com.massivecraft.mcore5.cmd.arg;
import java.util.Collection;
public class ARStringMatchStartCI extends ARAbstractStringMatch
{
// -------------------------------------------- //
// IMPLEMENTATION
// -------------------------------------------- //
@Override
public Integer matches(String arg, String alt)
{
arg = arg.toLowerCase();
alt = alt.toLowerCase();
if (alt.startsWith(arg))
{
return alt.length() - arg.length();
}
else
{
return null;
}
}
// -------------------------------------------- //
// CONSTRUCT
// -------------------------------------------- //
public ARStringMatchStartCI(String typename, Collection<Collection<String>> altColls)
{
super(typename, altColls);
}
}

View File

@@ -0,0 +1,32 @@
package com.massivecraft.mcore5.cmd.arg;
import java.util.Collection;
public class ARStringMatchStartCS extends ARAbstractStringMatch
{
// -------------------------------------------- //
// IMPLEMENTATION
// -------------------------------------------- //
@Override
public Integer matches(String arg, String alt)
{
if (alt.startsWith(arg))
{
return alt.length() - arg.length();
}
else
{
return null;
}
}
// -------------------------------------------- //
// CONSTRUCT
// -------------------------------------------- //
public ARStringMatchStartCS(String typename, Collection<Collection<String>> altColls)
{
super(typename, altColls);
}
}

View File

@@ -0,0 +1,51 @@
package com.massivecraft.mcore5.cmd.arg;
import java.util.ArrayList;
import java.util.Collection;
import com.massivecraft.mcore5.cmd.MCommand;
import com.massivecraft.mcore5.usys.Multiverse;
import com.massivecraft.mcore5.util.Txt;
public class ARUniverse implements ArgReader<String>
{
// -------------------------------------------- //
// IMPLEMENTATION
// -------------------------------------------- //
@Override
public ArgResult<String> read(String str, MCommand mcommand)
{
ArgResult<String> result = new ArgResult<String>();
if (multiverse.containsUniverse(str))
{
result.setResult(str);
}
else
{
result.getErrors().add("<b>No universe \"<h>"+str+"<b>\" exists in multiverse <h>"+this.multiverse.getId()+"<b>.");
Collection<String> names = new ArrayList<String>(multiverse.getUniverses());
result.getErrors().add("<i>Use "+Txt.implodeCommaAndDot(names, "<h>%s", "<i>, ", " <i>or ", "<i>."));
}
return result;
}
// -------------------------------------------- //
// FIELDS
// -------------------------------------------- //
protected Multiverse multiverse;
public Multiverse multiverse() { return this.multiverse; }
// -------------------------------------------- //
// CONSTRUCT
// -------------------------------------------- //
public ARUniverse(Multiverse multiverse)
{
this.multiverse = multiverse;
}
}

View File

@@ -0,0 +1,43 @@
package com.massivecraft.mcore5.cmd.arg;
import java.util.ArrayList;
import java.util.List;
import org.bukkit.Bukkit;
import org.bukkit.World;
import com.massivecraft.mcore5.cmd.MCommand;
public class ARWorld extends ARAbstractSelect<World>
{
@Override
public String typename()
{
return "world";
}
@Override
public World select(String str, MCommand mcommand)
{
return Bukkit.getWorld(str);
}
@Override
public List<String> altNames(MCommand mcommand)
{
List<String> ret = new ArrayList<String>();
for (World world : Bukkit.getWorlds())
{
ret.add(world.getName());
}
return ret;
}
// -------------------------------------------- //
// INSTANCE
// -------------------------------------------- //
private static ARWorld i = new ARWorld();
public static ARWorld get() { return i; }
}

View File

@@ -0,0 +1,70 @@
package com.massivecraft.mcore5.cmd.arg;
import java.util.Collection;
import org.bukkit.WorldType;
import com.massivecraft.mcore5.cmd.MCommand;
import com.massivecraft.mcore5.util.MUtil;
public class ARWorldType extends ARAbstractSelect<WorldType>
{
@Override
public String typename()
{
return "world type";
}
@Override
public WorldType select(String str, MCommand mcommand)
{
WorldType ret = null;
// "DEFAULT_1_1" --> "11"
// "LARGE_BIOMES" --> "large"
// "Default" --> ""
str = str.toLowerCase();
str = str.replace("_", "");
str = str.replace(".", "");
str = str.replace("normal", "");
str = str.replace("default", "");
str = str.replace("large", "");
if (str.equals(""))
{
// "normal" or "default"
ret = WorldType.NORMAL;
}
else if (str.startsWith("flat"))
{
// "flat"
ret = WorldType.FLAT;
}
else if (str.contains("11"))
{
// "VERSION_1_1"
ret = WorldType.VERSION_1_1;
}
else if (str.contains("large"))
{
// "LARGE_BIOMES"
ret = WorldType.LARGE_BIOMES;
}
return ret;
}
@Override
public Collection<String> altNames(MCommand mcommand)
{
return MUtil.list("normal", "flat", "1.1", "largebiomes");
}
// -------------------------------------------- //
// INSTANCE
// -------------------------------------------- //
private static ARWorldType i = new ARWorldType();
public static ARWorldType get() { return i; }
}

View File

@@ -0,0 +1,8 @@
package com.massivecraft.mcore5.cmd.arg;
import com.massivecraft.mcore5.cmd.MCommand;
public interface ArgReader<T>
{
public ArgResult<T> read(String str, MCommand mcommand);
}

View File

@@ -0,0 +1,75 @@
package com.massivecraft.mcore5.cmd.arg;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import lombok.Getter;
import lombok.Setter;
public class ArgResult<T>
{
// -------------------------------------------- //
// FIELD: RESULT
// -------------------------------------------- //
@Getter @Setter protected T result = null;
public boolean hasResult()
{
return this.getResult() != null;
}
// -------------------------------------------- //
// FIELD: ERRORS
// -------------------------------------------- //
@Getter protected List<String> errors = new ArrayList<String>();
public void setErrors(List<String> val)
{
if (val == null)
{
this.errors = new ArrayList<String>();
}
else
{
this.errors = val;
}
}
public void setErrors(String... val)
{
this.setErrors(Arrays.asList(val));
}
public boolean hasErrors()
{
return this.errors.size() > 0;
}
// -------------------------------------------- //
// CONSTRUCT
// -------------------------------------------- //
public ArgResult()
{
}
public ArgResult(T result)
{
this.setResult(result);
}
public ArgResult(T result, List<String> errors)
{
this.setResult(result);
this.setErrors(errors);
}
public ArgResult(T result, String... errors)
{
this.setResult(result);
this.setErrors(errors);
}
}

View File

@@ -0,0 +1,14 @@
package com.massivecraft.mcore5.cmd.req;
import org.bukkit.command.CommandSender;
import com.massivecraft.mcore5.cmd.MCommand;
public interface IReq
{
// This just tests wether the requirement is met or not.
public boolean test(CommandSender sender, MCommand command);
// This just composes the error message and does NOT test the requirement at all.
public String createErrorMessage(CommandSender sender, MCommand command);
}

View File

@@ -0,0 +1,37 @@
package com.massivecraft.mcore5.cmd.req;
import lombok.Getter;
import lombok.Setter;
import org.bukkit.command.CommandSender;
import com.massivecraft.mcore5.cmd.MCommand;
import com.massivecraft.mcore5.util.Perm;
public class ReqHasPerm implements IReq
{
@Getter @Setter private String perm;
public ReqHasPerm(String perm)
{
this.perm = perm;
}
@Override
public boolean test(CommandSender sender, MCommand command)
{
return sender.hasPermission(this.perm);
}
@Override
public String createErrorMessage(CommandSender sender, MCommand command)
{
return Perm.getForbiddenMessage(this.perm);
}
public static ReqHasPerm get(String perm)
{
return new ReqHasPerm(perm);
}
}

View File

@@ -0,0 +1,33 @@
package com.massivecraft.mcore5.cmd.req;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import com.massivecraft.mcore5.Lang;
import com.massivecraft.mcore5.cmd.MCommand;
public class ReqIsPlayer implements IReq
{
@Override
public boolean test(CommandSender sender, MCommand command)
{
return sender instanceof Player;
}
@Override
public String createErrorMessage(CommandSender sender, MCommand command)
{
return Lang.commandSenderMustBePlayer;
}
protected static ReqIsPlayer instance= new ReqIsPlayer();
public static ReqIsPlayer getInstance()
{
return instance;
}
public static ReqIsPlayer get()
{
return instance;
}
}

View File

@@ -0,0 +1,51 @@
package com.massivecraft.mcore5.event;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.bukkit.event.player.PlayerRespawnEvent;
public class MCoreAfterPlayerRespawnEvent extends Event implements Runnable
{
// -------------------------------------------- //
// REQUIRED EVENT CODE
// -------------------------------------------- //
private static final HandlerList handlers = new HandlerList();
@Override public HandlerList getHandlers() { return handlers; }
public static HandlerList getHandlerList() { return handlers; }
// -------------------------------------------- //
// FIELD
// -------------------------------------------- //
@Getter protected final Location deathLocation;
@Getter protected final PlayerRespawnEvent bukkitEvent;
public Location getRespawnLocation() { return this.bukkitEvent.getRespawnLocation(); }
public Player getPlayer() { return this.bukkitEvent.getPlayer(); }
// -------------------------------------------- //
// CONSTRUCT
// -------------------------------------------- //
public MCoreAfterPlayerRespawnEvent(PlayerRespawnEvent bukkitEvent, Location deathLocation)
{
this.bukkitEvent = bukkitEvent;
this.deathLocation = deathLocation;
}
// -------------------------------------------- //
// HANDY RUN SHORTCUT
// -------------------------------------------- //
@Override
public void run()
{
Bukkit.getPluginManager().callEvent(this);
}
}

View File

@@ -0,0 +1,51 @@
package com.massivecraft.mcore5.event;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
public class MCoreAfterPlayerTeleportEvent extends Event implements Runnable
{
// -------------------------------------------- //
// REQUIRED EVENT CODE
// -------------------------------------------- //
private static final HandlerList handlers = new HandlerList();
@Override public HandlerList getHandlers() { return handlers; }
public static HandlerList getHandlerList() { return handlers; }
// -------------------------------------------- //
// FIELD
// -------------------------------------------- //
@Getter protected final PlayerTeleportEvent bukkitEvent;
public Location getFrom() { return this.bukkitEvent.getFrom(); }
public Location getTo() { return this.bukkitEvent.getTo(); }
public Player getPlayer() { return this.bukkitEvent.getPlayer(); }
public TeleportCause getCause() { return this.bukkitEvent.getCause(); }
// -------------------------------------------- //
// CONSTRUCT
// -------------------------------------------- //
public MCoreAfterPlayerTeleportEvent(PlayerTeleportEvent bukkitEvent)
{
this.bukkitEvent = bukkitEvent;
}
// -------------------------------------------- //
// HANDY RUN SHORTCUT
// -------------------------------------------- //
@Override
public void run()
{
Bukkit.getPluginManager().callEvent(this);
}
}

View File

@@ -0,0 +1,85 @@
package com.massivecraft.mcore5.event;
import java.util.HashMap;
import java.util.Map;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
/**
* The MCorePlayerLeaveEvent is a non-cancellable event.
* It is run at the MONITOR of either PlayerKickEvent or PlayerQuitEvent.
* It is also guaranteed to run before the MCore "store" module syncs
* all entities related to the player that is leaving the server.
*
* Use this even if you want to update a player entity as
* that player leaves. Automatic syncing will be guaranteed and the
* event will run pre disconnect if possible due to the internal usage if the PlayerKickedEvent.
*/
public class MCorePlayerLeaveEvent extends Event implements Runnable
{
// -------------------------------------------- //
// REQUIRED EVENT CODE
// -------------------------------------------- //
private static final HandlerList handlers = new HandlerList();
@Override public HandlerList getHandlers() { return handlers; }
public static HandlerList getHandlerList() { return handlers; }
// -------------------------------------------- //
// FIELD
// -------------------------------------------- //
@Getter protected final Player player;
@Getter protected final boolean preDisconnect;
public boolean isPostDisconnect() { return !this.isPreDisconnect(); }
@Getter protected final String caller;
public boolean isQuit() { return "quit".equals(caller); }
public boolean isKick() { return "kick".equals(caller); }
@Getter protected final String message;
// -------------------------------------------- //
// CONSTRUCT
// -------------------------------------------- //
public MCorePlayerLeaveEvent(Player player, boolean preDisconnect, String caller, String message)
{
this.player = player;
this.preDisconnect = preDisconnect;
this.caller = caller;
this.message = message;
}
// -------------------------------------------- //
// HANDY RUN SHORTCUT
// -------------------------------------------- //
@Override
public void run()
{
// Someone may already have issued a player leave event for this disconnect.
// We ignore that since we want one leave event called per disconnect only.
boolean doit = !player2event.containsKey(this.player.getName());
//MCore.p.log("MCorePlayerLeaveEvent", "caller:", caller, "doit:", doit, "player:", player.getDisplayName(), "preDisconnect:", preDisconnect, "message:", message);
if (doit)
{
//MCore.p.log("MCorePlayerLeaveEvent", caller, player.getDisplayName(), preDisconnect, message);
player2event.put(this.player.getName(), this);
Bukkit.getPluginManager().callEvent(this);
}
}
// -------------------------------------------- //
// STORING THE ACTIVE PLAYER EVENT
// -------------------------------------------- //
public static Map<String,MCorePlayerLeaveEvent> player2event = new HashMap<String,MCorePlayerLeaveEvent>();
}

View File

@@ -0,0 +1,108 @@
package com.massivecraft.mcore5.integration;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.server.PluginDisableEvent;
import org.bukkit.event.server.PluginEnableEvent;
import org.bukkit.plugin.Plugin;
import com.massivecraft.mcore5.MPlugin;
import com.massivecraft.mcore5.util.Txt;
public class Integration implements Listener
{
// -------------------------------------------- //
// FIELDS
// -------------------------------------------- //
protected MPlugin ourPlugin;
protected IntegrationFeatures features;
@Getter protected boolean active = false;
// -------------------------------------------- //
// CONSTRUCT
// -------------------------------------------- //
public Integration(MPlugin ourPlugin, IntegrationFeatures features)
{
this.ourPlugin = ourPlugin;
this.features = features;
Bukkit.getServer().getPluginManager().registerEvents(this, this.ourPlugin);
this.tick();
}
// -------------------------------------------- //
// LOGIC
// -------------------------------------------- //
public void tick()
{
if (pluginEnabled(this.features.getTargetPluginName()))
{
if (!this.active)
{
try
{
this.features.activate();
this.active = true;
this.ourPlugin.log(Txt.parse("<g>Activated <i>integration with <h>%s<i>.", this.features.getTargetPluginName()));
}
catch (Exception e)
{
this.ourPlugin.log(Txt.parse("<b>Failed to activate <i>integration with <h>%s<i>.", this.features.getTargetPluginName()));
e.printStackTrace();
}
}
}
else
{
if (this.active)
{
try
{
this.active = false;
this.features.deactivate();
this.ourPlugin.log(Txt.parse("Deactivated integration with <h>%s<i>.", this.features.getTargetPluginName()));
}
catch (Exception e)
{
this.ourPlugin.log(Txt.parse("<b>Failed to deactivate <i>integration with <h>%s<i>.", this.features.getTargetPluginName()));
e.printStackTrace();
}
}
}
}
// -------------------------------------------- //
// UTIL
// -------------------------------------------- //
public static boolean pluginEnabled(String pluginName)
{
Plugin plugin = Bukkit.getPluginManager().getPlugin(pluginName);
if (plugin == null) return false;
return plugin.isEnabled();
}
// -------------------------------------------- //
// EVENT LISTENERS
// -------------------------------------------- //
@EventHandler(priority = EventPriority.MONITOR)
public void onPluginDisable(PluginDisableEvent event)
{
this.tick();
}
@EventHandler(priority = EventPriority.MONITOR)
public void onPluginEnable(PluginEnableEvent event)
{
this.tick();
}
}

View File

@@ -0,0 +1,8 @@
package com.massivecraft.mcore5.integration;
public interface IntegrationFeatures
{
public String getTargetPluginName();
public void activate();
public void deactivate();
}

View File

@@ -0,0 +1,25 @@
package com.massivecraft.mcore5.integration;
public abstract class IntegrationFeaturesAbstract implements IntegrationFeatures
{
@Override
public String getTargetPluginName()
{
// "SpoutFeatures" --> "Spout"
String ret = this.getClass().getSimpleName();
ret = ret.substring(0, ret.length()-8);
return ret;
}
@Override
public void activate()
{
}
@Override
public void deactivate()
{
}
}

View File

@@ -0,0 +1,614 @@
package com.massivecraft.mcore5.store;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import com.massivecraft.mcore5.MCore;
import com.massivecraft.mcore5.MPlugin;
import com.massivecraft.mcore5.Predictate;
import com.massivecraft.mcore5.store.accessor.Accessor;
import com.massivecraft.mcore5.store.idstrategy.IdStrategy;
import com.massivecraft.mcore5.store.storeadapter.StoreAdapter;
public class Coll<E, L> implements CollInterface<E, L>
{
// -------------------------------------------- //
// GLOBAL REGISTRY
// -------------------------------------------- //
public static List<Coll<?, ?>> instances = new CopyOnWriteArrayList<Coll<?, ?>>();
// -------------------------------------------- //
// WHAT DO WE HANDLE?
// -------------------------------------------- //
protected final String name;
@Override public String getName() { return this.name; }
protected final String basename;
@Override public String getBasename() { return this.basename; }
protected final String universe;
@Override public String getUniverse() { return this.universe; }
protected final Class<E> entityClass;
@Override public Class<E> getEntityClass() { return this.entityClass; }
protected final Class<L> idClass;
@Override public Class<L> getIdClass() { return this.idClass; }
// -------------------------------------------- //
// SUPPORTING SYSTEM
// -------------------------------------------- //
protected MPlugin mplugin;
@Override public MPlugin getMplugin() { return this.mplugin; }
protected Db<?> db;
@Override public Db<?> getDb() { return this.db; }
@Override public Driver<?> getDriver() { return this.db.getDriver(); }
protected IdStrategy<L, ?> idStrategy;
@Override public IdStrategy<L, ?> getIdStrategy() { return this.idStrategy; }
protected StoreAdapter storeAdapter;
@Override public StoreAdapter getStoreAdapter() { return this.storeAdapter; }
protected Object collDriverObject;
@Override public Object getCollDriverObject() { return this.collDriverObject; }
// -------------------------------------------- //
// STORAGE
// -------------------------------------------- //
protected Set<L> ids = Collections.newSetFromMap(new ConcurrentHashMap<L, Boolean>());
@Override public Collection<L> getIds() { return Collections.unmodifiableCollection(this.ids); }
@Override public Collection<L> getIdsRemote() { return this.getDb().getDriver().getIds(this); }
@Override public boolean containsEntity(E entity) { return this.entities.contains(entity); };
@Override
public boolean containsId(Object oid)
{
L id = this.fixId(oid);
if (id == null) return false;
return this.ids.contains(id);
}
protected Set<E> entities = Collections.newSetFromMap(new ConcurrentHashMap<E, Boolean>());
@Override public Collection<E> getAll() { return Collections.unmodifiableCollection(this.entities); }
@Override public Collection<E> getAll(Predictate<E> where) { return MStoreUtil.uglySQL(this.getAll(), where, null, null, null); }
@Override public Collection<E> getAll(Predictate<E> where, Comparator<E> orderby) { return MStoreUtil.uglySQL(this.getAll(), where, orderby, null, null); }
@Override public Collection<E> getAll(Predictate<E> where, Comparator<E> orderby, Integer limit) { return MStoreUtil.uglySQL(this.getAll(), where, orderby, limit, null); }
@Override public Collection<E> getAll(Predictate<E> where, Comparator<E> orderby, Integer limit, Integer offset) { return MStoreUtil.uglySQL(this.getAll(), where, orderby, limit, offset); }
protected Map<L, E> id2entity = new ConcurrentHashMap<L, E>();
@Override public Map<L, E> getId2entity() { return Collections.unmodifiableMap(this.id2entity); }
@Override
public E get(Object oid)
{
return this.get(oid, this.isCreative());
}
@Override
public E get(Object oid, boolean creative)
{
return this.get(oid, creative, true);
}
protected E get(Object oid, boolean creative, boolean noteChange)
{
L id = this.fixId(oid);
if (id == null) return null;
E ret = this.id2entity.get(id);
if (ret != null) return ret;
if ( ! creative) return null;
return this.create(id, noteChange);
}
// Get the id for this entity.
protected Map<E, L> entity2id = new ConcurrentHashMap<E, L>();
@Override public Map<E, L> getEntity2id() { return Collections.unmodifiableMap(this.entity2id); }
@Override public L getId(E entity) { return this.entity2id.get(entity); }
@Override
public L fixId(Object oid)
{
if (oid == null) return null;
if (oid.getClass() == this.idClass) return this.idClass.cast(oid);
if (oid.getClass() == this.entityClass) return this.entity2id.get(oid);
return null;
}
// -------------------------------------------- //
// BAHAVIOR
// -------------------------------------------- //
protected boolean creative;
@Override public boolean isCreative() { return this.creative; }
@Override public void setCreative(boolean val) { this.creative = val; }
// Should that instance be saved or not?
// If it is default it should not be saved.
@Override public boolean isDefault(E entity) { return false; }
// -------------------------------------------- //
// COPY AND CREATE
// -------------------------------------------- //
@SuppressWarnings({ "rawtypes", "unchecked" })
public void copy(Object ofrom, Object oto)
{
if (ofrom instanceof Entity)
{
Entity efrom = (Entity)ofrom;
Entity eto = (Entity)oto;
eto.load(efrom);
}
else
{
Accessor.get(this.getEntityClass()).copy(ofrom, oto);
}
}
// This simply creates and returns a new instance
// It does not detach/attach or anything. Just creates a new instance.
@Override
public E createNewInstance()
{
try
{
return this.entityClass.newInstance();
}
catch (Exception e)
{
return null;
}
}
// Create new instance with automatic id
@Override
public E create()
{
return this.create(null);
}
// Create new instance with the requested id
@Override
public synchronized E create(Object oid)
{
return this.create(oid, true);
}
public synchronized E create(Object oid, boolean noteChange)
{
E entity = this.createNewInstance();
if (this.attach(entity, oid, noteChange) == null) return null;
return entity;
}
// -------------------------------------------- //
// ATTACH AND DETACH
// -------------------------------------------- //
@Override
public L attach(E entity)
{
return this.attach(entity, null);
}
@Override
public synchronized L attach(E entity, Object oid)
{
return this.attach(entity, oid, true);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
protected synchronized L attach(E entity, Object oid, boolean noteChange)
{
// Check entity
if (entity == null) return null;
L id = this.getId(entity);
if (id != null) return id;
// Check/Fix id
if (oid == null)
{
id = this.getIdStrategy().generate(this);
}
else
{
id = this.fixId(oid);
if (id == null) return null;
if (this.ids.contains(id)) return null;
}
// Attach
this.ids.add(id);
this.entities.add(entity);
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)
{
this.localAttachIds.add(id);
this.changedIds.add(id);
}
return id;
}
@SuppressWarnings("unchecked")
@Override
public synchronized E detach(Object o)
{
// What id is this?
L id = null;
if (this.idClass.isInstance(o))
{
id = (L)o;
}
else if (this.entityClass.isInstance(o))
{
id = this.entity2id.get(o);
}
else
{
id = this.fixId(o);
}
if (id == null)
{
return null;
}
// Remove @ local
E ret = this.removeAtLocal(id);
// Identify the change
this.localDetachIds.add(id);
this.changedIds.add(id);
return ret;
}
// -------------------------------------------- //
// IDENTIFIED CHANGES
// -------------------------------------------- //
protected Set<L> localAttachIds = Collections.newSetFromMap(new ConcurrentHashMap<L, Boolean>());
protected Set<L> localDetachIds = Collections.newSetFromMap(new ConcurrentHashMap<L, Boolean>());
protected Set<L> changedIds = Collections.newSetFromMap(new ConcurrentHashMap<L, Boolean>());
protected synchronized void clearIdentifiedChanges(L id)
{
this.localAttachIds.remove(id);
this.localDetachIds.remove(id);
this.changedIds.remove(id);
}
// -------------------------------------------- //
// SYNCLOG
// -------------------------------------------- //
protected Map<L, Long> lastMtime = new ConcurrentHashMap<L, Long>();
protected Map<L, Object> lastRaw = new ConcurrentHashMap<L, Object>();
protected Set<L> lastDefault = Collections.newSetFromMap(new ConcurrentHashMap<L, Boolean>());
protected synchronized void clearSynclog(L id)
{
this.lastMtime.remove(id);
this.lastRaw.remove(id);
this.lastDefault.remove(id);
}
// -------------------------------------------- //
// SYNC LOWLEVEL IO ACTIONS
// -------------------------------------------- //
@Override
public synchronized E removeAtLocal(L id)
{
this.clearIdentifiedChanges(id);
this.clearSynclog(id);
this.ids.remove(id);
E entity = this.id2entity.remove(id);
if (entity == null) return null;
this.entity2id.remove(entity);
this.entities.remove(entity);
return entity;
}
@Override
public synchronized void removeAtRemote(L id)
{
this.clearIdentifiedChanges(id);
this.clearSynclog(id);
this.getDb().getDriver().delete(this, id);
}
@Override
public synchronized void saveToRemote(L id)
{
this.clearIdentifiedChanges(id);
this.clearSynclog(id);
E entity = this.id2entity.get(id);
if (entity == null) return;
Object raw = this.getStoreAdapter().read(this, entity);
this.lastRaw.put(id, raw);
if (this.isDefault(entity))
{
this.db.getDriver().delete(this, id);
this.lastDefault.add(id);
}
else
{
Long mtime = this.db.getDriver().save(this, id, raw);
if (mtime == null) return; // This fail should not happen often. We could handle it better though.
this.lastMtime.put(id, mtime);
}
}
@Override
public synchronized void loadFromRemote(L id)
{
this.clearIdentifiedChanges(id);
Entry<?, Long> entry = this.getDb().getDriver().load(this, id);
if (entry == null) return;
Object raw = entry.getKey();
if (raw == null) return;
Long mtime = entry.getValue();
if (mtime == null) return;
E entity = this.get(id, true, false);
this.getStoreAdapter().write(this, raw, entity);
// Store adapter again since result of a database read may be "different" from entity read.
this.lastRaw.put(id, this.getStoreAdapter().read(this, entity));
this.lastMtime.put(id, mtime);
this.lastDefault.remove(id);
}
// -------------------------------------------- //
// SYNC DECIDE AND BASIC DO
// -------------------------------------------- //
@Override
public ModificationState examineId(L id)
{
return this.examineId(id, null, false);
}
@Override
public ModificationState examineId(L id, Long remoteMtime)
{
return this.examineId(id, remoteMtime, true);
}
protected ModificationState examineId(L id, Long remoteMtime, boolean remoteMtimeSupplied)
{
if (this.localDetachIds.contains(id)) return ModificationState.LOCAL_DETACH;
if (this.localAttachIds.contains(id)) return ModificationState.LOCAL_ATTACH;
E localEntity = this.id2entity.get(id);
if ( ! remoteMtimeSupplied)
{
remoteMtime = this.getDriver().getMtime(this, id);
}
boolean existsLocal = (localEntity != null);
boolean existsRemote = (remoteMtime != null);
if ( ! existsLocal && ! existsRemote) return ModificationState.UNKNOWN;
if (existsLocal && existsRemote)
{
Long lastMtime = this.lastMtime.get(id);
if (remoteMtime.equals(lastMtime) == false) return ModificationState.REMOTE_ALTER;
if (this.examineHasLocalAlter(id, localEntity)) return ModificationState.LOCAL_ALTER;
}
else if (existsLocal)
{
if (this.lastDefault.contains(id))
{
if (this.examineHasLocalAlter(id, localEntity)) return ModificationState.LOCAL_ALTER;
}
else
{
return ModificationState.REMOTE_DETACH;
}
}
else if (existsRemote)
{
return ModificationState.REMOTE_ATTACH;
}
return ModificationState.NONE;
}
protected boolean examineHasLocalAlter(L id, E entity)
{
Object lastRaw = this.lastRaw.get(id);
Object currentRaw = this.storeAdapter.read(this, entity);
return (currentRaw.equals(lastRaw) == false);
}
@Override
public ModificationState syncId(L id)
{
ModificationState mstate = this.examineId(id);
//mplugin.log("syncId: It seems", id, "has state", mstate);
switch (mstate)
{
case LOCAL_ALTER:
case LOCAL_ATTACH:
this.saveToRemote(id);
break;
case LOCAL_DETACH:
this.removeAtRemote(id);
break;
case REMOTE_ALTER:
case REMOTE_ATTACH:
this.loadFromRemote(id);
break;
case REMOTE_DETACH:
this.removeAtLocal(id);
break;
default:
this.clearIdentifiedChanges(id);
break;
}
return mstate;
}
@Override
public void syncSuspects()
{
for (L id : this.changedIds)
{
this.syncId(id);
}
}
@Override
public void syncAll()
{
// Find all ids
Set<L> allids = new HashSet<L>(this.ids);
allids.addAll(this.getDriver().getIds(this));
for (L id : allids)
{
this.syncId(id);
}
}
@Override
public void findSuspects()
{
// Get remote id and mtime snapshot
Map<L, Long> id2RemoteMtime = this.getDb().getDriver().getId2mtime(this);
// Compile a list of all ids (both remote and local)
Set<L> allids = new HashSet<L>();
allids.addAll(id2RemoteMtime.keySet());
allids.addAll(this.ids);
// Check for modifications
for (L id : allids)
{
Long remoteMtime = id2RemoteMtime.get(id);
ModificationState state = this.examineId(id, remoteMtime);
//mplugin.log("findSuspects: It seems", id, "has state", state);
if (state.isModified())
{
//System.out.println("It seems "+id+" has state "+state);
this.changedIds.add(id);
}
}
}
// -------------------------------------------- //
// SYNC RUNNABLES / SCHEDULING
// -------------------------------------------- //
protected Runnable tickTask;
@Override public Runnable getTickTask() { return this.tickTask; }
@Override
public void onTick()
{
this.syncSuspects();
}
protected ExamineThread<E, L> examineThread;
@Override public Thread examineThread() { return this.examineThread; }
// -------------------------------------------- //
// CONSTRUCT
// -------------------------------------------- //
public Coll(Db<?> db, MPlugin mplugin, String idStrategyName, String name, Class<E> entityClass, Class<L> idClass, boolean creative)
{
// Setup the name and the parsed parts
this.name = name;
String[] nameParts = this.name.split("\\@");
this.basename = nameParts[0];
if (nameParts.length > 1)
{
this.universe = nameParts[1];
}
else
{
this.universe = null;
}
this.entityClass = entityClass;
this.idClass = idClass;
this.creative = creative;
this.mplugin = mplugin;
this.db = db;
this.storeAdapter = this.db.getDriver().getStoreAdapter();
this.idStrategy = this.db.getDriver().getIdStrategy(idStrategyName);
if (this.idStrategy == null)
{
throw new IllegalArgumentException("UNKNOWN: The id stragegy \""+idStrategyName+"\" is unknown to the driver \""+db.getDriver().getName()+"\".");
}
else if (this.idStrategy.getLocalClass() != idClass)
{
throw new IllegalArgumentException("MISSMATCH: The id stragegy \""+idStrategyName+"\" for the driver \""+db.getDriver().getName()+"\" uses \""+this.idStrategy.getLocalClass().getSimpleName()+"\" but the collection "+this.name+"/"+this.getClass().getSimpleName()+" uses \""+idClass.getSimpleName()+"\".");
}
this.collDriverObject = db.getCollDriverObject(this);
final Coll<E, L> me = this;
this.tickTask = new Runnable()
{
@Override public void run() { me.onTick(); }
};
}
public Coll(MPlugin mplugin, String idStrategyName, String name, Class<E> entityClass, Class<L> idClass, boolean creative)
{
this(MCore.getDb(), mplugin, idStrategyName, name, entityClass, idClass, creative);
}
@Override
public void init()
{
if (this.inited()) return;
this.syncAll();
this.examineThread = new ExamineThread<E, L>(this);
this.examineThread.start();
instances.add(this);
}
@Override
public boolean inited()
{
return instances.contains(this);
}
}

View File

@@ -0,0 +1,149 @@
package com.massivecraft.mcore5.store;
import java.util.Collection;
import java.util.Comparator;
import java.util.Map;
import com.massivecraft.mcore5.MPlugin;
import com.massivecraft.mcore5.Predictate;
import com.massivecraft.mcore5.store.idstrategy.IdStrategy;
import com.massivecraft.mcore5.store.storeadapter.StoreAdapter;
public interface CollInterface<E, L>
{
// -------------------------------------------- //
// WHAT DO WE HANDLE?
// -------------------------------------------- //
public String getName();
public String getBasename();
public String getUniverse();
public Class<E> getEntityClass();
public Class<L> getIdClass();
// -------------------------------------------- //
// SUPPORTING SYSTEM
// -------------------------------------------- //
public MPlugin getMplugin();
public Db<?> getDb();
public Driver<?> getDriver();
public StoreAdapter getStoreAdapter();
public IdStrategy<L, ?> getIdStrategy();
public Object getCollDriverObject();
// -------------------------------------------- //
// STORAGE
// -------------------------------------------- //
public Collection<L> getIds();
public Collection<L> getIdsRemote();
public boolean containsId(Object oid);
public boolean containsEntity(E entity);
public Collection<E> getAll();
public Collection<E> getAll(Predictate<E> where);
public Collection<E> getAll(Predictate<E> where, Comparator<E> orderby);
public Collection<E> getAll(Predictate<E> where, Comparator<E> orderby, Integer limit);
public Collection<E> getAll(Predictate<E> where, Comparator<E> orderby, Integer limit, Integer offset);
public Map<L, E> getId2entity();
public E get(Object oid);
public E get(Object oid, boolean creative);
public Map<E, L> getEntity2id();
public L getId(E entity);
public L fixId(Object oid);
// -------------------------------------------- //
// BAHAVIOR
// -------------------------------------------- //
public boolean isCreative();
public void setCreative(boolean val);
// A default entity will not be saved.
// This is often used together with creative collections to save disc space.
public boolean isDefault(E entity);
// -------------------------------------------- //
// 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();
// Create new instance with automatic id
public E create();
// Create new instance with the requested id
public E create(Object oid);
// -------------------------------------------- //
// ATTACH AND DETACH
// -------------------------------------------- //
public L attach(E entity);
public L attach(E entity, Object oid);
public E detach(Object o);
// -------------------------------------------- //
// IDENTIFIED CHANGES
// -------------------------------------------- //
/*
public Set<L> localAttachIds();
public Set<L> localDetachIds();
public Set<L> changedIds();
public void clearIdentifiedChanges(L id);
*/
// -------------------------------------------- //
// SYNC LOG
// -------------------------------------------- //
/*
public Map<L, Long> lastMtime();
public Map<L, Object> lastRaw();
public Set<L> lastDefault();
public void clearSynclog(L id);
*/
// -------------------------------------------- //
// SYNC LOWLEVEL IO ACTIONS
// -------------------------------------------- //
public E removeAtLocal(L id);
public void removeAtRemote(L id);
public void saveToRemote(L id);
public void loadFromRemote(L id);
// -------------------------------------------- //
// SYNC EXAMINE AND DO
// -------------------------------------------- //
public ModificationState examineId(L id);
public ModificationState examineId(L id, Long remoteMtime);
public ModificationState syncId(L id);
public void syncSuspects();
public void syncAll();
public void findSuspects();
// -------------------------------------------- //
// SYNC RUNNABLES / SCHEDULING
// -------------------------------------------- //
// The tickTask simply runs the onTick method.
public Runnable getTickTask();
public void onTick();
public Thread examineThread();
// -------------------------------------------- //
// CONSTRUCT
// -------------------------------------------- //
public void init();
public boolean inited();
}

View File

@@ -0,0 +1,99 @@
package com.massivecraft.mcore5.store;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.massivecraft.mcore5.usys.Aspect;
import com.massivecraft.mcore5.usys.Multiverse;
import com.massivecraft.mcore5.util.MUtil;
public abstract class Colls<C extends Coll<E, L>, E, L>
{
protected Map<String, C> name2coll = new HashMap<String, C>();
public abstract Aspect getAspect();
public abstract String getBasename();
public abstract C createColl(String name);
// -------------------------------------------- //
// CONSTRUCT
// -------------------------------------------- //
public void init()
{
this.getColls();
}
public List<C> getColls()
{
List<C> ret = new ArrayList<C>();
Aspect a = this.getAspect();
Multiverse m = a.multiverse();
for (String universe : m.getUniverses())
{
ret.add(this.getForUniverse(universe));
}
return ret;
}
// -------------------------------------------- //
// UTIL
// -------------------------------------------- //
public String collnameForUniverse(String universe)
{
return this.getBasename() + "@" + universe;
}
public String universeFromWorldName(String worldName)
{
if (worldName == null) throw new IllegalArgumentException("worldName may not be null.");
return this.getAspect().multiverse().getUniverseForWorldName(worldName);
}
// -------------------------------------------- //
// GET
// -------------------------------------------- //
public C getForWorld(String worldName)
{
if (worldName == null) throw new IllegalArgumentException("worldName may not be null.");
return this.getForUniverse(this.universeFromWorldName(worldName));
}
public C getForUniverse(String universe)
{
if (universe == null) throw new IllegalArgumentException("universe may not be null.");
String collname = this.collnameForUniverse(universe);
return this.getForCollname(collname);
}
public C getForCollname(String collname)
{
C ret = this.name2coll.get(collname);
if (ret == null)
{
ret = this.createColl(collname);
ret.init();
this.name2coll.put(collname, ret);
}
return ret;
}
public C get(Object worldNameExtractable)
{
String worldName = MUtil.extract(String.class, "worldName", worldNameExtractable);
return this.getForWorld(worldName);
}
public E get2(Object worldNameExtractable)
{
C coll = this.get(worldNameExtractable);
if (coll == null) return null;
return coll.get(worldNameExtractable);
}
}

View File

@@ -0,0 +1,16 @@
package com.massivecraft.mcore5.store;
import java.util.Set;
public interface Db<R>
{
public String getName();
public boolean drop();
public Set<String> getCollnames();
public Driver<R> getDriver();
public Object getCollDriverObject(Coll<?, ?> coll);
}

View File

@@ -0,0 +1,12 @@
package com.massivecraft.mcore5.store;
import java.util.Set;
public abstract class DbAbstract<R> implements Db<R>
{
@Override
public Set<String> getCollnames()
{
return this.getDriver().getCollnames(this);
}
}

View File

@@ -0,0 +1,57 @@
package com.massivecraft.mcore5.store;
import java.io.File;
import com.massivecraft.mcore5.util.DiscUtil;
import com.massivecraft.mcore5.xlib.gson.JsonElement;
public class DbGson extends DbAbstract<JsonElement>
{
// -------------------------------------------- //
// FIELDS
// -------------------------------------------- //
public File dir;
protected DriverGson driver;
@Override public DriverGson getDriver() { return driver; }
// -------------------------------------------- //
// CONSTRUCTORS
// -------------------------------------------- //
public DbGson(DriverGson driver, File folder)
{
this.driver = driver;
this.dir = folder;
}
// -------------------------------------------- //
// IMPLEMENTATION
// -------------------------------------------- //
@Override
public String getName()
{
return dir.getAbsolutePath();
}
@Override
public boolean drop()
{
try
{
return DiscUtil.deleteRecursive(this.dir);
}
catch (Exception e)
{
return false;
}
}
@Override
public Object getCollDriverObject(Coll<?, ?> coll)
{
return new File(dir, coll.getName());
}
}

View File

@@ -0,0 +1,56 @@
package com.massivecraft.mcore5.store;
import com.massivecraft.mcore5.xlib.mongodb.BasicDBObject;
import com.massivecraft.mcore5.xlib.mongodb.DB;
public class DbMongo extends DbAbstract<BasicDBObject>
{
// -------------------------------------------- //
// FIELDS
// -------------------------------------------- //
public DB db;
protected DriverMongo driver;
@Override public DriverMongo getDriver() { return driver; }
// -------------------------------------------- //
// CONSTRUCTORS
// -------------------------------------------- //
public DbMongo(DriverMongo driver, DB db)
{
this.driver = driver;
this.db = db;
}
// -------------------------------------------- //
// IMPLEMENTATION
// -------------------------------------------- //
@Override
public String getName()
{
return db.getName();
}
@Override
public boolean drop()
{
try
{
this.db.dropDatabase();
return true;
}
catch (Exception e)
{
return false;
}
}
@Override
public Object getCollDriverObject(Coll<?, ?> coll)
{
return db.getCollection(coll.getName());
}
}

View File

@@ -0,0 +1,55 @@
package com.massivecraft.mcore5.store;
import java.util.Collection;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import com.massivecraft.mcore5.store.idstrategy.IdStrategy;
import com.massivecraft.mcore5.store.storeadapter.StoreAdapter;
public interface Driver<R>
{
// Returns the name of the driver.
public String getName();
// This is the rawdata format this driver works with.
// Could for example be JsonElement or DBObject
public Class<R> getRawdataClass();
// This is some sort of database specific id strategy with built in adapter
public boolean registerIdStrategy(IdStrategy<?, ?> idStrategy);
public <L> IdStrategy<L, ?> getIdStrategy(String idStrategyName);
// Get the default store adapter for the driver.
public StoreAdapter getStoreAdapter();
// Get a database instance from the driver
public Db<R> getDb(String uri);
// What collections are in the database?
public Set<String> getCollnames(Db<?> db);
// Is id X in the collection?
public <L> boolean containsId(Coll<?, L> coll, L id);
// When was X last altered?
public <L> Long getMtime(Coll<?, L> coll, L id);
// What ids are in the collection?
public <L> Collection<L> getIds(Coll<?, L> coll);
// Return a map of all ids with their corresponding mtimes
public <L> Map<L, Long> getId2mtime(Coll<?, L> coll);
// Load the raw data for X. The second part of the entry is the remote mtime at the load.
public <L> Entry<R, Long> load(Coll<?, L> coll, L id);
// Save raw data as X
// Return value is the new mtime (we caused the change).
// If the mtime is null something failed.
public <L> Long save(Coll<?, L> coll, L id, final Object rawData);
// Delete X
public <L> void delete(Coll<?, L> coll, L id);
}

View File

@@ -0,0 +1,34 @@
package com.massivecraft.mcore5.store;
import java.util.HashMap;
import java.util.Map;
import com.massivecraft.mcore5.store.idstrategy.IdStrategy;
public abstract class DriverAbstract<R> implements Driver<R>
{
public DriverAbstract(String name)
{
this.name = name;
}
protected String name;
@Override public String getName() { return this.name; }
protected Map<String, IdStrategy<?, ?>> idStrategies = new HashMap<String, IdStrategy<?, ?>>();
@Override
public boolean registerIdStrategy(IdStrategy<?, ?> idStrategy)
{
if (idStrategies.containsKey(idStrategy.getName())) return false;
idStrategies.put(idStrategy.getName(), idStrategy);
return true;
}
@SuppressWarnings("unchecked")
@Override
public <L> IdStrategy<L, ?> getIdStrategy(String idStrategyName)
{
IdStrategy<?, ?> idStrategy = idStrategies.get(idStrategyName);
return (IdStrategy<L, ?>) idStrategy;
}
}

View File

@@ -0,0 +1,196 @@
package com.massivecraft.mcore5.store;
import java.io.File;
import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import com.massivecraft.mcore5.store.idstrategy.IdStrategyAiGson;
import com.massivecraft.mcore5.store.idstrategy.IdStrategyOidGson;
import com.massivecraft.mcore5.store.idstrategy.IdStrategyUuidMongoAndGson;
import com.massivecraft.mcore5.store.storeadapter.StoreAdapter;
import com.massivecraft.mcore5.store.storeadapter.StoreAdapterGson;
import com.massivecraft.mcore5.util.DiscUtil;
import com.massivecraft.mcore5.xlib.gson.JsonElement;
import com.massivecraft.mcore5.xlib.gson.JsonParser;
public class DriverGson extends DriverAbstract<JsonElement>
{
protected final static String DOTJSON = ".json";
// -------------------------------------------- //
// IMPLEMENTATION
// -------------------------------------------- //
@Override public Class<JsonElement> getRawdataClass() { return JsonElement.class; }
@Override
public StoreAdapter getStoreAdapter()
{
return StoreAdapterGson.get();
}
@Override
public Db<JsonElement> getDb(String uri)
{
// "gson://" is 7 chars
File folder = new File(uri.substring(7));
folder.mkdirs();
return new DbGson(this, folder);
}
@Override
public Set<String> getCollnames(Db<?> db)
{
Set<String> ret = new LinkedHashSet<String>();
for (File f : ((DbGson)db).dir.listFiles())
{
if ( ! f.isDirectory()) continue;
ret.add(f.getName());
}
return ret;
}
@Override
public <L> boolean containsId(Coll<?, L> coll, L id)
{
return fileFromId(coll, id).isFile();
}
@Override
public <L> Long getMtime(Coll<?, L> coll, L id)
{
File file = fileFromId(coll, id);
if ( ! file.isFile()) return null;
return file.lastModified();
}
@Override
public <L> Collection<L> getIds(Coll<?, L> coll)
{
List<L> ret = new ArrayList<L>();
// Scan the collection folder for .json files
File collDir = getCollDir(coll);
if ( ! collDir.isDirectory()) return ret;
for(File file : collDir.listFiles(JsonFileFilter.get()))
{
// Then convert them to what they should be
String remoteId = idFromFile(file);
L localId = coll.getIdStrategy().remoteToLocal(remoteId);
ret.add(localId);
}
return ret;
}
@Override
public <L> Map<L, Long> getId2mtime(Coll<?, L> coll)
{
Map<L, Long> ret = new HashMap<L, Long>();
// Scan the collection folder for .json files
File collDir = getCollDir(coll);
if ( ! collDir.isDirectory()) return ret;
for(File file : collDir.listFiles(JsonFileFilter.get()))
{
// Then convert them to what they should be
String remoteId = idFromFile(file);
L localId = coll.getIdStrategy().remoteToLocal(remoteId);
ret.put(localId, file.lastModified());
}
return ret;
}
@Override
public <L> Entry<JsonElement, Long> load(Coll<?, L> coll, L id)
{
File file = fileFromId(coll, id);
Long mtime = file.lastModified();
if (mtime == 0) return null;
String content = DiscUtil.readCatch(file);
if (content == null) return null;
if (content.length() == 0) return null;
JsonElement raw = new JsonParser().parse(content);
return new SimpleEntry<JsonElement, Long>(raw, mtime);
}
@Override
public <L> Long save(Coll<?, L> coll, L id, Object rawData)
{
File file = fileFromId(coll, id);
String content = coll.getMplugin().gson.toJson((JsonElement)rawData);
if (DiscUtil.writeCatch(file, content) == false) return null;
return file.lastModified();
}
@Override
public <L> void delete(Coll<?, L> coll, L id)
{
File file = fileFromId(coll, id);
file.delete();
}
// -------------------------------------------- //
// UTIL
// -------------------------------------------- //
protected static File getCollDir(Coll<?, ?> coll)
{
return (File) coll.getCollDriverObject();
}
protected static String idFromFile(File file)
{
if (file == null) return null;
String name = file.getName();
return name.substring(0, name.length()-5);
}
protected static <L> File fileFromId(Coll<?, L> coll, L id)
{
File collDir = getCollDir(coll);
String idString = (String)coll.getIdStrategy().localToRemote(id);
File idFile = new File(collDir, idString+DOTJSON);
return idFile;
}
//----------------------------------------------//
// CONSTRUCTORS
//----------------------------------------------//
public static String NAME = "gson";
private DriverGson()
{
super(NAME);
}
// -------------------------------------------- //
// INSTANCE
// -------------------------------------------- //
protected static DriverGson instance;
public static DriverGson get()
{
return instance;
}
static
{
instance = new DriverGson();
instance.registerIdStrategy(IdStrategyAiGson.get());
instance.registerIdStrategy(IdStrategyOidGson.get());
instance.registerIdStrategy(IdStrategyUuidMongoAndGson.get());
}
}

View File

@@ -0,0 +1,228 @@
package com.massivecraft.mcore5.store;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.AbstractMap.SimpleEntry;
import java.util.Map.Entry;
import com.massivecraft.mcore5.store.idstrategy.IdStrategyAiMongo;
import com.massivecraft.mcore5.store.idstrategy.IdStrategyOidMongo;
import com.massivecraft.mcore5.store.idstrategy.IdStrategyUuidMongoAndGson;
import com.massivecraft.mcore5.store.storeadapter.StoreAdapter;
import com.massivecraft.mcore5.store.storeadapter.StoreAdapterMongo;
import com.massivecraft.mcore5.xlib.mongodb.BasicDBObject;
import com.massivecraft.mcore5.xlib.mongodb.DB;
import com.massivecraft.mcore5.xlib.mongodb.DBCollection;
import com.massivecraft.mcore5.xlib.mongodb.DBCursor;
import com.massivecraft.mcore5.xlib.mongodb.MongoURI;
public class DriverMongo extends DriverAbstract<BasicDBObject>
{
// -------------------------------------------- //
// STATIC
// -------------------------------------------- //
public final static String ID_FIELD = "_id";
public final static String MTIME_FIELD = "_mtime";
public final static BasicDBObject dboEmpty = new BasicDBObject();
public final static BasicDBObject dboKeysId = new BasicDBObject().append(ID_FIELD, 1);
public final static BasicDBObject dboKeysMtime = new BasicDBObject().append(MTIME_FIELD, 1);
public final static BasicDBObject dboKeysIdandMtime = new BasicDBObject().append(ID_FIELD, 1).append(MTIME_FIELD, 1);
// -------------------------------------------- //
// IMPLEMENTATION
// -------------------------------------------- //
@Override public Class<BasicDBObject> getRawdataClass() { return BasicDBObject.class; }
@Override
public StoreAdapter getStoreAdapter()
{
return StoreAdapterMongo.get();
}
@Override
public Db<BasicDBObject> getDb(String uri)
{
DB db = this.getDbInner(uri);
return new DbMongo(this, db);
}
@Override
public Set<String> getCollnames(Db<?> db)
{
return ((DbMongo)db).db.getCollectionNames();
}
@Override
public <L> boolean containsId(Coll<?, L> coll, L id)
{
DBCollection dbcoll = fixColl(coll);
DBCursor cursor = dbcoll.find(new BasicDBObject(ID_FIELD, coll.getIdStrategy().localToRemote(id)));
return cursor.count() != 0;
}
@Override
public <L> Long getMtime(Coll<?, L> coll, L id)
{
DBCollection dbcoll = fixColl(coll);
BasicDBObject found = (BasicDBObject)dbcoll.findOne(new BasicDBObject(ID_FIELD, coll.getIdStrategy().localToRemote(id)), dboKeysMtime);
if (found == null) return null;
if ( ! found.containsField(MTIME_FIELD)) return null; // This should not happen! But better to ignore than crash?
return found.getLong(MTIME_FIELD);
}
@Override
public <L> Collection<L> getIds(Coll<?, L> coll)
{
List<L> ret = null;
DBCollection dbcoll = fixColl(coll);
DBCursor cursor = dbcoll.find(dboEmpty, dboKeysId);
try
{
ret = new ArrayList<L>(cursor.count());
while(cursor.hasNext())
{
Object remoteId = cursor.next().get(ID_FIELD);
L localId = coll.getIdStrategy().remoteToLocal(remoteId);
ret.add(localId);
}
}
finally
{
cursor.close();
}
return ret;
}
@Override
public <L> Map<L, Long> getId2mtime(Coll<?, L> coll)
{
Map<L, Long> ret = null;
DBCollection dbcoll = fixColl(coll);
DBCursor cursor = dbcoll.find(dboEmpty, dboKeysIdandMtime);
try
{
ret = new HashMap<L, Long>(cursor.count());
while(cursor.hasNext())
{
BasicDBObject raw = (BasicDBObject)cursor.next();
Object remoteId = raw.get(ID_FIELD);
L localId = coll.getIdStrategy().remoteToLocal(remoteId);
if ( ! raw.containsField(MTIME_FIELD)) continue; // This should not happen! But better to ignore than crash?
Long mtime = raw.getLong(MTIME_FIELD);
ret.put(localId, mtime);
}
}
finally
{
cursor.close();
}
return ret;
}
@Override
public <L> Entry<BasicDBObject, Long> load(Coll<?, L> coll, L id)
{
DBCollection dbcoll = fixColl(coll);
BasicDBObject raw = (BasicDBObject)dbcoll.findOne(new BasicDBObject(ID_FIELD, coll.getIdStrategy().localToRemote(id)));
if (raw == null) return null;
Long mtime = (Long) raw.removeField(MTIME_FIELD);
return new SimpleEntry<BasicDBObject, Long>(raw, mtime);
}
@Override
public <L> Long save(Coll<?, L> coll, L id, Object rawData)
{
DBCollection dbcoll = fixColl(coll);
// We shallow copy here in order to stop the extra "_mtime" field from messing up the lastRaw.
BasicDBObject data = (BasicDBObject)rawData;
data = (BasicDBObject)data.clone();
Long mtime = System.currentTimeMillis();
data.put(MTIME_FIELD, mtime);
Object remoteId = coll.getIdStrategy().localToRemote(id);
dbcoll.update(new BasicDBObject(ID_FIELD, remoteId), data, true, false);
return mtime;
}
@Override
public <L> void delete(Coll<?, L> coll, L id)
{
fixColl(coll).remove(new BasicDBObject(ID_FIELD, coll.getIdStrategy().localToRemote(id)));
}
//----------------------------------------------//
// UTIL
//----------------------------------------------//
protected static DBCollection fixColl(Coll<?, ?> coll)
{
return (DBCollection) coll.getCollDriverObject();
}
protected DB getDbInner(String uri)
{
MongoURI muri = new MongoURI(uri);
try
{
DB db = muri.connectDB();
if (muri.getUsername() == null) return db;
if ( ! db.authenticate(muri.getUsername(), muri.getPassword()))
{
//log(Level.SEVERE, "... db authentication failed.");
return null;
}
return db;
}
catch (Exception e)
{
//log(Level.SEVERE, "... mongo connection failed.");
e.printStackTrace();
return null;
}
}
//----------------------------------------------//
// CONSTRUCTORS
//----------------------------------------------//
private DriverMongo()
{
super("mongodb");
}
// -------------------------------------------- //
// INSTANCE
// -------------------------------------------- //
protected static DriverMongo instance;
public static DriverMongo get()
{
return instance;
}
static
{
instance = new DriverMongo();
instance.registerIdStrategy(IdStrategyAiMongo.get());
instance.registerIdStrategy(IdStrategyOidMongo.get());
instance.registerIdStrategy(IdStrategyUuidMongoAndGson.get());
}
}

View File

@@ -0,0 +1,119 @@
package com.massivecraft.mcore5.store;
import com.massivecraft.mcore5.MCore;
import com.massivecraft.mcore5.store.accessor.Accessor;
import com.massivecraft.mcore5.xlib.gson.Gson;
/**
* Usage of this class is highly optional. You may persist anything. If you are
* creating the class to be persisted yourself, it might be handy to extend this
* Entity class. It just contains a set of shortcut methods.
*/
// Self referencing generic using the "getThis trick".
// http://www.angelikalanger.com/GenericsFAQ/FAQSections/ProgrammingIdioms.html#FAQ206
public abstract class Entity<E extends Entity<E, L>, L>
{
protected transient Coll<E, L> coll;
protected void setColl(Coll<E, L> val) { this.coll = val; }
public Coll<E, L> getColl() { return this.coll; }
protected abstract E getThis();
protected abstract Class<E> getClazz();
public abstract E getDefaultInstance();
public String getUniverse()
{
Coll<E, L> coll = this.getColl();
if (coll == null) return null;
return coll.getUniverse();
}
public L attach(Coll<E, L> coll)
{
return coll.attach(getThis());
}
public E detach()
{
Coll<E, L> coll = this.getColl();
if (coll == null) return null;
return coll.detach(getThis());
}
public boolean attached()
{
Coll<E, L> coll = this.getColl();
if (coll == null) return false;
return coll.getAll().contains(getThis());
}
public boolean detached()
{
return ! this.attached();
}
public L getId()
{
Coll<E, L> coll = this.getColl();
if (coll == null) return null;
return coll.getId(this.getThis());
}
public void changed()
{
L id = this.getId();
if (id == null) return;
this.getColl().changedIds.add(id);
}
public ModificationState sync()
{
L id = this.getId();
if (id == null) return ModificationState.UNKNOWN;
return this.getColl().syncId(id);
}
public void saveToRemote()
{
L id = this.getId();
if (id == null) return;
this.getColl().saveToRemote(id);
}
public void loadFromRemote()
{
L id = this.getId();
if (id == null) return;
this.getColl().loadFromRemote(id);
}
@Override
public String toString()
{
Gson gson = MCore.gson;
Coll<E, L> coll = this.getColl();
if (coll != null) gson = coll.getMplugin().gson;
return this.getClazz().getSimpleName()+gson.toJson(this, this.getClazz());
}
public E loadDefaults()
{
Accessor.get(this.getClazz()).copy(this.getDefaultInstance(), this.getThis());
return this.getThis();
}
public E load(E that)
{
Accessor.get(this.getClazz()).copy(that, this.getThis());
return this.getThis();
}
}

View File

@@ -0,0 +1,43 @@
package com.massivecraft.mcore5.store;
public class ExamineThread<E, L> extends Thread
{
protected Coll<E, L> coll;
public ExamineThread(Coll<E, L> coll)
{
this.coll = coll;
this.setName("ExamineThread for "+coll.getName());
}
// TODO: Implement logging and/or auto adjusting system for how long the sleep should be?
@Override
public void run()
{
while(true)
{
try
{
//long before = System.currentTimeMillis();
coll.findSuspects();
//long after = System.currentTimeMillis();
//coll.mplugin().log(this.getName()+ " complete. Took "+ (after-before) +"ms.");
Thread.sleep(5000);
}
catch (InterruptedException e)
{
// We've been interrupted. Lets bail.
return;
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
}

View File

@@ -0,0 +1,23 @@
package com.massivecraft.mcore5.store;
import java.io.File;
import java.io.FileFilter;
public class JsonFileFilter implements FileFilter
{
private final static String DOTJSON = ".json";
@Override
public boolean accept(File pathname)
{
return pathname.getName().toLowerCase().endsWith(DOTJSON);
}
// -------------------------------------------- //
// INSTANCE
// -------------------------------------------- //
private static JsonFileFilter instance = new JsonFileFilter();
public static JsonFileFilter get() { return instance; }
}

View File

@@ -0,0 +1,53 @@
package com.massivecraft.mcore5.store;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;
import com.massivecraft.mcore5.MCore;
public class MStore
{
protected static Map<String, Driver<?>> drivers = new HashMap<String, Driver<?>>();
public static boolean registerDriver(Driver<?> driver)
{
if (drivers.containsKey(driver.getName())) return false;
drivers.put(driver.getName(), driver);
return true;
}
public static Driver<?> getDriver(String id)
{
return drivers.get(id);
}
public static Db<?> getDb(String uri)
{
try
{
if (uri.equalsIgnoreCase("default")) return MCore.getDb();
return getDb(new URI(uri));
}
catch (URISyntaxException e)
{
e.printStackTrace();
return null;
}
}
public static Db<?> getDb(URI uri)
{
String scheme = uri.getScheme();
Driver<?> driver = getDriver(scheme);
if (driver == null) return null;
return driver.getDb(uri.toString());
}
static
{
registerDriver(DriverMongo.get());
registerDriver(DriverGson.get());
}
}

View File

@@ -0,0 +1,75 @@
package com.massivecraft.mcore5.store;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import com.massivecraft.mcore5.Predictate;
public class MStoreUtil
{
public static <T> ArrayList<T> uglySQL(Collection<T> items, Predictate<T> where, Comparator<T> orderby, Integer limit, Integer offset)
{
ArrayList<T> ret = new ArrayList<T>(items.size());
// WHERE
if (where == null)
{
ret.addAll(items);
}
else
{
for (T item : items)
{
if (where.apply(item))
{
ret.add(item);
}
}
}
// ORDERBY
if (orderby != null)
{
Collections.sort(ret, orderby);
}
// LIMIT AND OFFSET
// Parse args
int fromIndex = 0;
if (offset != null)
{
fromIndex = offset;
}
int toIndex = ret.size()-1;
if (limit != null)
{
toIndex = offset+limit;
}
// Clean args
if (fromIndex <= 0)
{
fromIndex = 0;
}
else if (fromIndex > ret.size()-1)
{
fromIndex = ret.size()-1;
}
if (toIndex < fromIndex)
{
toIndex = fromIndex;
}
else if (toIndex > ret.size()-1)
{
toIndex = ret.size()-1;
}
// No limit?
if (fromIndex == 0 && toIndex == ret.size()-1) return ret;
return new ArrayList<T>(ret.subList(fromIndex, toIndex));
}
}

View File

@@ -0,0 +1,28 @@
package com.massivecraft.mcore5.store;
public enum ModificationState
{
LOCAL_ALTER (true, true),
LOCAL_ATTACH (true, true),
LOCAL_DETACH (true, true),
REMOTE_ALTER (true, false),
REMOTE_ATTACH (true, false),
REMOTE_DETACH (true, false),
NONE (false, false),
UNKNOWN (false, false),
;
private final boolean modified;
public boolean isModified() { return this.modified; }
private final boolean local;
public boolean isLocal() { return this.local; }
public boolean isRemote() { return this.local == false; }
private ModificationState(boolean modified, boolean local)
{
this.modified = modified;
this.local = local;
}
}

View File

@@ -0,0 +1,133 @@
package com.massivecraft.mcore5.store;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import com.massivecraft.mcore5.MCore;
import com.massivecraft.mcore5.MPlugin;
import com.massivecraft.mcore5.Predictate;
import com.massivecraft.mcore5.cmd.arg.ARStringEntity;
import com.massivecraft.mcore5.cmd.arg.ARStringMatchFullCI;
import com.massivecraft.mcore5.cmd.arg.ARStringMatchStartCI;
import com.massivecraft.mcore5.cmd.arg.ArgReader;
import com.massivecraft.mcore5.util.MUtil;
import com.massivecraft.mcore5.util.PlayerUtil;
public class PlayerColl<E extends PlayerEntity<E>> extends Coll<E, String>
{
// -------------------------------------------- //
// FIELDS
// -------------------------------------------- //
// Note that the lowercasing should be kept at either true or false.
protected boolean lowercasing = false;
public boolean isLowercasing() { return this.lowercasing; }
// -------------------------------------------- //
// CONSTRUCT
// -------------------------------------------- //
public PlayerColl(Db<?> db, MPlugin mplugin, String name, Class<E> entityClass, boolean creative, boolean lowercasing)
{
super(db, mplugin, "ai", name, entityClass, String.class, creative);
this.lowercasing = lowercasing;
}
public PlayerColl(Db<?> db, MPlugin mplugin, String name, Class<E> entityClass, boolean creative)
{
this(db, mplugin, name, entityClass, creative, false);
}
public PlayerColl(Db<?> db, MPlugin mplugin, String name, Class<E> entityClass)
{
this(db, mplugin, name, entityClass, true);
}
public PlayerColl(MPlugin mplugin, String name, Class<E> entityClass, boolean creative, boolean lowercasing)
{
this(MCore.getDb(), mplugin, name, entityClass, creative, lowercasing);
}
public PlayerColl(MPlugin mplugin, String name, Class<E> entityClass, boolean creative)
{
this(MCore.getDb(), mplugin, name, entityClass, creative);
}
public PlayerColl(MPlugin mplugin, String name, Class<E> entityClass)
{
this(MCore.getDb(), mplugin, name, entityClass);
}
// -------------------------------------------- //
// EXTRAS
// -------------------------------------------- //
@Override
public String fixId(Object oid)
{
if (oid == null) return null;
String ret = MUtil.extract(String.class, "playerName", oid);
if (ret == null) return ret;
return this.lowercasing ? ret.toLowerCase() : ret;
}
public Collection<E> getAllOnline()
{
List<E> ret = new ArrayList<E>();
for(Player player : Bukkit.getOnlinePlayers())
{
E entity = this.get(player.getName());
if (entity == null) continue;
ret.add(entity);
}
return ret;
}
public Collection<E> getAllOffline()
{
return this.getAll(new Predictate<E>()
{
public boolean apply(E entity)
{
return entity.isOffline();
}
});
}
// -------------------------------------------- //
// ARGUMENT READERS
// -------------------------------------------- //
protected Collection<Collection<String>> forgeAltColls()
{
Collection<Collection<String>> ret = new ArrayList<Collection<String>>();
ret.add(this.getIds());
if (this.isCreative()) ret.add(PlayerUtil.getAllVisitorNames());
return ret;
}
public ArgReader<String> argReaderPlayerNameFull()
{
return new ARStringMatchFullCI("player", this.forgeAltColls());
}
public ArgReader<String> argReaderPlayerNameStart()
{
return new ARStringMatchStartCI("player", this.forgeAltColls());
}
public ArgReader<E> argReaderPlayerFull()
{
return new ARStringEntity<E>(this.argReaderPlayerNameFull(), this);
}
public ArgReader<E> argReaderPlayerStart()
{
return new ARStringEntity<E>(this.argReaderPlayerNameStart(), this);
}
}

View File

@@ -0,0 +1,123 @@
package com.massivecraft.mcore5.store;
import java.util.Collection;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.entity.Player;
import com.massivecraft.mcore5.util.PlayerUtil;
import com.massivecraft.mcore5.util.Txt;
public abstract class PlayerEntity<E extends PlayerEntity<E>> extends Entity<E, String>
{
public Player getPlayer()
{
if (this.getColl() == null) return null;
if (this.getColl().isLowercasing())
{
return Bukkit.getPlayerExact(this.getId());
}
else
{
return PlayerUtil.getPlayerExact(this.getId());
}
}
@Override
public PlayerColl<E> getColl()
{
return (PlayerColl<E>) super.getColl();
}
public boolean isOnline()
{
return this.getPlayer() != null;
}
public boolean isOffline()
{
return ! isOnline();
}
/*public String getCurrentUniverse()
{
Player player = this.getPlayer();
if (player == null) return null;
String aspectId = this.getColl().nameAspect();
Aspect aspect = Aspect.get(aspectId);
aspect.
return USelColl.i.get(aspect).select(player.getWorld().getName());
vi ska returna ett universeId
}
public boolean isInThisUniverse()
{
String universe = this.getUniverse();
if (universe == null) return false;
String currentUniverse = this.getCurrentUniverse();
if (currentUniverse == null) return false;
return universe.equals(currentUniverse);
}*/
// -------------------------------------------- //
// CHECKER UTILS
// -------------------------------------------- //
public boolean isGameMode(GameMode gm, boolean defaultIfOffline)
{
Player player = this.getPlayer();
if (player == null || ! player.isOnline()) return defaultIfOffline;
return player.getGameMode() == gm;
}
// -------------------------------------------- //
// Message Sending Helpers
// -------------------------------------------- //
public void sendMessage(String msg)
{
Player player = this.getPlayer();
if (player == null) return;
player.sendMessage(msg);
}
public void sendMessage(Collection<String> msgs)
{
Player player = this.getPlayer();
if (player == null) return;
for(String msg : msgs)
{
player.sendMessage(msg);
}
}
public void msg(String msg)
{
this.sendMessage(Txt.parse(msg));
}
public void msg(String msg, Object... args)
{
this.sendMessage(Txt.parse(msg, args));
}
public void msg(Collection<String> msgs)
{
Player player = this.getPlayer();
if (player == null) return;
for(String msg : msgs)
{
player.sendMessage(Txt.parse(msg));
}
}
}

View File

@@ -0,0 +1,20 @@
package com.massivecraft.mcore5.store.accessor;
import java.util.HashMap;
import java.util.Map;
public final class Accessor
{
private static Map<Class<?>, EntityAccessor> class2EntityAccessor = new HashMap<Class<?>, EntityAccessor>();
public static EntityAccessor get(Class<?> clazz)
{
EntityAccessor ret = class2EntityAccessor.get(clazz);
if (ret == null)
{
ret = new EntityAccessorPerProperty(clazz);
class2EntityAccessor.put(clazz, ret);
}
return ret;
}
}

View File

@@ -0,0 +1,175 @@
package com.massivecraft.mcore5.store.accessor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class AccessorUtil
{
//----------------------------------------------//
// MAKE ACCESSIBLE
//----------------------------------------------//
public static void makeAccessible(Field field)
{
if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers()) || Modifier.isFinal(field.getModifiers())) && !field.isAccessible())
{
field.setAccessible(true);
}
}
public static void makeAccessible(Method method)
{
if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers())) && !method.isAccessible())
{
method.setAccessible(true);
}
}
//----------------------------------------------//
// FIND
//----------------------------------------------//
public static List<Method> findMethod(Class<?> clazz, String name)
{
List<Method> ret = new ArrayList<Method>();
for (Class<?> c = clazz; c != null; c = c.getSuperclass())
{
Method[] methods = (c.isInterface() ? c.getMethods() : c.getDeclaredMethods());
for (Method method : methods)
{
if (name.equals(method.getName())) ret.add(method);
}
}
return ret;
}
public static Field findField(Class<?> clazz, String name)
{
for (Class<?> c = clazz; c != null && !Object.class.equals(c); c = c.getSuperclass())
{
Field[] fields = c.getDeclaredFields();
for (Field field : fields)
{
if (name.equals(field.getName())) return field;
}
}
return null;
}
public static List<Field> findAllFields(Class<?> clazz)
{
List<Field> fields = new ArrayList<Field>();
for (Class<?> c = clazz; c != null; c = c.getSuperclass())
{
fields.addAll(Arrays.asList(c.getDeclaredFields()));
}
return fields;
}
/**
* Must be non-transient.
* Must be non-final.
* Will be set accessible if possible.
*/
public static Map<String, Field> getFieldMap(Class<?> clazz)
{
Map<String, Field> ret = new HashMap<String, Field>();
for (Field field : findAllFields(clazz))
{
if (Modifier.isTransient(field.getModifiers())) continue;
if (Modifier.isFinal(field.getModifiers())) continue;
makeAccessible(field);
ret.put(field.getName(), field);
}
return ret;
}
//----------------------------------------------//
// FIND GETTERS AND SETTERS
//----------------------------------------------//
public static String ucfirst(String str)
{
return Character.toUpperCase(str.charAt(0))+str.substring(1);
}
public static String calcGetterNameBool(String fieldName) { return "is"+ucfirst(fieldName); }
public static String calcGetterName(String fieldName) { return "get"+ucfirst(fieldName); }
public static String calcSetterName(String fieldName) { return "set"+ucfirst(fieldName); }
// TODO: Use a predictate?
public static Method findGetter(Class<?> clazz, String fieldName)
{
for (Method method : findMethod(clazz, calcGetterName(fieldName)))
{
if (method.getParameterTypes().length == 0 && method.getReturnType() != null) return method;
}
for (Method method : findMethod(clazz, calcGetterNameBool(fieldName)))
{
if (method.getParameterTypes().length == 0 && method.getReturnType() == Boolean.class) return method;
}
return null;
}
public static Method findSetter(Class<?> clazz, String fieldName)
{
List<Method> methods = findMethod(clazz, calcSetterName(fieldName));
methods.addAll(findMethod(clazz, fieldName));
for (Method method : methods)
{
if (method != null && method.getParameterTypes().length == 1) return method;
}
return null;
}
//----------------------------------------------//
// CREATE PROPERTY ACCESS
//----------------------------------------------//
public static PropertyGetter createPropertyGetter(Class<?> clazz, String name)
{
Method method = findGetter(clazz, name);
if (method != null) return new PropertyGetterMethodReflection(method);
Field field = findField(clazz, name);
if (field != null) return new PropertyGetterFieldReflection(field);
return null;
}
public static PropertySetter createPropertySetter(Class<?> clazz, String name)
{
Method method = findSetter(clazz, name);
if (method != null) return new PropertySetterMethodReflection(method);
Field field = findField(clazz, name);
if (field != null) return new PropertySetterFieldReflection(field);
return null;
}
public static PropertyAccessor createPropertyAccessor(Class<?> clazz, String name)
{
PropertyGetter getter = createPropertyGetter(clazz, name);
if (getter == null) return null;
PropertySetter setter = createPropertySetter(clazz, name);
if (setter == null) return null;
return new PropertyAccessorComposite(getter, setter);
}
}

View File

@@ -0,0 +1,6 @@
package com.massivecraft.mcore5.store.accessor;
public interface EntityAccessor extends EntitySetter, EntityGetter, EntityGlue
{
}

View File

@@ -0,0 +1,51 @@
package com.massivecraft.mcore5.store.accessor;
import java.util.Collection;
public abstract class EntityAccessorAbstract implements EntityAccessor
{
protected final Class<?> clazz;
public Class<?> getClazz() { return this.clazz; }
public EntityAccessorAbstract(Class<?> clazz)
{
this.clazz = clazz;
}
private static final boolean DEFAULT_TRANSPARENT = false;
@Override
public void copy(Object from, Object to, String property, boolean transparent)
{
Object val = this.get(from, property);
if (transparent && val == null) return;
this.set(to, property, val);
}
@Override
public void copy(Object from, Object to, String property)
{
this.copy(from, to, property, DEFAULT_TRANSPARENT);
}
@Override
public void copy(Object from, Object to, Collection<String> properties, boolean transparent)
{
for (String property : properties)
{
this.copy(from, to, property, transparent);
}
}
@Override
public void copy(Object from, Object to, Collection<String> properties)
{
this.copy(from, to, properties, DEFAULT_TRANSPARENT);
}
@Override
public void copy(Object from, Object to, boolean transparent)
{
this.copy(from, to, this.getPropertyNames(), transparent);
}
@Override
public void copy(Object from, Object to)
{
this.copy(from, to, DEFAULT_TRANSPARENT);
}
}

View File

@@ -0,0 +1,85 @@
package com.massivecraft.mcore5.store.accessor;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
public class EntityAccessorPerProperty extends EntityAccessorAbstract
{
protected Map<String, PropertyAccessor> propertyAccessors;
public Map<String, PropertyAccessor> getPropertyAccessors() { return this.propertyAccessors; }
public PropertyAccessor getPropertyAccessor(String name)
{
PropertyAccessor ret = this.propertyAccessors.get(name);
if (ret == null)
{
throw new IllegalArgumentException("The property \""+name+"\" is not supported.");
}
return ret;
}
public void setPropertyAccessor(String name, PropertyAccessor val)
{
this.propertyAccessors.put(name, val);
}
//----------------------------------------------//
// CONSTRUCTORS
//----------------------------------------------//
public EntityAccessorPerProperty(Class<?> clazz)
{
super(clazz);
this.propertyAccessors = new HashMap<String, PropertyAccessor>();
this.populateAI1();
}
//----------------------------------------------//
// AI
//----------------------------------------------//
public void populateAI1()
{
this.propertyAccessorAI(AccessorUtil.getFieldMap(this.clazz).keySet());
}
public void propertyAccessorAI(String name)
{
this.propertyAccessors.put(name, AccessorUtil.createPropertyAccessor(this.clazz, name));
}
public void propertyAccessorAI(String... names)
{
for (String name : names)
{
this.propertyAccessorAI(name);
}
}
public void propertyAccessorAI(Collection<? extends String> names)
{
this.propertyAccessorAI(names.toArray(new String[0]));
}
//----------------------------------------------//
// IMPLEMENTATION
//----------------------------------------------//
@Override
public void set(Object entity, String property, Object val)
{
PropertyAccessor pa = this.getPropertyAccessor(property);
pa.set(entity, val);
}
@Override
public Object get(Object entity, String property)
{
PropertyAccessor pa = this.getPropertyAccessor(property);
return pa.get(entity);
}
@Override
public Collection<String> getPropertyNames()
{
return this.propertyAccessors.keySet();
}
}

View File

@@ -0,0 +1,6 @@
package com.massivecraft.mcore5.store.accessor;
public interface EntityGetter
{
public Object get(Object entity, String property);
}

View File

@@ -0,0 +1,17 @@
package com.massivecraft.mcore5.store.accessor;
import java.util.Collection;
public interface EntityGlue
{
public void copy(Object from, Object to, String property, boolean transparent);
public void copy(Object from, Object to, String property);
public void copy(Object from, Object to, Collection<String> properties, boolean transparent);
public void copy(Object from, Object to, Collection<String> properties);
public void copy(Object from, Object to, boolean transparent);
public void copy(Object from, Object to);
public Collection<String> getPropertyNames();
}

View File

@@ -0,0 +1,6 @@
package com.massivecraft.mcore5.store.accessor;
public interface EntitySetter
{
public void set(Object entity, String property, Object val);
}

View File

@@ -0,0 +1,6 @@
package com.massivecraft.mcore5.store.accessor;
public interface PropertyAccessor extends PropertySetter, PropertyGetter
{
}

View File

@@ -0,0 +1,25 @@
package com.massivecraft.mcore5.store.accessor;
public class PropertyAccessorComposite implements PropertyAccessor
{
private final PropertyGetter getter;
private final PropertySetter setter;
public PropertyAccessorComposite(PropertyGetter getter, PropertySetter setter)
{
this.getter = getter;
this.setter = setter;
}
@Override
public void set(Object entity, Object val)
{
this.setter.set(entity, val);
}
@Override
public Object get(Object entity)
{
return this.getter.get(entity);
}
}

View File

@@ -0,0 +1,6 @@
package com.massivecraft.mcore5.store.accessor;
public interface PropertyGetter
{
public Object get(Object entity);
}

View File

@@ -0,0 +1,29 @@
package com.massivecraft.mcore5.store.accessor;
import java.lang.reflect.Field;
public class PropertyGetterFieldReflection implements PropertyGetter
{
private final Field field;
public PropertyGetterFieldReflection(Field field)
{
AccessorUtil.makeAccessible(field);
this.field = field;
}
@Override
public Object get(Object entity)
{
try
{
return this.field.get(entity);
}
catch (Exception e)
{
e.printStackTrace();
return null;
}
}
}

View File

@@ -0,0 +1,29 @@
package com.massivecraft.mcore5.store.accessor;
import java.lang.reflect.Method;
public class PropertyGetterMethodReflection implements PropertyGetter
{
private final Method method;
public PropertyGetterMethodReflection(Method method)
{
AccessorUtil.makeAccessible(method);
this.method = method;
}
@Override
public Object get(Object entity)
{
try
{
return this.method.invoke(entity, new Object[0]);
}
catch (Exception e)
{
e.printStackTrace();
return null;
}
}
}

View File

@@ -0,0 +1,6 @@
package com.massivecraft.mcore5.store.accessor;
public interface PropertySetter
{
public void set(Object entity, Object val);
}

View File

@@ -0,0 +1,28 @@
package com.massivecraft.mcore5.store.accessor;
import java.lang.reflect.Field;
public class PropertySetterFieldReflection implements PropertySetter
{
private final Field field;
public PropertySetterFieldReflection(Field field)
{
AccessorUtil.makeAccessible(field);
this.field = field;
}
@Override
public void set(Object entity, Object val)
{
try
{
this.field.set(entity, val);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,28 @@
package com.massivecraft.mcore5.store.accessor;
import java.lang.reflect.Method;
public class PropertySetterMethodReflection implements PropertySetter
{
private final Method method;
public PropertySetterMethodReflection(Method method)
{
AccessorUtil.makeAccessible(method);
this.method = method;
}
@Override
public void set(Object entity, Object val)
{
try
{
this.method.invoke(entity, val);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,29 @@
package com.massivecraft.mcore5.store.idstrategy;
import com.massivecraft.mcore5.store.CollInterface;
/**
* The tasks of the IdStrategy:
* 1. Generate a new free id that has not yet been used.
* 2. Convert the id between java object and raw database data.
*
* To complete the tasks the IdStrategy must be tailored for a specific database-driver.
* Thus you will find multiple implementations with the name "ai" (auto increment).
* There must be one implementation per driver.
*/
public interface IdStrategy<L, R>
{
// The name of the strategy (such as "auto_increment")
public String getName();
// The id classes
public Class<L> getLocalClass();
public Class<R> getRemoteClass();
// Convert
public R localToRemote(Object local);
public L remoteToLocal(Object remote);
// Generate
public L generate(CollInterface<?, L> coll);
}

View File

@@ -0,0 +1,41 @@
package com.massivecraft.mcore5.store.idstrategy;
import java.util.Collection;
import com.massivecraft.mcore5.store.CollInterface;
public abstract class IdStrategyAbstract<L, R> implements IdStrategy<L, R>
{
public IdStrategyAbstract(String name, Class<L> localClass, Class<R> remoteClass)
{
this.name = name;
this.localClass = localClass;
this.remoteClass = remoteClass;
}
protected String name;
@Override public String getName() { return this.name; }
protected Class<L> localClass;
@Override public Class<L> getLocalClass() { return this.localClass; }
protected Class<R> remoteClass;
@Override public Class<R> getRemoteClass() { return this.remoteClass; }
@Override
public L generate(CollInterface<?, L> coll)
{
Collection<L> alreadyInUse = coll.getIds();
L ret = null;
do
{
ret = this.generateAttempt(coll);
if (ret == null) return null;
}
while (alreadyInUse.contains(ret));
return ret;
}
public abstract L generateAttempt(CollInterface<?, L> coll);
}

View File

@@ -0,0 +1,91 @@
package com.massivecraft.mcore5.store.idstrategy;
import java.io.File;
import java.io.IOException;
import com.massivecraft.mcore5.store.CollInterface;
import com.massivecraft.mcore5.store.DbGson;
import com.massivecraft.mcore5.util.DiscUtil;
public class IdStrategyAiGson extends IdStrategyAbstract<String, String>
{
//----------------------------------------------//
// CONSTRUCTORS
//----------------------------------------------//
private IdStrategyAiGson()
{
super("ai", String.class, String.class);
}
// -------------------------------------------- //
// IMPLEMENTATION
// -------------------------------------------- //
@Override public String localToRemote(Object local) { return (String)local; }
@Override public String remoteToLocal(Object remote) { return (String)remote; }
@Override
public String generateAttempt(CollInterface<?, String> coll)
{
File file = getAiFile(coll);
// Ensure the file exists
if (this.ensureFileExists(file) == false)
{
return null;
}
String content = DiscUtil.readCatch(file);
if (content == null)
{
return null;
}
Integer current = 0;
if (content.length() > 0)
{
current = Integer.valueOf(content);
}
Integer next = current + 1;
if (DiscUtil.writeCatch(file, next.toString()) == false)
{
return null;
}
return current.toString();
}
protected File getAiFile(CollInterface<?, String> coll)
{
DbGson cdb = (DbGson)coll.getDb();
return new File(cdb.dir, coll.getName() + "_ai.txt");
}
protected boolean ensureFileExists(File file)
{
if (file.isFile()) return true;
if (file.isDirectory()) return false;
try
{
return file.createNewFile();
}
catch (IOException e)
{
return false;
}
}
// -------------------------------------------- //
// INSTANCE
// -------------------------------------------- //
protected static IdStrategyAiGson instance = new IdStrategyAiGson();
public static IdStrategyAiGson get()
{
return instance;
}
}

View File

@@ -0,0 +1,67 @@
package com.massivecraft.mcore5.store.idstrategy;
import com.massivecraft.mcore5.store.CollInterface;
import com.massivecraft.mcore5.store.DbMongo;
import com.massivecraft.mcore5.xlib.mongodb.BasicDBObject;
import com.massivecraft.mcore5.xlib.mongodb.DBCollection;
import com.massivecraft.mcore5.xlib.mongodb.DBObject;
public class IdStrategyAiMongo extends IdStrategyAbstract<String, String>
{
private static String SEC = "seq";
// -------------------------------------------- //
// FIELDS
// -------------------------------------------- //
// String sequenseName;
// DBCollection sequenseCollection;
String sequenseField;
//----------------------------------------------//
// CONSTRUCTORS
//----------------------------------------------//
private IdStrategyAiMongo()
{
super("ai", String.class, String.class);
this.sequenseField = SEC;
}
// -------------------------------------------- //
// IMPLEMENTATION
// -------------------------------------------- //
@Override public String localToRemote(Object local) { return (String)local; }
@Override public String remoteToLocal(Object remote) { return (String)remote; }
// http://dev.bubblemix.net/blog/2011/04/auto-increment-for-mongodb-with-the-java-driver/
@Override
public String generateAttempt(CollInterface<?, String> coll)
{
String sequenseName = coll.getName();
DBCollection sequenseCollection = ((DbMongo)coll.getDb()).db.getCollection(SEC);
// this object represents your "query", its analogous to a WHERE clause in SQL
DBObject query = new BasicDBObject();
query.put("_id", sequenseName); // where _id = the input sequence name
// this object represents the "update" or the SET blah=blah in SQL
DBObject change = new BasicDBObject(this.sequenseField, 1);
DBObject update = new BasicDBObject("$inc", change); // the $inc here is a mongodb command for increment
// Atomically updates the sequence field and returns the value for you
DBObject res = sequenseCollection.findAndModify(query, new BasicDBObject(), new BasicDBObject(), false, update, true, true);
return res.get(this.sequenseField).toString();
}
// -------------------------------------------- //
// INSTANCE
// -------------------------------------------- //
protected static IdStrategyAiMongo instance = new IdStrategyAiMongo();
public static IdStrategyAiMongo get()
{
return instance;
}
}

View File

@@ -0,0 +1,39 @@
package com.massivecraft.mcore5.store.idstrategy;
import com.massivecraft.mcore5.store.CollInterface;
import com.massivecraft.mcore5.xlib.bson.types.ObjectId;
public class IdStrategyOidGson extends IdStrategyAbstract<ObjectId, String>
{
// -------------------------------------------- //
// IMPLEMENTATION
// -------------------------------------------- //
@Override public String localToRemote(Object local) { return ((ObjectId)local).toStringBabble(); }
@Override public ObjectId remoteToLocal(Object remote) { return ObjectId.massageToObjectId((String)remote); }
@Override
public ObjectId generateAttempt(CollInterface<?, ObjectId> coll)
{
return ObjectId.get();
}
//----------------------------------------------//
// CONSTRUCTORS
//----------------------------------------------//
private IdStrategyOidGson()
{
super("oid", ObjectId.class, String.class);
}
// -------------------------------------------- //
// INSTANCE
// -------------------------------------------- //
protected static IdStrategyOidGson instance = new IdStrategyOidGson();
public static IdStrategyOidGson get()
{
return instance;
}
}

View File

@@ -0,0 +1,40 @@
package com.massivecraft.mcore5.store.idstrategy;
import com.massivecraft.mcore5.store.CollInterface;
import com.massivecraft.mcore5.xlib.bson.types.ObjectId;
public class IdStrategyOidMongo extends IdStrategyAbstract<ObjectId, ObjectId>
{
// -------------------------------------------- //
// IMPLEMENTATION
// -------------------------------------------- //
@Override public ObjectId localToRemote(Object local) { return (ObjectId)local; }
@Override public ObjectId remoteToLocal(Object remote) { return (ObjectId)remote; }
@Override
public ObjectId generateAttempt(CollInterface<?, ObjectId> coll)
{
return ObjectId.get();
}
//----------------------------------------------//
// CONSTRUCTORS
//----------------------------------------------//
private IdStrategyOidMongo()
{
super("oid", ObjectId.class, ObjectId.class);
}
// -------------------------------------------- //
// INSTANCE
// -------------------------------------------- //
protected static IdStrategyOidMongo instance = new IdStrategyOidMongo();
public static IdStrategyOidMongo get()
{
return instance;
}
}

View File

@@ -0,0 +1,40 @@
package com.massivecraft.mcore5.store.idstrategy;
import java.util.UUID;
import com.massivecraft.mcore5.store.CollInterface;
public class IdStrategyUuidMongoAndGson extends IdStrategyAbstract<UUID, String>
{
// -------------------------------------------- //
// IMPLEMENTATION
// -------------------------------------------- //
@Override public String localToRemote(Object local) { return ((UUID)local).toString(); }
@Override public UUID remoteToLocal(Object remote) { return UUID.fromString((String)remote); }
@Override
public UUID generateAttempt(CollInterface<?, UUID> coll)
{
return UUID.randomUUID();
}
//----------------------------------------------//
// CONSTRUCTORS
//----------------------------------------------//
private IdStrategyUuidMongoAndGson()
{
super("uuid", UUID.class, String.class);
}
// -------------------------------------------- //
// INSTANCE
// -------------------------------------------- //
protected static IdStrategyUuidMongoAndGson instance = new IdStrategyUuidMongoAndGson();
public static IdStrategyUuidMongoAndGson get()
{
return instance;
}
}

View File

@@ -0,0 +1,142 @@
package com.massivecraft.mcore5.store.storeadapter;
import java.util.Map.Entry;
import com.massivecraft.mcore5.xlib.bson.types.ObjectId;
import com.massivecraft.mcore5.xlib.gson.JsonArray;
import com.massivecraft.mcore5.xlib.gson.JsonElement;
import com.massivecraft.mcore5.xlib.gson.JsonNull;
import com.massivecraft.mcore5.xlib.gson.JsonObject;
import com.massivecraft.mcore5.xlib.gson.JsonPrimitive;
import com.massivecraft.mcore5.xlib.mongodb.BasicDBList;
import com.massivecraft.mcore5.xlib.mongodb.BasicDBObject;
import com.massivecraft.mcore5.xlib.mongodb.DBObject;
public final class MongoGsonConverter
{
// -------------------------------------------- //
// GSON 2 MONGO
// -------------------------------------------- //
public static BasicDBObject gson2MongoObject(JsonElement inElement)
{
JsonObject in = inElement.getAsJsonObject();
BasicDBObject out = new BasicDBObject();
for (Entry<String, JsonElement> entry : in.entrySet())
{
String key = entry.getKey();
JsonElement val = entry.getValue();
if (val.isJsonArray())
{
out.put(key, gson2MongoArray(val));
}
else if (val.isJsonObject())
{
out.put(key, gson2MongoObject(val));
}
else
{
out.put(key, gson2MongoPrimitive(val));
}
}
return out;
}
public static BasicDBList gson2MongoArray(JsonElement inElement)
{
JsonArray in = inElement.getAsJsonArray();
BasicDBList out = new BasicDBList();
for (int i = 0; i < in.size(); i++)
{
JsonElement element = in.get(i);
if (element.isJsonArray())
{
out.add(gson2MongoArray(element));
}
else if (element.isJsonObject())
{
out.add(gson2MongoObject(element));
}
else
{
out.add(gson2MongoPrimitive(element));
}
}
return out;
}
public static Object gson2MongoPrimitive(JsonElement inElement)
{
if (inElement.isJsonNull()) return null;
JsonPrimitive in = inElement.getAsJsonPrimitive();
if (in.isBoolean()) return in.getAsBoolean();
if (in.isNumber()) return in.getAsNumber();
if (in.isString()) return in.getAsString();
throw new IllegalArgumentException("Unsupported value type for: " + in);
}
// -------------------------------------------- //
// MONGO 2 GSON
// -------------------------------------------- //
public static JsonObject mongo2GsonObject(DBObject inObject)
{
if (!(inObject instanceof BasicDBObject)) throw new IllegalArgumentException("Expected BasicDBObject as argument type!");
BasicDBObject in = (BasicDBObject)inObject;
JsonObject jsonObject = new JsonObject();
for (Entry<String, Object> entry : in.entrySet())
{
String key = entry.getKey();
Object val = entry.getValue();
if (val instanceof BasicDBList)
{
jsonObject.add(key, mongo2GsonArray((BasicDBList)val));
}
else if (val instanceof BasicDBObject)
{
jsonObject.add(key, mongo2GsonObject((BasicDBObject)val));
}
else
{
jsonObject.add(key, mongo2GsonPrimitive(val));
}
}
return jsonObject;
}
public static JsonArray mongo2GsonArray(DBObject inObject)
{
if (!(inObject instanceof BasicDBList)) throw new IllegalArgumentException("Expected BasicDBList as argument type!");
BasicDBList in = (BasicDBList)inObject;
JsonArray jsonArray = new JsonArray();
for (int i = 0; i < in.size(); i++)
{
Object object = in.get(i);
if (object instanceof BasicDBList)
{
jsonArray.add(mongo2GsonArray((BasicDBList) object));
}
else if (object instanceof BasicDBObject)
{
jsonArray.add(mongo2GsonObject((BasicDBObject) object));
}
else
{
jsonArray.add(mongo2GsonPrimitive(object));
}
}
return jsonArray;
}
public static JsonElement mongo2GsonPrimitive(Object inObject)
{
if (inObject == null) return JsonNull.INSTANCE;
if (inObject instanceof Boolean) return new JsonPrimitive((Boolean) inObject);
if (inObject instanceof Number) return new JsonPrimitive((Number) inObject);
if (inObject instanceof String) return new JsonPrimitive((String) inObject);
if (inObject instanceof Character) return new JsonPrimitive((Character) inObject);
if (inObject instanceof ObjectId) return new JsonPrimitive(inObject.toString());
throw new IllegalArgumentException("Unsupported value type for: " + inObject);
}
}

Some files were not shown because too many files have changed in this diff Show More