From 4638ba909ded0f7bebb9ef9846b16c43c4358eb6 Mon Sep 17 00:00:00 2001 From: Ben Date: Tue, 15 Mar 2016 22:52:13 +0000 Subject: [PATCH] siege weapon finalizations & analytics (wip) --- .../mineplex/core/common/util/MapBuilder.java | 27 +++++ .../core/common/util/UtilCollections.java | 21 ++++ .../mineplex/core/common/util/UtilFile.java | 1 - .../mineplex/core/common/util/UtilWeb.java | 58 ++++++++++ .../src/mineplex/game/clans/Clans.java | 4 + .../game/clans/analytics/Analytic.java | 37 +++++++ .../game/clans/analytics/AnalyticQueuer.java | 100 ++++++++++++++++++ .../game/clans/analytics/Profiler.java | 69 ++++++++++++ .../game/clans/analytics/Section.java | 36 +++++++ .../src/mineplex/game/clans/clans/Test.java | 15 --- .../game/clans/clans/siege/SiegeManager.java | 20 ++-- .../clans/siege/outpost/OutpostManager.java | 17 +-- .../siege/repository/OutpostRepository.java | 1 + .../clans/clans/siege/weapon/SiegeWeapon.java | 13 ++- .../weapon/projectile/WeaponProjectile.java | 14 ++- 15 files changed, 397 insertions(+), 36 deletions(-) create mode 100644 Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/MapBuilder.java create mode 100644 Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilWeb.java create mode 100644 Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/analytics/Analytic.java create mode 100644 Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/analytics/AnalyticQueuer.java create mode 100644 Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/analytics/Profiler.java create mode 100644 Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/analytics/Section.java delete mode 100644 Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/Test.java diff --git a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/MapBuilder.java b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/MapBuilder.java new file mode 100644 index 000000000..5e54c7e0c --- /dev/null +++ b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/MapBuilder.java @@ -0,0 +1,27 @@ +package mineplex.core.common.util; + +import java.util.HashMap; +import java.util.Map; + +public class MapBuilder +{ + private Map _map; + + public MapBuilder() + { + _map = new HashMap<>(); + } + + public MapBuilder Put(K key, V value) + { + _map.put(key, value); + + return this; + } + + public Map GetMap() + { + return _map; + } + +} diff --git a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilCollections.java b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilCollections.java index 0ffee83ad..d2eef098c 100644 --- a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilCollections.java +++ b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilCollections.java @@ -254,4 +254,25 @@ public class UtilCollections return toList(elements); } + public static String combine(X[] data, String delimiter) + { + StringBuilder total = new StringBuilder(); + + int loops = 0; + + for (X x : data) + { + if (delimiter != null && loops != 0) + { + total.append(delimiter); + } + + total.append(x.toString()); + + loops++; + } + + return total.toString(); + } + } diff --git a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilFile.java b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilFile.java index 1a02a7110..038824e40 100644 --- a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilFile.java +++ b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilFile.java @@ -50,5 +50,4 @@ public class UtilFile return bytes; } - } diff --git a/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilWeb.java b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilWeb.java new file mode 100644 index 000000000..5b45d1913 --- /dev/null +++ b/Plugins/Mineplex.Core.Common/src/mineplex/core/common/util/UtilWeb.java @@ -0,0 +1,58 @@ +package mineplex.core.common.util; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.Reader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLEncoder; +import java.util.Map; + +public class UtilWeb +{ + public static String doPOST(String url, Map params) + { + try + { + StringBuilder postData = new StringBuilder(); + for (Map.Entry param : params.entrySet()) + { + if (postData.length() != 0) + { + postData.append('&'); + } + + postData.append(URLEncoder.encode(param.getKey(), "UTF-8")); + postData.append('='); + postData.append(URLEncoder.encode(String.valueOf(param.getValue()), "UTF-8")); + } + + byte[] postDataBytes = postData.toString().getBytes("UTF-8"); + + HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection(); + conn.setRequestMethod("POST"); + conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); + conn.setRequestProperty("Content-Length", String.valueOf(postDataBytes.length)); + conn.setDoOutput(true); + conn.getOutputStream().write(postDataBytes); + + Reader in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8")); + + StringBuilder back = new StringBuilder(); + + for (int $char; ($char = in.read()) >= 0;) + { + back.append((char) $char); + } + + return back.toString(); + } + catch (Exception exception) + { + exception.printStackTrace(); + + return null; + } + } + +} diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/Clans.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/Clans.java index 8c55b008e..0bcec2523 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/Clans.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/Clans.java @@ -41,6 +41,7 @@ import mineplex.core.teleport.Teleport; import mineplex.core.updater.FileUpdater; import mineplex.core.updater.Updater; import mineplex.core.visibility.VisibilityManager; +import mineplex.game.clans.analytics.Profiler; import mineplex.game.clans.clans.ClansManager; import mineplex.game.clans.clans.ban.ClansBanManager; import mineplex.game.clans.items.GearManager; @@ -65,6 +66,9 @@ public class Clans extends JavaPlugin @Override public void onEnable() { + // Initialize Profiler + new Profiler(); + // Configs getConfig().addDefault(WEB_CONFIG, "http://accounts.mineplex.com/"); getConfig().set(WEB_CONFIG, getConfig().getString(WEB_CONFIG)); diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/analytics/Analytic.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/analytics/Analytic.java new file mode 100644 index 000000000..2b0655bc4 --- /dev/null +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/analytics/Analytic.java @@ -0,0 +1,37 @@ +package mineplex.game.clans.analytics; + +public class Analytic +{ + private long _start; + private long _elapsed; + private String _section; + private String[] _data; + + public Analytic(String section, String[] data, long start, long elapsed) + { + _data = data; + _elapsed = elapsed; + _start = start; + _section = section; + } + + public String[] getData() + { + return _data; + } + + public long getStart() + { + return _start; + } + + public long getElapsed() + { + return _elapsed; + } + + public String getSection() + { + return _section; + } +} diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/analytics/AnalyticQueuer.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/analytics/AnalyticQueuer.java new file mode 100644 index 000000000..c7f43414d --- /dev/null +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/analytics/AnalyticQueuer.java @@ -0,0 +1,100 @@ +package mineplex.game.clans.analytics; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import mineplex.core.common.util.MapBuilder; +import mineplex.core.common.util.UtilCollections; +import mineplex.core.common.util.UtilTime; +import mineplex.core.common.util.UtilWeb; + +public class AnalyticQueuer extends Thread +{ + private List Queue = new ArrayList<>(); + + private ByteArrayOutputStream _bytes; + + private long _lastPush = System.currentTimeMillis(); + + public void Queue(Section section, String[] data) + { + Queue.add(new Analytic(section.getSection(), data, section.getStart(), section.getElapsed())); + } + + private void write(Analytic analytic) + { + try ( + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + DataOutputStream out = new DataOutputStream(stream); + ) + { + + out.writeLong(analytic.getStart()); + out.writeLong(analytic.getElapsed()); + + out.writeInt(analytic.getSection().getBytes().length); + out.writeBytes(analytic.getSection()); + + String data = UtilCollections.combine(analytic.getData(), ","); + + out.writeInt(data.length()); + out.writeBytes(data); + + _bytes.write(stream.toByteArray()); + } + catch (Exception exception) + { + exception.printStackTrace(); + } + } + + public void run() + { + while (true) + { + Iterator iterator = Queue.iterator(); + + while (iterator.hasNext()) + { + Analytic analytic = iterator.next(); + + write(analytic); + + iterator.remove(); + } + + + if (UtilTime.elapsed(_lastPush, 10000)) + { + String response = UtilWeb.doPOST("http://analytics.garblox.com/PushAnalyticData", + new MapBuilder() + .Put("authkey", Profiler.ANALYTICS_KEY) + .Put("service", "ClansBeta") + .Put("data", _bytes.toString()) + .GetMap() + ); + + _bytes.reset(); + + if (!response.equals("OK")) + { + System.out.println("[Clans Beta] Error while pushing analytic data to garblox: " + response); + } + } + + try + { + Thread.sleep(250); + } + catch (Exception exception) + { + exception.printStackTrace(); + } + } + } + +} diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/analytics/Profiler.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/analytics/Profiler.java new file mode 100644 index 000000000..9d43c5df4 --- /dev/null +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/analytics/Profiler.java @@ -0,0 +1,69 @@ +package mineplex.game.clans.analytics; + +import java.io.File; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Stack; + +import mineplex.core.common.util.MapBuilder; +import mineplex.core.common.util.UtilFile; +import mineplex.core.common.util.UtilServer; +import mineplex.core.common.util.UtilWeb; + +public class Profiler +{ + public static final String ANALYTICS_KEY; + + public static Profiler Instance; + + private Map> _sections = new HashMap<>(); + + private AnalyticQueuer _queuer; + + static + { + ANALYTICS_KEY = UtilFile.read(new File(UtilServer.getServer().getWorldContainer() + "/GarbloxAnalyticsKey")); + } + + public Profiler() + { + _queuer = new AnalyticQueuer(); + _queuer.start(); + + String response = UtilWeb.doPOST("http://analytics.garblox.com/RegisterAnalytics", + new MapBuilder() + .Put("authkey", Profiler.ANALYTICS_KEY) + .Put("name", "ClansBeta") + .GetMap() + ); + + if (!response.equals("OK")) + { + System.out.println("[Clans Beta Analytics] Error while registering new analytic type: " + response); + } + + Instance = this; + } + + public void start(String section) + { + Thread thread = Thread.currentThread(); + + if (_sections.get(thread) == null) + { + _sections.put(thread, new Stack<>()); + } + + _sections.get(thread).push(new Section(section, System.currentTimeMillis(), thread)); + } + + public void end(String... data) + { + Thread thread = Thread.currentThread(); + + Section section = _sections.get(thread).pop(); + + _queuer.Queue(section, data); + } +} diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/analytics/Section.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/analytics/Section.java new file mode 100644 index 000000000..143457b59 --- /dev/null +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/analytics/Section.java @@ -0,0 +1,36 @@ +package mineplex.game.clans.analytics; + +public class Section +{ + private String _section; + private long _start; + private Thread _thread; + + public Section(String section, long start, Thread thread) + { + _section = section; + _start = start; + _thread = thread; + } + + public String getSection() + { + return _section; + } + + public long getStart() + { + return _start; + } + + public long getElapsed() + { + return System.currentTimeMillis() - _start; + } + + public Thread getThread() + { + return _thread; + } + +} diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/Test.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/Test.java deleted file mode 100644 index 96de74f98..000000000 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/Test.java +++ /dev/null @@ -1,15 +0,0 @@ -package mineplex.game.clans.clans; - -import java.io.File; -import java.io.IOException; - -import mineplex.core.common.util.UtilOfflinePlayer; - -public class Test -{ - public static void main(String[] args) throws IOException - { - System.out.println("wtf"); - UtilOfflinePlayer.loadOfflineInventory(new File("M:/Clans/a797d3ef-dd25-4e18-a002-6537b19b3603.dat")); - } -} diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/SiegeManager.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/SiegeManager.java index 2331fe7fc..386f66b06 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/SiegeManager.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/SiegeManager.java @@ -22,6 +22,7 @@ import mineplex.core.common.util.UtilServer; import mineplex.core.common.util.UtilTime; import mineplex.core.updater.UpdateType; import mineplex.core.updater.event.UpdateEvent; +import mineplex.game.clans.analytics.Profiler; import mineplex.game.clans.clans.ClansManager; import mineplex.game.clans.clans.siege.commands.CommandSiegeSupplies; import mineplex.game.clans.clans.siege.outpost.OutpostManager; @@ -132,6 +133,7 @@ public class SiegeManager extends MiniPlugin _outpostManager.saveOutposts(); saveSiegeWeapons(); + Profiler.Instance.start("SiegeManager.CleanupEntities"); for (Entity entity : Spawn.getSpawnWorld().getEntitiesByClass(ArmorStand.class)) { boolean part = false; @@ -160,6 +162,7 @@ public class SiegeManager extends MiniPlugin } } } + Profiler.Instance.end(); } } @@ -176,24 +179,27 @@ public class SiegeManager extends MiniPlugin }); } + runAsync(() -> { + Profiler.Instance.start("SiegeManager.CleanupEntities"); + while (!queue.isEmpty()) { queue.pop().run(); } - }); - - runAsync(() -> - _repository.getWeaponsByServer(_clansManager.getServerId(), tokens -> + + _repository.getWeaponsByServer(_clansManager.getServerId(), tokens -> { tokens.forEach(token -> { if (!LiveSiegeWeapons.containsKey(Integer.valueOf(token.UniqueId))) { System.out.println("LiveSiegeWeapons no longer contains old weapon " + token.UniqueId + ", deleting."); _repository.deleteWeapon(token.UniqueId); } - }) - ) - ); + }); + }); + + Profiler.Instance.end(); + }); } @EventHandler diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/outpost/OutpostManager.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/outpost/OutpostManager.java index d142caa75..c73b9705e 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/outpost/OutpostManager.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/outpost/OutpostManager.java @@ -27,6 +27,7 @@ import mineplex.core.common.util.UtilMath; import mineplex.core.common.util.UtilPlayer; import mineplex.core.updater.UpdateType; import mineplex.core.updater.event.UpdateEvent; +import mineplex.game.clans.analytics.Profiler; import mineplex.game.clans.clans.ClanInfo; import mineplex.game.clans.clans.ClansBlacklist; import mineplex.game.clans.clans.ClansManager; @@ -294,21 +295,23 @@ public class OutpostManager extends MiniPlugin }); runAsync(() -> { + Profiler.Instance.start("OutpostManager.UpdateOutposts"); + while (!queue.isEmpty()) queue.pop().run(); - }); - - runAsync(() -> - _repository.getOutpostsByServer(_clansManager.getServerId(), tokens -> + + _repository.getOutpostsByServer(_clansManager.getServerId(), tokens -> { tokens.forEach(token -> { if (!_idToOutpost.containsKey(Integer.valueOf(token.UniqueId))) { System.out.println("[OUTPOSTS] OUTPOST [" + token.UniqueId + "] NO LONGER EXISTS, DELETING"); _repository.deleteOutpost(token.UniqueId); } - }) - ) - ); + }); + }); + + Profiler.Instance.end(); + }); } public OutpostRepository getRepository() diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/repository/OutpostRepository.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/repository/OutpostRepository.java index 4eb471c1c..b3546a110 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/repository/OutpostRepository.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/repository/OutpostRepository.java @@ -12,6 +12,7 @@ import com.google.common.collect.Lists; import mineplex.core.common.util.Callback; import mineplex.core.common.util.UtilWorld; import mineplex.core.database.MinecraftRepository; +import mineplex.game.clans.analytics.Profiler; import mineplex.game.clans.clans.ClanInfo; import mineplex.game.clans.clans.siege.outpost.OutpostManager; import mineplex.game.clans.clans.siege.outpost.OutpostState; diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/weapon/SiegeWeapon.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/weapon/SiegeWeapon.java index 178cf8962..e1868b309 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/weapon/SiegeWeapon.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/weapon/SiegeWeapon.java @@ -18,6 +18,7 @@ import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.inventory.ClickType; import org.bukkit.event.inventory.InventoryCloseEvent; import org.bukkit.event.player.PlayerArmorStandManipulateEvent; import org.bukkit.event.player.PlayerInteractAtEntityEvent; @@ -152,6 +153,16 @@ public abstract class SiegeWeapon implements Listener _infoHologram = new Hologram(ClansManager.getInstance().getHologramManager(), _location.clone().add(.5, 3, .5), _name + " Health", getDisplayHealth()); _infoHologram.start(); + _infoHologram.setInteraction((player, type) -> { + if (player.equals(_rider)) + { + if (type.equals(ClickType.RIGHT)) + { + handleLeftClick(player); + } + } + }); + UtilServer.RegisterEvents(this); _clans = clansManager; @@ -478,7 +489,7 @@ public abstract class SiegeWeapon implements Listener new Hologram( _siegeManager.getClansManager().getHologramManager(), - _location.add(UtilMath.random(-1, 1),1.4, UtilMath.random(-1, 1)), + _location.clone().add(UtilMath.random(-1, 1),1.4, UtilMath.random(-1, 1)), 3500l, C.cRed + "-" + health) .start(); diff --git a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/weapon/projectile/WeaponProjectile.java b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/weapon/projectile/WeaponProjectile.java index 7133afae7..687d54b93 100644 --- a/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/weapon/projectile/WeaponProjectile.java +++ b/Plugins/Mineplex.Game.Clans/src/mineplex/game/clans/clans/siege/weapon/projectile/WeaponProjectile.java @@ -53,13 +53,9 @@ public class WeaponProjectile implements Listener @EventHandler(priority = EventPriority.HIGHEST) public void onTntExplode(EntityExplodeEvent event) { - if (!_attributes._isPrimedTnt) - { - return; - } - if (event.getEntity().equals(_projectileEntity)) { + ((TNTPrimed) event.getEntity()).setFuseTicks(60); event.setCancelled(true); } } @@ -82,12 +78,20 @@ public class WeaponProjectile implements Listener return; } + if (_projectileEntity.isDead()) + { + die(); + return; + } + if (_dead || _projectileEntity == null) { die(); return; } + ((TNTPrimed) _projectileEntity).setFuseTicks(60); + if ((Math.abs(_projectileEntity.getVelocity().getX()) < 0.01 || Math.abs(_projectileEntity.getVelocity().getZ()) < 0.01) && UtilBlock.getInRadius(_projectileEntity.getLocation(), 2)