diff --git a/Plugin NPC/src/main/java/net/simon987/npcplugin/VaultExitPortal.java b/Plugin NPC/src/main/java/net/simon987/npcplugin/VaultExitPortal.java index 3266b5a..bea6435 100644 --- a/Plugin NPC/src/main/java/net/simon987/npcplugin/VaultExitPortal.java +++ b/Plugin NPC/src/main/java/net/simon987/npcplugin/VaultExitPortal.java @@ -34,10 +34,12 @@ public class VaultExitPortal extends Portal { @Override public boolean enter(GameObject object) { - LogManager.LOGGER.info(((ControllableUnit) object).getParent().getUsername() + " Completed vault " + - object.getWorld().getDimension()); + if (object instanceof ControllableUnit) { + LogManager.LOGGER.info(((ControllableUnit) object).getParent().getUsername() + " Completed vault " + + object.getWorld().getDimension()); - //todo: save vault completion stat + ((ControllableUnit) object).getParent().getStats().addToStringSet("completedVaults", getWorld().getDimension()); + } return super.enter(object); } diff --git a/Server/src/main/java/net/simon987/server/GameServer.java b/Server/src/main/java/net/simon987/server/GameServer.java index 6186b3a..adb00c5 100644 --- a/Server/src/main/java/net/simon987/server/GameServer.java +++ b/Server/src/main/java/net/simon987/server/GameServer.java @@ -14,6 +14,7 @@ import net.simon987.server.logging.LogManager; import net.simon987.server.plugin.PluginManager; import net.simon987.server.user.User; import net.simon987.server.user.UserManager; +import net.simon987.server.user.UserStatsHelper; import net.simon987.server.websocket.SocketServer; import java.io.File; @@ -42,14 +43,20 @@ public class GameServer implements Runnable { private UserManager userManager; + private UserStatsHelper userStatsHelper; + public GameServer() { this.config = new ServerConfiguration("config.properties"); try{ mongo = new MongoClient("localhost", 27017); - userManager = new UserManager(mongo, config); + DB db = mongo.getDB(config.getString("mongo_dbname")); + DBCollection userCollection = db.getCollection("user"); + + userManager = new UserManager(userCollection); + userStatsHelper = new UserStatsHelper(userCollection); } catch (UnknownHostException e) { e.printStackTrace(); } @@ -74,7 +81,6 @@ public class GameServer implements Runnable { if (pluginFile.getName().endsWith(".jar")) { pluginManager.load(pluginFile, config); } - } } else { if (!pluginDir.mkdir()) { @@ -98,7 +104,7 @@ public class GameServer implements Runnable { eventDispatcher.getListeners().add(new HealObjCommandListener()); eventDispatcher.getListeners().add(new DamageObjCommandListener()); eventDispatcher.getListeners().add(new SetEnergyCommandListener()); - + eventDispatcher.getListeners().add(new SaveGameCommandListener()); } public GameUniverse getGameUniverse() { @@ -141,10 +147,7 @@ public class GameServer implements Runnable { } catch (InterruptedException e) { e.printStackTrace(); } - } - - } private void tick() { @@ -230,7 +233,7 @@ public class GameServer implements Runnable { " | U:" + GameServer.INSTANCE.getGameUniverse().getUserCount()); } - private void save() { + public void save() { LogManager.LOGGER.info("Saving to MongoDB | W:" + gameUniverse.getWorldCount() + " | U:" + gameUniverse.getUserCount()); try{ @@ -294,4 +297,8 @@ public class GameServer implements Runnable { public UserManager getUserManager() { return userManager; } + + public UserStatsHelper getUserStatsHelper() { + return userStatsHelper; + } } diff --git a/Server/src/main/java/net/simon987/server/user/User.java b/Server/src/main/java/net/simon987/server/user/User.java index 21345a8..021bb95 100755 --- a/Server/src/main/java/net/simon987/server/user/User.java +++ b/Server/src/main/java/net/simon987/server/user/User.java @@ -28,6 +28,8 @@ public class User implements MongoSerialisable { private boolean guest = false; private boolean moderator = false; + private UserStats stats; + public User() throws CancelledException { GameEvent event = new UserCreationEvent(this); GameServer.INSTANCE.getEventDispatcher().dispatch(event); @@ -35,6 +37,7 @@ public class User implements MongoSerialisable { throw new CancelledException(); } + this.stats = new UserStats(); } public User(ControllableUnit unit) { @@ -53,6 +56,7 @@ public class User implements MongoSerialisable { dbObject.put("cpu", cpu.mongoSerialise()); dbObject.put("password", password); dbObject.put("moderator", moderator); + dbObject.put("stats", stats.mongoSerialise()); return dbObject; @@ -65,6 +69,7 @@ public class User implements MongoSerialisable { user.userCode = (String) obj.get("code"); user.password = (String) obj.get("password"); user.moderator = (boolean) obj.get("moderator"); + user.stats = new UserStats((BasicDBObject) obj.get("stats")); user.getControlledUnit().setParent(user); @@ -72,7 +77,6 @@ public class User implements MongoSerialisable { return user; } - //---- public String getUserCode() { return userCode; @@ -133,4 +137,8 @@ public class User implements MongoSerialisable { public void setModerator(boolean moderator) { this.moderator = moderator; } + + public UserStats getStats() { + return stats; + } } diff --git a/Server/src/main/java/net/simon987/server/user/UserManager.java b/Server/src/main/java/net/simon987/server/user/UserManager.java index 5369e9f..cf3dcc2 100644 --- a/Server/src/main/java/net/simon987/server/user/UserManager.java +++ b/Server/src/main/java/net/simon987/server/user/UserManager.java @@ -1,8 +1,10 @@ package net.simon987.server.user; -import com.mongodb.*; +import com.mongodb.BasicDBObject; +import com.mongodb.DBCollection; +import com.mongodb.DBCursor; +import com.mongodb.DBObject; import net.simon987.server.GameServer; -import net.simon987.server.ServerConfiguration; import net.simon987.server.assembly.exception.CancelledException; import net.simon987.server.crypto.RandomStringGenerator; import net.simon987.server.logging.LogManager; @@ -12,14 +14,11 @@ import java.util.ArrayList; public class UserManager { - private MongoClient mongo; private DBCollection userCollection; - public UserManager(MongoClient mongo, ServerConfiguration config) { + public UserManager(DBCollection userCollection) { - this.mongo = mongo; - DB db = mongo.getDB(config.getString("mongo_dbname")); - userCollection = db.getCollection("user"); + this.userCollection = userCollection; } /** diff --git a/Server/src/main/java/net/simon987/server/user/UserStats.java b/Server/src/main/java/net/simon987/server/user/UserStats.java new file mode 100644 index 0000000..eaf6ea3 --- /dev/null +++ b/Server/src/main/java/net/simon987/server/user/UserStats.java @@ -0,0 +1,98 @@ +package net.simon987.server.user; + +import com.mongodb.BasicDBList; +import com.mongodb.BasicDBObject; +import net.simon987.server.io.MongoSerialisable; +import net.simon987.server.logging.LogManager; + +public class UserStats implements MongoSerialisable { + + private BasicDBObject stats; + + public UserStats() { + this.stats = new BasicDBObject(); + } + + public UserStats(BasicDBObject stats) { + this.stats = stats; + } + + @Override + public BasicDBObject mongoSerialise() { + + return stats; + } + + /** + * Increment a stat n times + * + * @param name Name of the stat to increment + * @param count Number of time to increment + */ + public void incrementStat(String name, int count) { + + stats.putIfAbsent(name, 0); + stats.put(name, stats.getInt(name) + count); + } + + /** + * Set the value of a stat + * + * @param name Name of the stat + * @param value new value + */ + public void setInt(String name, int value) { + + stats.put(name, value); + } + + /** + * Get the value of at stat + * + * @param name Name of the value + * @return The value of the stat. Returns 0 if not found + */ + public int getInt(String name) { + + return stats.getInt(name, 0); + } + + /** + * Add an string item to a set + * + * @param name Name of the stat + * @param value Value to add to the set + */ + public void addToStringSet(String name, String value) { + + stats.putIfAbsent(name, new BasicDBList()); + + try { + ((BasicDBList) stats.get(name)).add(value); + } catch (ClassCastException e) { + LogManager.LOGGER.severe("UserStats: cannot add to list because stat already exists and is not a list"); + } + } + + /** + * Remove an item from a set + * + * @param name Name of the stat + * @param value Value to remove from the set + * @return true if the list contained the item + */ + public boolean removeFromSet(String name, String value) { + + if (stats.putIfAbsent(name, new BasicDBList()) != null) { + return ((BasicDBList) stats.get(name)).remove(value); + } + + return false; + } + + public BasicDBList getSet(String name) { + stats.putIfAbsent(name, new BasicDBList()); + + return (BasicDBList) stats.get(name); + } +} diff --git a/Server/src/main/java/net/simon987/server/user/UserStatsHelper.java b/Server/src/main/java/net/simon987/server/user/UserStatsHelper.java new file mode 100644 index 0000000..598d61f --- /dev/null +++ b/Server/src/main/java/net/simon987/server/user/UserStatsHelper.java @@ -0,0 +1,82 @@ +package net.simon987.server.user; + +import com.mongodb.*; +import net.simon987.server.GameServer; + +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.Map; + +/** + * Retrieve user stats in a structured fashion + */ +public class UserStatsHelper { + + /** + * Database collection of users + */ + private DBCollection users; + + /** + * @param users Database collection of users + */ + public UserStatsHelper(DBCollection users) { + this.users = users; + } + + /** + * Get top n players along with their stat value, in descending order + * + * @param statName Name of the stat + * @param n Maximum number of players + * @return Top n players, in User,value format, in descending order + */ + public ArrayList> getTopN(String statName, int n) { + + ArrayList> rows = new ArrayList<>(); + + BasicDBObject orderBy = new BasicDBObject("$stats." + statName, -1); + DBCursor cursor = users.find().sort(orderBy).limit(n); + + while (cursor.hasNext()) { + DBObject dbUser = cursor.next(); + User user = GameServer.INSTANCE.getGameUniverse().getUser((String) dbUser.get("username")); + rows.add(new AbstractMap.SimpleEntry<>(user, user.getStats().getInt(statName))); + } + + return rows; + } + + /** + * Get top n players along with the stat set, in descending order + * + * @param statName Name of the stat + * @param n Maximum number of players + * @return Top n players, in User,set format, in descending order + */ + public ArrayList> getTopNSetLength(String statName, int n) { + + ArrayList> rows = new ArrayList<>(); + + BasicDBList ifNullList = new BasicDBList(); + ifNullList.add("$stats." + statName); + ifNullList.add(new BasicDBList()); + + BasicDBObject project = new BasicDBObject(); + project.put("setLength", new BasicDBObject("$size", new BasicDBObject("$ifNull", ifNullList))); + project.put("username", 1); + + Iterable results = users.aggregate( + new BasicDBObject("$project", project), + new BasicDBObject("$sort", new BasicDBObject("setLength", -1)), + new BasicDBObject("$limit", n) + ).results(); + + for (DBObject dbUser : results) { + User user = GameServer.INSTANCE.getGameUniverse().getUser((String) dbUser.get("username")); + rows.add(new AbstractMap.SimpleEntry<>(user, user.getStats().getSet(statName))); + } + + return rows; + } +} diff --git a/Server/src/main/java/net/simon987/server/web/LeaderBoardPage.java b/Server/src/main/java/net/simon987/server/web/LeaderBoardPage.java index 90022ed..521b383 100644 --- a/Server/src/main/java/net/simon987/server/web/LeaderBoardPage.java +++ b/Server/src/main/java/net/simon987/server/web/LeaderBoardPage.java @@ -1,5 +1,6 @@ package net.simon987.server.web; +import net.simon987.server.GameServer; import spark.ModelAndView; import spark.Request; import spark.Response; @@ -12,9 +13,9 @@ public class LeaderBoardPage implements TemplateViewRoute { @Override public ModelAndView handle(Request request, Response response) { - Map model = new HashMap<>(1); + Map model = new HashMap<>(2); model.put("session", request.session()); - + model.put("stats", GameServer.INSTANCE.getUserStatsHelper().getTopNSetLength("completedVaults", 25)); return new ModelAndView(model, "leaderboard.vm"); } -} +} \ No newline at end of file diff --git a/Server/src/main/resources/templates/leaderboard.vm b/Server/src/main/resources/templates/leaderboard.vm index 9a34d2e..523cbeb 100644 --- a/Server/src/main/resources/templates/leaderboard.vm +++ b/Server/src/main/resources/templates/leaderboard.vm @@ -19,18 +19,12 @@ - - Test1 - Test2 - - - Test1 - Test2 - - - Test1 - Test2 - + #foreach($row in $stats) + + $row.getKey().getUsername() + $row.getValue().size() + + #end