diff --git a/config.yml b/config.yml
index 6dddd84..33b9e17 100644
--- a/config.yml
+++ b/config.yml
@@ -140,7 +140,14 @@ region:
# Hint: Is very confusing, if MultiVerse "enforce gamemode" swaps your state.
# default: false
remember: false
-
+
+ # RegionSafeMode
+ # When a player leaves a region he always will get back to the world gamemode, even if he entered the region already
+ # in the region-gamemode. So its the opposite analog to RegionRememberOptional.
+ # That means: If a GM in creative-mode walks/flies through a creative-region in a survival world, he will get back
+ # to survival on leaving the region.
+ # default: false
+ safemode: false
cmdblock:
# CommandBlockerEnabled
@@ -167,4 +174,11 @@ cmdblock:
# Uncomment the "locale: en_US"-Line, to override the locale which be used for localized messages. By default the
# System-Locale is used (selected by Java depending on LC_LANG-Environment-Variable
# default: none (Use System-Default Locale)
-#locale: en_US
\ No newline at end of file
+#locale: en_US
+
+# Metrics
+# This settings allows the Addon-Author to track the Servers using this plugin. It will not track any player
+# related data like names, ips, online time or such. Please do not disable the option! As more servers are using
+# the plugin and the author knows, as more he is willing to support the plugin! Its a win-win for both.
+# default: true
+metrics: true
diff --git a/plugin.yml b/plugin.yml
index 9967591..d1e5e37 100644
--- a/plugin.yml
+++ b/plugin.yml
@@ -1,6 +1,6 @@
name: LimitedCreative
main: de.jaschastarke.minecraft.limitedcreative.Core
-version: 1.4.7a
+version: 1.4.7b
softdepend: [WorldGuard, WorldEdit, MultiInv, xAuth, AuthMe, MultiInv, Multiverse-Inventories]
dev-url: http://dev.bukkit.org/server-mods/limited-creative/
commands:
diff --git a/pom.xml b/pom.xml
index 76dcc0f..ad95df6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
de.jaschastarke
LimitedCreative
LimitedCreative
- 1.4.7a
+ 1.4.7b
https://github.com/possi/LimitedCreative
scm:git:git://github.com/possi/LimitedCreative.git
@@ -57,6 +57,7 @@
plugin.yml
config.yml
+ settings.properties
@@ -81,13 +82,13 @@
org.bukkit
bukkit
- 1.4.6-R0.1
+ 1.4.7-R0.1
org.bukkit
craftbukkit
- 1.4.6-R0.1
+ 1.4.7-R0.1
diff --git a/settings.properties b/settings.properties
new file mode 100644
index 0000000..ed3b3f7
--- /dev/null
+++ b/settings.properties
@@ -0,0 +1,2 @@
+piwik_url = http://stats.ja-s.de/piwikProxy.php
+piwik_site_id = 2
\ No newline at end of file
diff --git a/src/de/jaschastarke/bukkit/tools/stats/IStatistics.java b/src/de/jaschastarke/bukkit/tools/stats/IStatistics.java
new file mode 100644
index 0000000..0909a60
--- /dev/null
+++ b/src/de/jaschastarke/bukkit/tools/stats/IStatistics.java
@@ -0,0 +1,10 @@
+package de.jaschastarke.bukkit.tools.stats;
+
+public interface IStatistics {
+ public static final String SEPERATOR = "/";
+ /**
+ * Use the {@see SEPERATOR} to create subgroup of events
+ * @param event
+ */
+ public void trackEvent(String event);
+}
diff --git a/src/de/jaschastarke/bukkit/tools/stats/PiwikStatistics.java b/src/de/jaschastarke/bukkit/tools/stats/PiwikStatistics.java
new file mode 100644
index 0000000..e967611
--- /dev/null
+++ b/src/de/jaschastarke/bukkit/tools/stats/PiwikStatistics.java
@@ -0,0 +1,245 @@
+package de.jaschastarke.bukkit.tools.stats;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+import java.util.Stack;
+import java.util.UUID;
+
+import org.bukkit.ChatColor;
+import org.bukkit.plugin.Plugin;
+import org.bukkit.plugin.java.JavaPlugin;
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+
+/**
+ * Use the piwik-Proxy https://gist.github.com/4664325 to track the online-count as seperate requests to get a propper
+ * graph of usage.
+ *
+ * Settings as Properties:
+ * - piwik_url : required; URL to the piwik.php or the proxy file (see above)
+ * - piwik_site_id : required; The Site-ID of the Piwik-Website to use for tracking
+ * - stats_interval : optional; seconds between tracking online count (defaults to 300 for 5 min)
+ */
+public class PiwikStatistics implements IStatistics {
+ private static final int TICKS_PER_SECOND = 20;
+ private static final long DEFAULT_WAIT = 6000L; // 6000 ticks or 300 seconds or 5 minutes
+ private static final int MAX_CVAR_SIZE = 200;
+ private static final int APIV = 1;
+ private URL apiUrl;
+ private int idSite;
+ private Plugin plugin;
+ private String pluginname;
+ private String version;
+ private String server;
+ private String serverid = getUniqueID();
+ private String servername;
+ private String servermotd;
+ private long wait = DEFAULT_WAIT;
+
+ private static final String PIWIK_FIELD_CVAR = "cvar";
+
+ /**
+ * Single call instantiate
+ *
+ * Also calls .register,
+ */
+ public PiwikStatistics(final JavaPlugin plugin) {
+ Properties settings = new Properties();
+ try {
+ settings.load(plugin.getClass().getClassLoader().getResourceAsStream("settings.properties"));
+ init(settings);
+ register(plugin);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ /**
+ * Single call instantiate
+ *
+ * Also calls .register,
+ */
+ public PiwikStatistics(final JavaPlugin plugin, final InputStream settingsFile) {
+ Properties settings = new Properties();
+ try {
+ settings.load(settingsFile);
+ init(settings);
+ register(plugin);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ public PiwikStatistics(final Properties settings) {
+ init(settings);
+ }
+ private void init(final Properties settings) {
+ try {
+ String url = settings.getProperty("piwik_url");
+ if (url.isEmpty()) {
+ apiUrl = null;
+ return;
+ }
+ apiUrl = new URL(url);
+ idSite = Integer.parseInt(settings.getProperty("piwik_site_id"));
+ String seconds = settings.getProperty("stats_interval");
+ if (seconds != null && !seconds.isEmpty())
+ wait = Long.parseLong(seconds) * TICKS_PER_SECOND;
+ } catch (MalformedURLException e) {
+ throw new IllegalArgumentException("Invalid Piwik-URL defined", e);
+ }
+ }
+
+ public static String getUniqueID() {
+ return String.format("%016x", UUID.randomUUID().getMostSignificantBits());
+ }
+
+ public void register(final Plugin rplugin) {
+ if (apiUrl == null)
+ return;
+ plugin = rplugin;
+ //plugin.getServer().getPluginManager().registerEvents(new StatsListener(), plugin);
+ pluginname = plugin.getName();
+ version = plugin.getDescription().getVersion();
+
+ plugin.getServer().getScheduler().runTaskLaterAsynchronously(plugin, new Runnable() {
+ @Override
+ public void run() {
+ // Well, we all know it isn't http, but as piwik is a website tracking, it doesn't tracks the url if it isn't a http url ;)
+ server = "http://" + StatsUtils.getIP(plugin.getServer()) + ":" + plugin.getServer().getPort();
+ servername = ChatColor.stripColor(plugin.getServer().getServerName().replace(SEPERATOR, "-"));
+ servermotd = ChatColor.stripColor(plugin.getServer().getMotd().replace(SEPERATOR, "-").replaceAll("\\s+", " "));
+ trackEnable();
+ }
+ }, wait);
+ plugin.getServer().getScheduler().scheduleSyncRepeatingTask(plugin, new Runnable() {
+ @Override
+ public void run() {
+ final int playercount = plugin.getServer().getOnlinePlayers().length;
+ if (playercount > 0) {
+ plugin.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable() {
+ @Override
+ public void run() {
+ trackOnlineUsage(playercount);
+ }
+ });
+ }
+ }
+ }, wait, wait);
+ }
+
+ private void trackEnable() {
+ Plugin[] pluginlist = plugin.getServer().getPluginManager().getPlugins();
+ List cdata = new ArrayList();
+ cdata.add(new String[]{"Server-Name", servername});
+ cdata.add(new String[]{"Server-Version", (plugin.getServer().getName() + " " + plugin.getServer().getVersion())});
+ cdata.add(new String[]{"Plugin-Version", pluginname + " " + version});
+
+ Stack plugins = new Stack();
+ plugins.add(new StringBuilder(""));
+
+ for (Plugin cplugin : pluginlist) {
+ StringBuilder currentPlugins = plugins.lastElement();
+ if ((currentPlugins.length() + cplugin.getName().length() + 1) > MAX_CVAR_SIZE) {
+ plugins.add(new StringBuilder());
+ currentPlugins = plugins.lastElement();
+ }
+ if (currentPlugins.length() > 0)
+ currentPlugins.append(",");
+ currentPlugins.append(cplugin.getName());
+ }
+ for (int i = 0; i < plugins.size(); i++) {
+ String plname = i == 0 ? "Plugins" : ("Plugins " + (i + 1));
+ cdata.add(new String[]{plname, plugins.get(i).toString()});
+ }
+ cdata.add(new String[]{"Mode", plugin.getServer().getOnlineMode() ? "Online" : "Offline"});
+ JSONObject cvar = getCVar(cdata.toArray(new String[cdata.size()][]));
+
+ String[][] args = new String[][]{
+ {"action_name", servermotd},
+ {PIWIK_FIELD_CVAR, cvar.toJSONString()}
+ };
+ track(server + SEPERATOR + pluginname + "/load", args);
+ }
+
+ private void trackOnlineUsage(final int playercount) {
+ List cdata = new ArrayList();
+ cdata.add(new String[]{"Online-Count", Integer.toString(playercount)});
+ if (!plugin.getServer().getOnlineMode())
+ cdata.add(new String[]{"Offline-Mode", "yes"});
+ JSONObject cvar = getCVar(cdata.toArray(new String[cdata.size()][]));
+
+ track(server + SEPERATOR + pluginname + "/usage", new String[][]{
+ {"multiple", Integer.toString(playercount)}, // handled by piwikProxy.php to create a Batch-Request to simulate multiple hits
+ {PIWIK_FIELD_CVAR, cvar.toJSONString()}
+ });
+ }
+
+ @SuppressWarnings("unchecked")
+ public static JSONObject getCVar(final String[][] cvars) {
+ JSONObject cvar = new JSONObject();
+ for (int i = 0; i < cvars.length; i++) {
+ JSONArray t = new JSONArray();
+ t.add(cvars[i][0]);
+ t.add(cvars[i][1]);
+ cvar.put(Integer.toString(i + 1), t);
+ }
+ return cvar;
+ }
+
+ protected void track(final String target, final String[][] addargs) {
+ String[][] basicargs = new String[][]{
+ {"idsite", Integer.toString(idSite)},
+ {"rec", "1"},
+ {"url", target},
+ {"_id", serverid},
+ {"rand", Long.toString(System.currentTimeMillis())},
+ {"apiv", Integer.toString(APIV)},
+ };
+
+ String[][] arguments;
+ if (addargs.length > 0) {
+ arguments = new String[basicargs.length + addargs.length][2];
+ System.arraycopy(basicargs, 0, arguments, 0, basicargs.length);
+ System.arraycopy(addargs, 0, arguments, basicargs.length, addargs.length);
+ } else {
+ arguments = basicargs;
+ }
+
+ try {
+ URL req = StatsUtils.buildRequest(apiUrl, arguments);
+ URLConnection conn = req.openConnection();
+ //System.out.println(req.toString());
+ conn.setUseCaches(false);
+ conn.connect();
+ InputStream in = conn.getInputStream();
+ in.read();
+ in.close();
+ } catch (IllegalArgumentException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /*class StatsListener implements Listener {
+ @EventHandler
+ public void onJoin(final PlayerJoinEvent event) {
+ plugin.getServer().getScheduler().scheduleAsyncDelayedTask(plugin, new Runnable() {
+ @Override
+ public void run() {
+ track(server + SEPERATOR + pluginname + "/join", new String[0][0]);
+ }
+ });
+ }
+ }*/
+
+ @Override
+ public void trackEvent(final String event) {
+ track(server + SEPERATOR + pluginname + SEPERATOR + event, new String[0][0]);
+ }
+}
diff --git a/src/de/jaschastarke/bukkit/tools/stats/StatsUtils.java b/src/de/jaschastarke/bukkit/tools/stats/StatsUtils.java
new file mode 100644
index 0000000..60346b9
--- /dev/null
+++ b/src/de/jaschastarke/bukkit/tools/stats/StatsUtils.java
@@ -0,0 +1,58 @@
+package de.jaschastarke.bukkit.tools.stats;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.UnsupportedEncodingException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLEncoder;
+
+import org.bukkit.Server;
+
+public final class StatsUtils {
+ private static final String ENCODING = "UTF-8";
+ private StatsUtils() {
+ }
+
+ public static String getIP(final Server server) {
+ String ip = server.getIp();
+ if (ip.isEmpty()) {
+ try {
+ URL getip = new URL("http://checkip.amazonaws.com/");
+ BufferedReader in = new BufferedReader(new InputStreamReader(getip.openStream()));
+ ip = in.readLine();
+ in.close();
+ } catch (MalformedURLException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ return ip;
+ }
+
+ public static String enc(final String s) {
+ try {
+ return URLEncoder.encode(s, ENCODING);
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+ return s;
+ }
+
+ public static URL buildRequest(final URL url, final String[][] arguments) {
+ StringBuilder u = new StringBuilder(url.toString());
+ for (int i = 0; i < arguments.length; i++) {
+ u.append(i == 0 ? "?" : "&");
+ u.append(arguments[i][0]);
+ u.append("=");
+ u.append(enc(arguments[i][1]));
+ }
+ try {
+ return new URL(u.toString());
+ } catch (MalformedURLException e) {
+ throw new IllegalArgumentException("Arguments couldn't build to a new URL");
+ }
+ }
+}
diff --git a/src/de/jaschastarke/minecraft/limitedcreative/Configuration.java b/src/de/jaschastarke/minecraft/limitedcreative/Configuration.java
index 2c2ede7..30b57a9 100644
--- a/src/de/jaschastarke/minecraft/limitedcreative/Configuration.java
+++ b/src/de/jaschastarke/minecraft/limitedcreative/Configuration.java
@@ -49,6 +49,7 @@ public class Configuration {
ADVENTUREINV("store.adventure", false),
REGION_OPTIONAL("region.optional", true),
REGION_REMEMBER("region.remember", false),
+ REGION_SAFEMODE("region.safemode", false),
BLOCKPICKUP("limit.pickup", true),
BLOCKSIGN("limit.sign", true),
BLOCKBUTTON("limit.button", false),
@@ -58,6 +59,7 @@ public class Configuration {
REMOVEPICKUP("limit.remove_pickup", false),
PERM_WEPIF("permissions.wepif", true),
CMDBLOCKER("cmdblocker.enabled", true),
+ METRICS("metrics", true),
DEBUG("debug", false);
private String key;
@@ -162,6 +164,9 @@ public class Configuration {
public boolean getRegionRememberOptional() {
return this.getRegionOptional() && this.getBoolean(Option.REGION_REMEMBER);
}
+ public boolean getRegionSafeMode() {
+ return this.getBoolean(Option.REGION_SAFEMODE);
+ }
public String getLocale() {
if (c.contains("locale") && c.getString("locale") != "none")
diff --git a/src/de/jaschastarke/minecraft/limitedcreative/Core.java b/src/de/jaschastarke/minecraft/limitedcreative/Core.java
index 0a04847..fbf4a46 100644
--- a/src/de/jaschastarke/minecraft/limitedcreative/Core.java
+++ b/src/de/jaschastarke/minecraft/limitedcreative/Core.java
@@ -24,7 +24,9 @@ import org.bukkit.event.HandlerList;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.java.JavaPlugin;
+import de.jaschastarke.bukkit.tools.stats.PiwikStatistics;
import de.jaschastarke.minecraft.integration.Communicator;
+import de.jaschastarke.minecraft.limitedcreative.Configuration.Option;
import de.jaschastarke.minecraft.limitedcreative.cmdblock.CommandBlocker;
import de.jaschastarke.minecraft.limitedcreative.listeners.LimitListener;
import de.jaschastarke.minecraft.limitedcreative.listeners.MainListener;
@@ -106,6 +108,9 @@ public class Core extends JavaPlugin {
Commands.register(this);
+ if (config.getBoolean(Option.METRICS))
+ new PiwikStatistics(this);
+
/*plugin.getServer().getScheduler().scheduleSyncRepeatingTask(plugin, new Runnable() {
@Override
public void run() {
diff --git a/src/de/jaschastarke/minecraft/limitedcreative/LCPlayer.java b/src/de/jaschastarke/minecraft/limitedcreative/LCPlayer.java
index 26599fa..72c8b6d 100644
--- a/src/de/jaschastarke/minecraft/limitedcreative/LCPlayer.java
+++ b/src/de/jaschastarke/minecraft/limitedcreative/LCPlayer.java
@@ -161,9 +161,13 @@ public class LCPlayer {
_permanent_gamemode = temp;
}
public boolean isInPermanentGameMode() {
+ if (plugin.config.getRegionSafeMode())
+ return false;
return isInPermanentGameMode(getPlayer().getGameMode());
}
public boolean isInPermanentGameMode(GameMode temp) {
+ if (plugin.config.getRegionSafeMode())
+ return false;
Core.debug(getName()+": get permanent game mode: " + _permanent_gamemode);
return temp.equals(_permanent_gamemode);
}