From 50bb599aaa30c0ad619f4e10a859420e759aa79e Mon Sep 17 00:00:00 2001 From: Daniel Kozlowski Date: Sun, 27 May 2012 23:07:14 -0400 Subject: [PATCH] Added missing stat Types ( should have just as many types as MineJMX now ) Added framework for Logging to a stat source --- README.md | 10 ++++ .../scala/com/dkhenry/minestat/MineStat.scala | 21 +++++++-- .../minestat/MineStatBlockListener.scala | 3 +- .../minestat/MineStatEntityListener.scala | 2 +- .../minestat/MineStatPlayerListener.scala | 47 +++++++++++++++++++ .../scala/com/dkhenry/minestat/MongoLog.scala | 19 ++++++++ .../dkhenry/minestat/ServerTickPoller.scala | 38 +++++++++++++++ 7 files changed, 135 insertions(+), 5 deletions(-) create mode 100644 src/main/scala/com/dkhenry/minestat/MineStatPlayerListener.scala create mode 100644 src/main/scala/com/dkhenry/minestat/MongoLog.scala create mode 100644 src/main/scala/com/dkhenry/minestat/ServerTickPoller.scala diff --git a/README.md b/README.md index 51f07f7..9b375e9 100644 --- a/README.md +++ b/README.md @@ -8,3 +8,13 @@ To Build this you will need a working installation of the Simple Build Tool then sbt assembly This will create the Jar file in target/ + + +## TODO + +Add a type flag so we can have things like which kind of block was destroyed ( ignored by some persisters ) +Add the process to snapshot the persisted data at regular intervals ( 5min ) + +Idealy every five minutes we would roll up the entire persistance table into nice objects and insert them as documents into the data store + +Add Option to log events ( then count the events , LogIn , LogOff , ... ) diff --git a/src/main/scala/com/dkhenry/minestat/MineStat.scala b/src/main/scala/com/dkhenry/minestat/MineStat.scala index 97e3733..c602583 100644 --- a/src/main/scala/com/dkhenry/minestat/MineStat.scala +++ b/src/main/scala/com/dkhenry/minestat/MineStat.scala @@ -100,6 +100,7 @@ class MongoPersist extends Persist { val data = _mongoConn("minestat") def store(typ: String, name: String, indicator: String, value: Double) = { + // true -> Upsert , false -> multiple ( only update one document if you match the filter ) data(typ).update(DBObject("name"->name,"indicator"->indicator),$set("value"-> value),true,false) } @@ -138,17 +139,31 @@ class MineStatPlugin extends JavaPlugin { // The Listeners val blockListener = new MineStatBlockListener(this) val entityListener = new MineStatEntityListener(this) + val playerListener = new MineStatPlayerListener(this) + val tickPoller = new ServerTickPoller(this) - override def onEnable = { - logInfo("MineStat Enabled!") + val scorekeeper = new MongoLog(this) + + override def onEnable = { + logInfo("Enableing MineStat!") /* Register the Listeners */ val pm: PluginManager = this.getServer().getPluginManager() ; // The Block Events pm.registerEvents(blockListener, this) ; - // The Entity Events pm.registerEvents(entityListener, this); + // The Player Listener + pm.registerEvents(playerListener, this); + + // Reset the server wide statistics + persistance.set("server",serverName,"numberOfPlayers",0.0); + + // Server Events + tickPoller.registerWithScheduler(getServer().getScheduler()) + scorekeeper.registerWithScheduler(getServer().getScheduler()) + + logInfo("MineStat Enabled!") } override def onDisable = { diff --git a/src/main/scala/com/dkhenry/minestat/MineStatBlockListener.scala b/src/main/scala/com/dkhenry/minestat/MineStatBlockListener.scala index 4b3c749..0d781dc 100644 --- a/src/main/scala/com/dkhenry/minestat/MineStatBlockListener.scala +++ b/src/main/scala/com/dkhenry/minestat/MineStatBlockListener.scala @@ -14,7 +14,8 @@ import org.bukkit.event.block.LeavesDecayEvent import scala.collection.mutable.HashMap import org.bukkit.plugin.PluginManager -class MineStatBlockListener(plugin: MineStatPlugin) extends Listener { +class MineStatBlockListener(plugin: MineStatPlugin) extends Listener { + @EventHandler def onBlockPlace(event: BlockPlaceEvent) = { val mat = event.getBlock().getType() diff --git a/src/main/scala/com/dkhenry/minestat/MineStatEntityListener.scala b/src/main/scala/com/dkhenry/minestat/MineStatEntityListener.scala index 1899d9e..6e75fee 100644 --- a/src/main/scala/com/dkhenry/minestat/MineStatEntityListener.scala +++ b/src/main/scala/com/dkhenry/minestat/MineStatEntityListener.scala @@ -103,7 +103,7 @@ class MineStatEntityListener(plugin: MineStatPlugin) extends Listener{ plugin.logInfo(subject.getClass().getName().split('.').last + " Death") subject match { case p: Player => handlePlayerDeath(p) - case e: LivingEntity => plugin.logInfo("About to Handle NPE Death") ; handleNpeDeath(e) + case e: LivingEntity => plugin.logInfo("About to Handle NPE Death") ; handleNpeDeath(e) case _ => plugin.logInfo("Well I could have handled that better") } plugin.logInfo("Done Handling Event") diff --git a/src/main/scala/com/dkhenry/minestat/MineStatPlayerListener.scala b/src/main/scala/com/dkhenry/minestat/MineStatPlayerListener.scala new file mode 100644 index 0000000..59f20bc --- /dev/null +++ b/src/main/scala/com/dkhenry/minestat/MineStatPlayerListener.scala @@ -0,0 +1,47 @@ +package com.dkhenry.minestat + +import org.bukkit.Location +import org.bukkit.entity.Player +import org.bukkit.event.EventHandler +import org.bukkit.event.Listener +import org.bukkit.event.player.PlayerJoinEvent +import org.bukkit.event.player.PlayerMoveEvent +import org.bukkit.event.player.PlayerQuitEvent; +import scala.collection.mutable.HashMap + +class MineStatPlayerListener(plugin: MineStatPlugin) extends Listener { + var playerHash = new HashMap[String,Long]() + + @EventHandler + def onPlayerJoin(event: PlayerJoinEvent) = { + def name = event.getPlayer().getName() + plugin.persistance.increment("server",plugin.serverName,"numberOfPlayers",1.0); + plugin.persistance.increment("player",name,"numberOfLogins",1.0); + plugin.persistance.set("player",name,"active",1.0); + playerHash put (name , System.currentTimeMillis()) + } + + @EventHandler + def onPlayerQuit(event: PlayerQuitEvent) = { + def name = event.getPlayer().getName() + plugin.persistance.increment("server",plugin.serverName,"numberOfPlayers",-1.0); + plugin.persistance.set("player",name,"active",0.0); + + playerHash get name map { t => + plugin.persistance.increment("player",name,"timeOnServer",System.currentTimeMillis() - t); + } + } + + @EventHandler + def onPlayerMove(event: PlayerMoveEvent) = { + val player = event.getPlayer(); + val from = event.getFrom() + val to = event.getTo(); + + val distance = Math.sqrt(Math.pow(to.getX() - from.getX(), 2) + Math.pow(to.getY() - from.getY(), 2) + Math.pow(to.getZ() - from.getZ(), 2)); + + // Increment the per-Player stats + plugin.persistance.increment("player",player.getName(),"distanceMoved",distance); + plugin.persistance.increment("server",plugin.serverName,"playerDistanceMoved",distance); + } +} \ No newline at end of file diff --git a/src/main/scala/com/dkhenry/minestat/MongoLog.scala b/src/main/scala/com/dkhenry/minestat/MongoLog.scala new file mode 100644 index 0000000..285e0d8 --- /dev/null +++ b/src/main/scala/com/dkhenry/minestat/MongoLog.scala @@ -0,0 +1,19 @@ +package com.dkhenry.minestat +import org.bukkit.scheduler.BukkitScheduler + +class MongoLog(plugin: MineStatPlugin) extends Runnable { + + var interval = 300 + var tid = 0 + + def registerWithScheduler(scheduler: BukkitScheduler) { + tid = scheduler.scheduleAsyncRepeatingTask(plugin, this, 0, interval) ; + } + + + @Override + def run() = { + // we need to take a snapshot of persistance and write it to the MongoDB Log + + } +} \ No newline at end of file diff --git a/src/main/scala/com/dkhenry/minestat/ServerTickPoller.scala b/src/main/scala/com/dkhenry/minestat/ServerTickPoller.scala new file mode 100644 index 0000000..48566d4 --- /dev/null +++ b/src/main/scala/com/dkhenry/minestat/ServerTickPoller.scala @@ -0,0 +1,38 @@ +package com.dkhenry.minestat + +import org.bukkit.scheduler.BukkitScheduler; + +class ServerTickPoller(plugin: MineStatPlugin) extends Runnable { + var interval: Long = 40; + var lastPoll: Long = System.currentTimeMillis() ; + + def registerWithScheduler(scheduler: BukkitScheduler) { + scheduler.scheduleAsyncRepeatingTask(plugin, this, 0, interval) ; + } + + @Override + def run() = { + // Cache the current time + val current = System.currentTimeMillis() ; + + // Calculate the Delta + var delta = current - lastPoll ; + + // Make sure we check for a DivByZero error + if(delta <= 0 ) { + delta = 1 ; + } + + val tickRate = this.interval*1000 / delta ; + + plugin.persistance.set("server",plugin.serverName,"tickRate",tickRate.doubleValue()); + plugin.persistance.increment("server",plugin.serverName,"ticks",tickRate.doubleValue()); + + val active = plugin.getServer().getScheduler().getActiveWorkers().size() ; + plugin.persistance.set("server",plugin.serverName,"activeTasks",active); + val pending = plugin.getServer().getScheduler().getPendingTasks().size() ; + plugin.persistance.set("server",plugin.serverName,"pendingTasks",pending); + + lastPoll = current ; + } +} \ No newline at end of file