diff --git a/PlanPluginBridge/pom.xml b/PlanPluginBridge/pom.xml
index 782e69645..896e2dec9 100644
--- a/PlanPluginBridge/pom.xml
+++ b/PlanPluginBridge/pom.xml
@@ -111,6 +111,36 @@
1.1.1
provided
+
+ org.kingdoms
+ kingdoms_demo
+ 13.3.40
+ provided
+
+
+ me.confuser
+ banmanager
+ 5.15.0
+ provided
+
+
+
+
+
+
+
+
+ com.github.ProtocolSupport
+ ProtocolSupport
+ 4.28
+ provided
+
+
+ br.net.fabiozumbi12.RedProtect
+ RedProtect
+ 7.3.0
+ provided
+
diff --git a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/Bridge.java b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/Bridge.java
index 599889f3d..a2602a980 100644
--- a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/Bridge.java
+++ b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/Bridge.java
@@ -9,6 +9,7 @@ import com.djrapitops.pluginbridge.plan.griefprevention.GriefPreventionHook;
import com.djrapitops.pluginbridge.plan.jobs.JobsHook;
import com.djrapitops.pluginbridge.plan.litebans.LiteBansHook;
import com.djrapitops.pluginbridge.plan.mcmmo.McmmoHook;
+import com.djrapitops.pluginbridge.plan.protocolsupport.ProtocolSupportHook;
import com.djrapitops.pluginbridge.plan.superbvote.SuperbVoteHook;
import com.djrapitops.pluginbridge.plan.towny.TownyHook;
import com.djrapitops.pluginbridge.plan.vault.VaultHook;
@@ -26,6 +27,7 @@ import main.java.com.djrapitops.plan.data.additional.HookHandler;
* @see LiteBansHook
* @see McmmoHook
* @see SuperbVoteHook
+ * @see ProtocolSupportHook
* @see TownyHook
* @see VaultHook
* @see ViaVersionHook
@@ -48,6 +50,7 @@ public class Bridge {
new LiteBansHook(h),
new McmmoHook(h),
new SuperbVoteHook(h),
+ new ProtocolSupportHook(h),
new TownyHook(h),
new VaultHook(h),
new ViaVersionHook(h)
diff --git a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/protocolsupport/PlayerVersionListener.java b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/protocolsupport/PlayerVersionListener.java
new file mode 100644
index 000000000..0b3847455
--- /dev/null
+++ b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/protocolsupport/PlayerVersionListener.java
@@ -0,0 +1,54 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.djrapitops.pluginbridge.plan.protocolsupport;
+
+
+import com.djrapitops.plugin.api.utility.log.Log;
+import com.djrapitops.pluginbridge.plan.viaversion.ProtocolTable;
+import main.java.com.djrapitops.plan.Plan;
+import main.java.com.djrapitops.plan.database.databases.SQLDB;
+import main.java.com.djrapitops.plan.systems.processing.Processor;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerJoinEvent;
+import protocolsupport.api.ProtocolSupportAPI;
+import protocolsupport.api.ProtocolVersion;
+
+import java.sql.SQLException;
+import java.util.UUID;
+
+/**
+ * Class responsible for listening join events for Version protocol.
+ *
+ * @author Rsl1122
+ * @since 4.1.0
+ */
+public class PlayerVersionListener implements Listener {
+
+ public PlayerVersionListener() {
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ public void onJoin(PlayerJoinEvent event) {
+ Player player = event.getPlayer();
+ UUID uuid = player.getUniqueId();
+ ProtocolVersion protocolVersion = ProtocolSupportAPI.getProtocolVersion(player);
+ int playerVersion = protocolVersion.getId();
+ Plan plan = Plan.getInstance();
+ plan.addToProcessQueue(new Processor(uuid) {
+ @Override
+ public void process() {
+ try {
+ new ProtocolTable((SQLDB) plan.getDB()).saveProtocolVersion(uuid, playerVersion);
+ } catch (SQLException e) {
+ Log.toLog(this.getClass().getName() + ":PlanViaVersionJoinListener", e);
+ }
+ }
+ });
+ }
+}
diff --git a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/protocolsupport/ProtocolSupportData.java b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/protocolsupport/ProtocolSupportData.java
new file mode 100644
index 000000000..13baab2c0
--- /dev/null
+++ b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/protocolsupport/ProtocolSupportData.java
@@ -0,0 +1,90 @@
+/*
+ * Licence is provided in the jar as license.yml also here:
+ * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml
+ */
+package com.djrapitops.pluginbridge.plan.protocolsupport;
+
+import com.djrapitops.plugin.api.utility.log.Log;
+import com.djrapitops.pluginbridge.plan.viaversion.Protocol;
+import com.djrapitops.pluginbridge.plan.viaversion.ProtocolTable;
+import main.java.com.djrapitops.plan.data.additional.*;
+
+import java.sql.SQLException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+import java.util.stream.Collectors;
+
+/**
+ * PluginData for ProtocolSupport plugin.
+ *
+ * @author Rsl1122
+ */
+public class ProtocolSupportData extends PluginData {
+
+ private final ProtocolTable table;
+
+ public ProtocolSupportData(ProtocolTable table) {
+ super(ContainerSize.THIRD, "ProtocolSupport");
+ super.setPluginIcon("gamepad");
+ super.setIconColor("cyan");
+ this.table = table;
+ }
+
+ @Override
+ public InspectContainer getPlayerData(UUID uuid, InspectContainer inspectContainer) throws Exception {
+ try {
+ int protocolVersion = table.getProtocolVersion(uuid);
+
+ inspectContainer.addValue(getWithIcon("Last Join Version", "signal", "light-green"),
+ protocolVersion != -1 ? Protocol.getMCVersion(protocolVersion) : "Not Yet Known");
+ } catch (SQLException ex) {
+ Log.toLog(this.getClass().getName(), ex);
+ }
+
+ return inspectContainer;
+ }
+
+ @Override
+ public AnalysisContainer getServerData(Collection collection, AnalysisContainer analysisContainer) throws Exception {
+ Map versions;
+
+ try {
+ versions = table.getProtocolVersions();
+ } catch (SQLException ex) {
+ Log.toLog(this.getClass().getName(), ex);
+ return analysisContainer;
+ }
+
+ Map userVersions = versions.entrySet().stream()
+ .collect(Collectors.toMap(Map.Entry::getKey, entry -> Protocol.getMCVersion(entry.getValue())));
+
+ analysisContainer.addPlayerTableValues(getWithIcon("Last Version", "signal"), userVersions);
+
+ String versionS = getWithIcon("Version", "signal");
+ String membersS = getWithIcon("Users", "users");
+ TableContainer versionTable = new TableContainer(versionS, membersS);
+ versionTable.setColor("cyan");
+ Map usersPerVersion = getUsersPerVersion(versions);
+ for (Map.Entry entry : usersPerVersion.entrySet()) {
+ versionTable.addRow(entry.getKey(), entry.getValue());
+ }
+ analysisContainer.addTable("versionTable", versionTable);
+
+ return analysisContainer;
+ }
+
+ private Map getUsersPerVersion(Map versions) {
+ Map usersPerVersion = new HashMap<>();
+
+ for (int protocolVersion : versions.values()) {
+ String mcVer = Protocol.getMCVersion(protocolVersion);
+ if (!usersPerVersion.containsKey(mcVer)) {
+ usersPerVersion.put(mcVer, 0);
+ }
+ usersPerVersion.replace(mcVer, usersPerVersion.get(mcVer) + 1);
+ }
+ return usersPerVersion;
+ }
+}
\ No newline at end of file
diff --git a/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/protocolsupport/ProtocolSupportHook.java b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/protocolsupport/ProtocolSupportHook.java
new file mode 100644
index 000000000..023e01b55
--- /dev/null
+++ b/PlanPluginBridge/src/main/java/com/djrapitops/pluginbridge/plan/protocolsupport/ProtocolSupportHook.java
@@ -0,0 +1,47 @@
+/*
+ * Licence is provided in the jar as license.yml also here:
+ * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml
+ */
+package com.djrapitops.pluginbridge.plan.protocolsupport;
+
+import com.djrapitops.plugin.api.utility.log.Log;
+import com.djrapitops.pluginbridge.plan.Hook;
+import com.djrapitops.pluginbridge.plan.viaversion.ProtocolTable;
+import main.java.com.djrapitops.plan.Plan;
+import main.java.com.djrapitops.plan.api.exceptions.DBCreateTableException;
+import main.java.com.djrapitops.plan.data.additional.HookHandler;
+import main.java.com.djrapitops.plan.database.databases.SQLDB;
+
+/**
+ * Hook for ProtocolSupport plugin.
+ *
+ * @author Rsl1122
+ */
+public class ProtocolSupportHook extends Hook {
+
+ private static PlayerVersionListener listener;
+
+ public ProtocolSupportHook(HookHandler hookHandler) {
+ super("protocolsupport.ProtocolSupport", hookHandler);
+ }
+
+ @Override
+ public void hook() throws NoClassDefFoundError {
+ if (!enabled) {
+ return;
+ }
+ Plan plan = Plan.getInstance();
+ ProtocolTable table = new ProtocolTable((SQLDB) plan.getDB());
+ try {
+ table.createTable();
+ } catch (DBCreateTableException e) {
+ Log.toLog(this.getClass().getName(), e);
+ return;
+ }
+ if (listener == null) {
+ listener = new PlayerVersionListener();
+ plan.registerListener(listener);
+ }
+ addPluginDataSource(new ProtocolSupportData(table));
+ }
+}
\ No newline at end of file