* This was added as a security measure against unwanted MySQL snooping.
*
* @author Rsl1122
*/
-public class BungeeSetupToggleCommand extends SubCommand {
+public class BungeeSetupToggleCommand extends CommandNode {
public BungeeSetupToggleCommand() {
- super("setup", CommandType.ALL, Permissions.MANAGE.getPermission(), "Toggle Setup mode for Bungee");
+ super("setup", Permissions.MANAGE.getPermission(), CommandType.ALL);
+ setShortHelp("Toggle Setup mode for Bungee");
}
@Override
- public boolean onCommand(ISender sender, String s, String[] strings) {
+ public void onCommand(ISender sender, String s, String[] strings) {
boolean setupAllowed = ConnectionSystem.isSetupAllowed();
ConnectionSystem connectionSystem = ConnectionSystem.getInstance();
@@ -35,6 +36,5 @@ public class BungeeSetupToggleCommand extends SubCommand {
}
String msg = !setupAllowed ? "§aSet-up is now Allowed" : "§cSet-up is now Forbidden";
sender.sendMessage(msg);
- return true;
}
}
\ No newline at end of file
diff --git a/Plan/src/main/java/com/djrapitops/plan/command/commands/DevCommand.java b/Plan/src/main/java/com/djrapitops/plan/command/commands/DevCommand.java
index 7021b997e..16b15247f 100644
--- a/Plan/src/main/java/com/djrapitops/plan/command/commands/DevCommand.java
+++ b/Plan/src/main/java/com/djrapitops/plan/command/commands/DevCommand.java
@@ -8,25 +8,27 @@ import com.djrapitops.plan.system.info.connection.ConnectionSystem;
import com.djrapitops.plan.system.settings.locale.Locale;
import com.djrapitops.plan.system.settings.locale.Msg;
import com.djrapitops.plan.utilities.Condition;
+import com.djrapitops.plugin.command.CommandNode;
import com.djrapitops.plugin.command.CommandType;
import com.djrapitops.plugin.command.ISender;
-import com.djrapitops.plugin.command.SubCommand;
/**
* Command used for testing functions that are too difficult to unit test.
*
* @author Rsl1122
*/
-public class DevCommand extends SubCommand {
+public class DevCommand extends CommandNode {
public DevCommand() {
- super("dev", CommandType.PLAYER_OR_ARGS, "plan.*", "Test Plugin functions not testable with unit tests.", "
@@ -27,27 +29,22 @@ import com.djrapitops.plugin.task.RunnableFactory;
* @author Rsl1122
* @since 3.5.2
*/
-public class RegisterCommand extends SubCommand {
+public class RegisterCommand extends CommandNode {
public RegisterCommand() {
- super("register",
- CommandType.PLAYER_OR_ARGS,
- "", // No Permission Requirement
- Locale.get(Msg.CMD_USG_WEB_REGISTER).toString(),
- "
+ * Additional Listener calls in SpongePlayerListener to avoid having HIGHEST priority listeners.
+ *
+ * @author Rsl1122
+ * @see SpongePlayerListener
+ */
+public class SpongeAFKListener {
+
+ // Static so that /reload does not cause afk tracking to fail.
+ public static final AFKTracker AFK_TRACKER = new AFKTracker();
+
+ private void event(TargetPlayerEvent event) {
+ try {
+ UUID uuid = event.getTargetEntity().getUniqueId();
+ long time = MiscUtils.getTime();
+
+ AFK_TRACKER.performedAction(uuid, time);
+ } catch (Exception e) {
+ Log.toLog(this.getClass(), e);
+ }
+ }
+
+ @Listener(order = Order.POST)
+ public void onMove(MoveEntityEvent event, @First Player player) {
+ UUID uuid = player.getUniqueId();
+ long time = MiscUtils.getTime();
+ AFK_TRACKER.performedAction(uuid, time);
+ }
+
+ @Listener(order = Order.POST)
+ public void onPlayerChat(MessageChannelEvent.Chat event, @First Player player) {
+ UUID uuid = player.getUniqueId();
+ long time = MiscUtils.getTime();
+ AFK_TRACKER.performedAction(uuid, time);
+ }
+
+ @Listener(order = Order.POST)
+ public void onPlayerCommand(SendCommandEvent event, @First Player player) {
+ UUID uuid = player.getUniqueId();
+ long time = MiscUtils.getTime();
+ AFK_TRACKER.performedAction(uuid, time);
+ }
+
+ @Listener(order = Order.POST)
+ public void onSettingsChange(PlayerChangeClientSettingsEvent event) {
+ event(event);
+ }
+
+}
\ No newline at end of file
diff --git a/Plan/src/main/java/com/djrapitops/plan/system/listeners/sponge/SpongeChatListener.java b/Plan/src/main/java/com/djrapitops/plan/system/listeners/sponge/SpongeChatListener.java
new file mode 100644
index 000000000..c3f7f56af
--- /dev/null
+++ b/Plan/src/main/java/com/djrapitops/plan/system/listeners/sponge/SpongeChatListener.java
@@ -0,0 +1,48 @@
+package com.djrapitops.plan.system.listeners.sponge;
+
+import com.djrapitops.plan.system.cache.SessionCache;
+import com.djrapitops.plan.system.processing.Processing;
+import com.djrapitops.plan.system.processing.processors.player.NameProcessor;
+import com.djrapitops.plugin.api.utility.log.Log;
+import org.spongepowered.api.entity.living.player.Player;
+import org.spongepowered.api.event.Listener;
+import org.spongepowered.api.event.Order;
+import org.spongepowered.api.event.filter.cause.First;
+import org.spongepowered.api.event.message.MessageChannelEvent;
+
+import java.util.UUID;
+
+/**
+ * Listener that keeps track of player display name.
+ *
+ * @author Rsl1122
+ */
+public class SpongeChatListener {
+
+ @Listener(order = Order.POST)
+ public void onPlayerChat(MessageChannelEvent.Chat event, @First Player player) {
+ if (event.isCancelled()) {
+ return;
+ }
+
+ try {
+ actOnChatEvent(player);
+ } catch (Exception e) {
+ Log.toLog(this.getClass(), e);
+ }
+ }
+
+ private void actOnChatEvent(@First Player player) {
+ UUID uuid = player.getUniqueId();
+ String name = player.getName();
+ String displayName = player.getDisplayNameData().displayName().get().toPlain();
+
+ SessionCache sessionCache = SessionCache.getInstance();
+ if (sessionCache.isFirstSession(uuid)) {
+ sessionCache.firstSessionMessageSent(uuid);
+ }
+
+ Processing.submit(new NameProcessor(uuid, name, displayName));
+ }
+
+}
\ No newline at end of file
diff --git a/Plan/src/main/java/com/djrapitops/plan/system/listeners/sponge/SpongeCommandListener.java b/Plan/src/main/java/com/djrapitops/plan/system/listeners/sponge/SpongeCommandListener.java
new file mode 100644
index 000000000..1eccd3774
--- /dev/null
+++ b/Plan/src/main/java/com/djrapitops/plan/system/listeners/sponge/SpongeCommandListener.java
@@ -0,0 +1,57 @@
+package com.djrapitops.plan.system.listeners.sponge;
+
+import com.djrapitops.plan.system.processing.Processing;
+import com.djrapitops.plan.system.processing.processors.CommandProcessor;
+import com.djrapitops.plan.system.settings.Permissions;
+import com.djrapitops.plan.system.settings.Settings;
+import com.djrapitops.plugin.api.utility.log.Log;
+import org.spongepowered.api.Sponge;
+import org.spongepowered.api.command.CommandMapping;
+import org.spongepowered.api.entity.living.player.Player;
+import org.spongepowered.api.event.Listener;
+import org.spongepowered.api.event.Order;
+import org.spongepowered.api.event.command.SendCommandEvent;
+import org.spongepowered.api.event.filter.cause.First;
+
+import java.util.Optional;
+
+/**
+ * Listener that keeps track of used commands.
+ *
+ * @author Rsl1122
+ */
+public class SpongeCommandListener {
+
+ @Listener(order = Order.POST)
+ public void onPlayerCommand(SendCommandEvent event, @First Player player) {
+ boolean hasIgnorePermission = player.hasPermission(Permissions.IGNORE_COMMANDUSE.getPermission());
+ if (event.isCancelled() || hasIgnorePermission) {
+ return;
+ }
+ try {
+ actOnCommandEvent(event);
+ } catch (Exception e) {
+ Log.toLog(this.getClass(), e);
+ }
+ }
+
+ private void actOnCommandEvent(SendCommandEvent event) {
+ String commandName = event.getCommand();
+
+ boolean logUnknownCommands = Settings.LOG_UNKNOWN_COMMANDS.isTrue();
+ boolean combineCommandAliases = Settings.COMBINE_COMMAND_ALIASES.isTrue();
+
+ if (!logUnknownCommands || combineCommandAliases) {
+ Optional extends CommandMapping> existingCommand = Sponge.getCommandManager().get(commandName);
+ if (!existingCommand.isPresent()) {
+ if (!logUnknownCommands) {
+ return;
+ }
+ } else if (combineCommandAliases) {
+ commandName = existingCommand.get().getPrimaryAlias();
+ }
+ }
+ Processing.submit(new CommandProcessor(commandName));
+ }
+
+}
\ No newline at end of file
diff --git a/Plan/src/main/java/com/djrapitops/plan/system/listeners/sponge/SpongeDeathListener.java b/Plan/src/main/java/com/djrapitops/plan/system/listeners/sponge/SpongeDeathListener.java
new file mode 100644
index 000000000..43aa426ed
--- /dev/null
+++ b/Plan/src/main/java/com/djrapitops/plan/system/listeners/sponge/SpongeDeathListener.java
@@ -0,0 +1,131 @@
+package com.djrapitops.plan.system.listeners.sponge;
+
+import com.djrapitops.plan.data.container.Session;
+import com.djrapitops.plan.system.cache.SessionCache;
+import com.djrapitops.plan.system.processing.Processing;
+import com.djrapitops.plan.system.processing.processors.player.SpongeKillProcessor;
+import com.djrapitops.plan.utilities.MiscUtils;
+import com.djrapitops.plugin.api.utility.log.Log;
+import com.djrapitops.plugin.utilities.Format;
+import org.spongepowered.api.data.key.Keys;
+import org.spongepowered.api.data.type.HandTypes;
+import org.spongepowered.api.entity.Entity;
+import org.spongepowered.api.entity.living.Living;
+import org.spongepowered.api.entity.living.animal.Wolf;
+import org.spongepowered.api.entity.living.player.Player;
+import org.spongepowered.api.entity.projectile.arrow.Arrow;
+import org.spongepowered.api.entity.projectile.source.ProjectileSource;
+import org.spongepowered.api.event.Listener;
+import org.spongepowered.api.event.cause.entity.damage.source.EntityDamageSource;
+import org.spongepowered.api.event.entity.DestructEntityEvent;
+import org.spongepowered.api.item.ItemType;
+import org.spongepowered.api.item.ItemTypes;
+import org.spongepowered.api.item.inventory.ItemStack;
+
+import java.util.Optional;
+import java.util.UUID;
+
+/**
+ * Listener for Deaths and Kills on Sponge.
+ *
+ * @author Rsl1122
+ */
+public class SpongeDeathListener {
+
+ @Listener
+ public void onEntityDeath(DestructEntityEvent.Death event) {
+ long time = MiscUtils.getTime();
+ Living dead = event.getTargetEntity();
+
+ if (dead instanceof Player) {
+ // Process Death
+ Processing.submitCritical(() -> SessionCache.getCachedSession(dead.getUniqueId()).ifPresent(Session::died));
+ }
+
+ try {
+ Optional
+ * Adds PlayerKill or a Mob kill to the active Session.
+ *
+ * @author Rsl1122
+ * @since 4.3.0
+ */
+public class SpongeKillProcessor implements CriticalRunnable {
+
+ private final UUID uuid;
+ private final UUID deadUUID;
+ private final String weaponName;
+ private final long time;
+
+ /**
+ * Constructor.
+ *
+ * @param uuid UUID of the killer.
+ * @param time Epoch ms the event occurred.
+ * @param deadUUID Dead entity (Mob or Player)
+ * @param weaponName Weapon used.
+ */
+ public SpongeKillProcessor(UUID uuid, long time, UUID deadUUID, String weaponName) {
+ this.uuid = uuid;
+ this.time = time;
+ this.deadUUID = deadUUID;
+ this.weaponName = weaponName;
+ }
+
+ @Override
+ public void run() {
+ Optional
+ * Does not perform update on force close.
+ *
+ * @author Rsl1122
+ */
+public class ShutdownUpdateHook extends Thread {
+
+ private static boolean activated = false;
+ private static File newJar;
+
+ private static Set
+ * API#addPluginDataSource uses the same method from HookHandler.
+ *
+ * @param hookH HookHandler instance for registering the data sources.
+ */
+ public PlaceholderAPIHook(HookHandler hookH) {
+ super("me.clip.placeholderapi.PlaceholderAPI", hookH);
+ }
+
+ public void hook() throws NoClassDefFoundError {
+ if (enabled) {
+ PlaceholderAPI.unregisterPlaceholderHook("plan");
+ PlaceholderAPI.registerPlaceholderHook("plan", new PlanPlaceholders());
+ }
+ }
+}
diff --git a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/placeholderapi/PlanPlaceholders.java b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/placeholderapi/PlanPlaceholders.java
new file mode 100644
index 000000000..3f0f576fd
--- /dev/null
+++ b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/placeholderapi/PlanPlaceholders.java
@@ -0,0 +1,190 @@
+package com.djrapitops.pluginbridge.plan.placeholderapi;
+
+import com.djrapitops.plan.PlanPlugin;
+import com.djrapitops.plan.data.PlayerProfile;
+import com.djrapitops.plan.data.ServerProfile;
+import com.djrapitops.plan.data.calculation.ActivityIndex;
+import com.djrapitops.plan.data.container.TPS;
+import com.djrapitops.plan.system.PlanSystem;
+import com.djrapitops.plan.system.database.databases.Database;
+import com.djrapitops.plan.utilities.FormatUtils;
+import com.djrapitops.plan.utilities.MiscUtils;
+import com.djrapitops.plan.utilities.analysis.Analysis;
+import com.djrapitops.plan.utilities.analysis.MathUtils;
+import com.djrapitops.plugin.api.TimeAmount;
+import com.djrapitops.plugin.api.utility.log.Log;
+import me.clip.placeholderapi.expansion.PlaceholderExpansion;
+import org.bukkit.entity.Player;
+
+import java.io.Serializable;
+import java.util.Optional;
+import java.util.UUID;
+import java.util.concurrent.Callable;
+import java.util.stream.Collectors;
+
+/**
+ * Placeholders of Plan.
+ *
+ * @author Rsl1122
+ */
+public class PlanPlaceholders extends PlaceholderExpansion {
+
+ private final PlanPlugin plugin;
+
+ public PlanPlaceholders() {
+ plugin = PlanPlugin.getInstance();
+ }
+
+ @Override
+ public String getIdentifier() {
+ return "plan";
+ }
+
+ @Override
+ public String getPlugin() {
+ return "Plan";
+ }
+
+ @Override
+ public String getAuthor() {
+ return "Rsl1122";
+ }
+
+ @Override
+ public String getVersion() {
+ return plugin.getVersion();
+ }
+
+ @Override
+ public String onPlaceholderRequest(Player player, String identifier) {
+ Serializable planValue = getPlanValue(identifier);
+ if (planValue != null) {
+ return planValue.toString();
+ }
+ Serializable serverValue = getServerValue(identifier);
+ if (serverValue != null) {
+ return serverValue.toString();
+ }
+
+ if (player != null) {
+ Serializable playerValue = getPlayerValue(player, identifier);
+ if (playerValue != null) {
+ return playerValue.toString();
+ }
+ }
+
+ return null;
+ }
+
+ private Serializable getPlanValue(String identifier) {
+ switch (identifier.toLowerCase()) {
+ case "address":
+ return PlanSystem.getInstance().getWebServerSystem().getWebServer().getAccessAddress();
+ case "analysis_refresh":
+ Optional