Fixed Plugin sources not registering, standalone plugins tabs

This commit is contained in:
Rsl1122 2017-09-09 14:39:42 +03:00
parent 013f01ccff
commit 7fd3386a47
22 changed files with 240 additions and 94 deletions

View File

@ -9,16 +9,21 @@ import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.api.exceptions.ParseException;
import main.java.com.djrapitops.plan.command.commands.AnalyzeCommand;
import main.java.com.djrapitops.plan.data.AnalysisData;
import main.java.com.djrapitops.plan.data.additional.HookHandler;
import main.java.com.djrapitops.plan.data.additional.PluginData;
import main.java.com.djrapitops.plan.systems.cache.DataCache;
import main.java.com.djrapitops.plan.systems.info.parsing.AnalysisPageParser;
import main.java.com.djrapitops.plan.systems.info.parsing.InspectPageParser;
import main.java.com.djrapitops.plan.systems.processing.Processor;
import main.java.com.djrapitops.plan.systems.webserver.PageCache;
import main.java.com.djrapitops.plan.systems.webserver.response.InspectPageResponse;
import main.java.com.djrapitops.plan.systems.webserver.response.Response;
import main.java.com.djrapitops.plan.utilities.MiscUtils;
import main.java.com.djrapitops.plan.utilities.analysis.Analysis;
import main.java.com.djrapitops.plan.utilities.html.HtmlStructure;
import java.util.Optional;
import java.util.UUID;
import java.io.Serializable;
import java.util.*;
/**
* //TODO Class Javadoc Comment
@ -35,11 +40,13 @@ public class BukkitInformationManager extends InformationManager {
private String analysisPluginsTab;
private Long refreshDate;
private final Map<UUID, String> pluginsTabContents;
public BukkitInformationManager(Plan plugin) {
this.plugin = plugin;
dataCache = new DataCache(plugin);
analysis = new Analysis(plugin);
pluginsTabContents = new HashMap<>();
Optional<String> bungeeConnectionAddress = plugin.getServerInfoManager().getBungeeConnectionAddress();
if (bungeeConnectionAddress.isPresent()) {
@ -60,7 +67,38 @@ public class BukkitInformationManager extends InformationManager {
@Override
public void cachePlayer(UUID uuid) {
PageCache.loadPage("inspectPage: " + uuid, () -> new InspectPageResponse(this, uuid));
// TODO Player page plugin tab request
plugin.addToProcessQueue(new Processor<UUID>(uuid) {
@Override
public void process() {
cacheInspectPluginsTab(object);
}
});
}
public void cacheInspectPluginsTab(UUID uuid) {
if (usingBungeeWebServer) {
// TODO plugin tab request on bungee
}
String serverName = plugin.getServerInfoManager().getServerName();
HookHandler hookHandler = plugin.getHookHandler();
List<PluginData> plugins = hookHandler.getAdditionalDataSources();
Map<String, Serializable> replaceMap = hookHandler.getAdditionalInspectReplaceRules(uuid);
String contents = HtmlStructure.createInspectPageTabContent(serverName, plugins, replaceMap);
cacheInspectPluginsTab(uuid, contents);
}
public void cacheInspectPluginsTab(UUID uuid, String contents) {
pluginsTabContents.put(uuid, contents);
Response inspectResponse = PageCache.loadPage("inspectPage: " + uuid);
if (inspectResponse != null) {
((InspectPageResponse) inspectResponse).setInspectPagePluginsTab(contents);
}
}
@Override
public String getPluginsTabContent(UUID uuid) {
String calculating = HtmlStructure.createInspectPageTabContentCalculating();
return pluginsTabContents.getOrDefault(uuid, calculating);
}
@Override

View File

@ -61,4 +61,9 @@ public class BungeeInformationManager extends InformationManager {
public String getAnalysisHtml() {
return null;
}
@Override
public String getPluginsTabContent(UUID uuid) {
return null;
}
}

View File

@ -72,5 +72,5 @@ public abstract class InformationManager {
analysisNotification.add(sender);
}
public abstract String getPluginsTabContent(UUID uuid);
}

View File

@ -11,8 +11,20 @@ import java.util.UUID;
*/
public class InspectPageResponse extends Response {
private String inspectPagePluginsTab;
public InspectPageResponse(InformationManager infoManager, UUID uuid) {
super.setHeader("HTTP/1.1 200 OK");
super.setContent(Theme.replaceColors(infoManager.getPlayerHtml(uuid)));
setInspectPagePluginsTab(infoManager.getPluginsTabContent(uuid));
}
public void setInspectPagePluginsTab(String inspectPagePluginsTab) {
if (this.inspectPagePluginsTab != null) {
setContent(getContent().replace(this.inspectPagePluginsTab, inspectPagePluginsTab));
} else {
setContent(getContent().replace("${tabContentPlugins}", inspectPagePluginsTab));
}
this.inspectPagePluginsTab = inspectPagePluginsTab;
}
}

View File

@ -14,6 +14,7 @@ import main.java.com.djrapitops.plan.utilities.html.tables.KillsTableCreator;
import org.apache.commons.lang3.text.StrSubstitutor;
import java.io.FileNotFoundException;
import java.io.Serializable;
import java.util.*;
/**
@ -175,7 +176,7 @@ public class HtmlStructure {
return new String[]{html.toString(), viewScript.toString()};
}
public static String createInspectPageTabContent(String serverName, List<PluginData> plugins, Map<String, String> replaceMap) {
public static String createInspectPageTabContent(String serverName, List<PluginData> plugins, Map<String, Serializable> replaceMap) {
if (plugins.isEmpty()) {
return "";
}
@ -344,4 +345,17 @@ public class HtmlStructure {
}
return placeholders;
}
public static String createInspectPageTabContentCalculating() {
StringBuilder html = new StringBuilder();
html.append("<div class=\"row\">")
.append("<div class=\"column\">")
.append("<div class=\"box-header\">")
.append("<h2><i class=\"fa fa-cube\" aria-hidden=\"true\"></i> No Plugins</h2></div>")
.append("<div class=\"box plugin\">")
.append("<p><i class=\"fa fa-refresh fa-spin\" aria-hidden=\"true\"></i> Plugins tab is still being calculated, please refresh the page after a while (F5)</p>")
.append("</div></div>")
.append("</div>");
return html.toString();
}
}

View File

@ -42,7 +42,7 @@
</a>
</div>
<div id="limiter" class="main-limiter">
<div id="main" class="main-wrapper">
<div id="main" class="main-wrapper" style="width: 400%;">
<div id="tab-information" class="tab">
<div class="row">
<div class="column">

View File

@ -1,8 +0,0 @@
<component name="ArtifactManager">
<artifact type="jar" name="PlanPluginBridge-3.6.0">
<output-path>$PROJECT_DIR$/target</output-path>
<root id="archive" name="PlanPluginBridge-3.6.0.jar">
<element id="module-output" name="PlanPluginBridge" />
</root>
</artifact>
</component>

View File

@ -1,9 +1,34 @@
package com.djrapitops.pluginbridge.plan;
import com.djrapitops.pluginbridge.plan.advancedachievements.AdvancedAchievementsHook;
import com.djrapitops.pluginbridge.plan.askyblock.ASkyBlockHook;
import com.djrapitops.pluginbridge.plan.essentials.EssentialsHook;
import com.djrapitops.pluginbridge.plan.factions.FactionsHook;
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.ontime.OnTimeHook;
import com.djrapitops.pluginbridge.plan.superbvote.SuperbVoteHook;
import com.djrapitops.pluginbridge.plan.towny.TownyHook;
import com.djrapitops.pluginbridge.plan.vault.VaultHook;
import com.djrapitops.pluginbridge.plan.viaversion.ViaVersionHook;
import main.java.com.djrapitops.plan.data.additional.HookHandler;
/**
* @author Rsl1122
* @see AdvancedAchievementsHook
* @see EssentialsHook
* @see FactionsHook
* @see GriefPreventionHook
* @see JobsHook
* @see LiteBansHook
* @see McmmoHook
* @see OnTimeHook
* @see SuperbVoteHook
* @see TownyHook
* @see VaultHook
* @see ViaVersionHook
*/
@SuppressWarnings("WeakerAccess")
public class Bridge {
@ -12,17 +37,25 @@ public class Bridge {
throw new IllegalStateException("Utility class");
}
public static void hook(HookHandler handler) {
String[] plugins = new String[]{
"AdvancedAchievements", "Essentials", "Factions", "Mcmmo",
"Jobs", "OnTime", "Towny", "Valut", "ASkyBlock",
"GriefPrevention", "LiteBans", "SuperbVote", "ViaVersion"
public static void hook(HookHandler h) {
Hook[] hooks = new Hook[]{
new AdvancedAchievementsHook(h),
new ASkyBlockHook(h),
new EssentialsHook(h),
new FactionsHook(h),
new GriefPreventionHook(h),
new JobsHook(h),
new LiteBansHook(h),
new McmmoHook(h),
new OnTimeHook(h),
new SuperbVoteHook(h),
new TownyHook(h),
new VaultHook(h),
new ViaVersionHook(h)
};
for (String pluginName : plugins) {
for (Hook hook : hooks) {
try {
String className = "com.djrapitops.pluginbridge.plan." + pluginName + "Hook";
Class<Hook> clazz = (Class<Hook>) Hook.class.forName(className);
clazz.getConstructor(HookHandler.class).newInstance(handler);
hook.hook();
} catch (Exception | NoClassDefFoundError ignore) {
}
}

View File

@ -1,5 +1,7 @@
package com.djrapitops.pluginbridge.plan;
import main.java.com.djrapitops.plan.data.additional.HookHandler;
import main.java.com.djrapitops.plan.data.additional.PluginData;
import org.bukkit.plugin.java.JavaPlugin;
import static org.bukkit.plugin.java.JavaPlugin.getPlugin;
@ -17,6 +19,8 @@ public abstract class Hook {
*/
protected boolean enabled;
protected HookHandler hookHandler;
/**
* Class constructor.
* <p>
@ -24,7 +28,8 @@ public abstract class Hook {
*
* @param plugin Class path string of the plugin's main JavaPlugin class.
*/
public Hook(String plugin) {
public Hook(String plugin, HookHandler hookHandler) {
this.hookHandler = hookHandler;
try {
Class<?> givenClass = Class.forName(plugin);
Class<? extends JavaPlugin> pluginClass = (Class<? extends JavaPlugin>) givenClass;
@ -35,10 +40,16 @@ public abstract class Hook {
}
}
public abstract void hook() throws NoClassDefFoundError;
/**
* Constructor to set enabled to false.
*/
public Hook() {
enabled = false;
}
protected void addPluginDataSource(PluginData pluginData) {
hookHandler.addPluginDataSource(pluginData);
}
}

View File

@ -6,6 +6,7 @@ import com.hm.achievement.api.AdvancedAchievementsAPI;
import com.hm.achievement.api.AdvancedAchievementsBukkitAPI;
import main.java.com.djrapitops.plan.api.API;
import main.java.com.djrapitops.plan.data.additional.HookHandler;
import static org.bukkit.plugin.java.JavaPlugin.getPlugin;
/**
@ -19,21 +20,24 @@ public class AdvancedAchievementsHook extends Hook {
/**
* Hooks the plugin and registers it's PluginData objects.
*
* <p>
* API#addPluginDataSource uses the same method from HookHandler.
*
* @param hookH HookHandler instance for registering the data sources.
* @see API
* @throws NoClassDefFoundError when the plugin class can not be found.
* @see API
*/
public AdvancedAchievementsHook(HookHandler hookH) throws NoClassDefFoundError {
super("com.hm.achievement.AdvancedAchievements");
public AdvancedAchievementsHook(HookHandler hookH) {
super("com.hm.achievement.AdvancedAchievements", hookH);
}
public void hook() throws NoClassDefFoundError {
if (enabled) {
AdvancedAchievements aa = getPlugin(AdvancedAchievements.class);
if (Integer.parseInt(Character.toString(aa.getDescription().getVersion().charAt(0))) >= 5) {
AdvancedAchievementsAPI aaAPI = AdvancedAchievementsBukkitAPI.linkAdvancedAchievements();
hookH.addPluginDataSource(new AdvancedAchievementsAchievements(aaAPI));
hookH.addPluginDataSource(new AdvancedAchievementsTable(aaAPI));
addPluginDataSource(new AdvancedAchievementsAchievements(aaAPI));
addPluginDataSource(new AdvancedAchievementsTable(aaAPI));
} else {
enabled = false;
}

View File

@ -15,21 +15,24 @@ public class ASkyBlockHook extends Hook {
/**
* Hooks the plugin and registers it's PluginData objects.
*
* <p>
* API#addPluginDataSource uses the same method from HookHandler.
*
* @param hookH HookHandler instance for registering the data sources.
* @see API
* @throws NoClassDefFoundError when the plugin class can not be found.
* @see API
*/
public ASkyBlockHook(HookHandler hookH) throws NoClassDefFoundError {
super("com.wasteofplastic.askyblock.ASkyBlock");
super("com.wasteofplastic.askyblock.ASkyBlock", hookH);
}
public void hook() throws NoClassDefFoundError {
if (enabled) {
ASkyBlockAPI api = ASkyBlockAPI.getInstance();
hookH.addPluginDataSource(new ASkyBlockIslandName(api));
hookH.addPluginDataSource(new ASkyBlockIslandLevel(api));
hookH.addPluginDataSource(new ASkyBlockIslandResets(api));
hookH.addPluginDataSource(new ASkyBlockIslands(api));
addPluginDataSource(new ASkyBlockIslandName(api));
addPluginDataSource(new ASkyBlockIslandLevel(api));
addPluginDataSource(new ASkyBlockIslandResets(api));
addPluginDataSource(new ASkyBlockIslands(api));
}
}
}

View File

@ -4,6 +4,7 @@ import main.java.com.djrapitops.plan.data.additional.HookHandler;
import com.djrapitops.pluginbridge.plan.Hook;
import com.earth2me.essentials.Essentials;
import main.java.com.djrapitops.plan.api.API;
import static org.bukkit.plugin.java.JavaPlugin.getPlugin;
/**
@ -16,20 +17,23 @@ public class EssentialsHook extends Hook {
/**
* Hooks the plugin and registers it's PluginData objects.
*
* <p>
* API#addPluginDataSource uses the same method from HookHandler.
*
* @param hookH HookHandler instance for registering the data sources.
* @see API
* @throws NoClassDefFoundError when the plugin class can not be found.
* @see API
*/
public EssentialsHook(HookHandler hookH) throws NoClassDefFoundError {
super("com.earth2me.essentials.Essentials");
public EssentialsHook(HookHandler hookH) {
super("com.earth2me.essentials.Essentials", hookH);
}
public void hook() throws NoClassDefFoundError {
if (enabled) {
Essentials ess = getPlugin(Essentials.class);
hookH.addPluginDataSource(new EssentialsJailed(ess));
hookH.addPluginDataSource(new EssentialsMuted(ess));
hookH.addPluginDataSource(new EssentialsWarps(ess));
addPluginDataSource(new EssentialsJailed(ess));
addPluginDataSource(new EssentialsMuted(ess));
addPluginDataSource(new EssentialsWarps(ess));
}
}
}

View File

@ -21,12 +21,15 @@ public class FactionsHook extends Hook {
* @see API
*/
public FactionsHook(HookHandler hookH) {
super("com.massivecraft.factions.Factions");
super("com.massivecraft.factions.Factions", hookH);
}
public void hook() throws NoClassDefFoundError {
if (enabled) {
hookH.addPluginDataSource(new FactionsFaction());
hookH.addPluginDataSource(new FactionsPower());
hookH.addPluginDataSource(new FactionsMaxPower());
hookH.addPluginDataSource(new FactionsTable());
addPluginDataSource(new FactionsFaction());
addPluginDataSource(new FactionsPower());
addPluginDataSource(new FactionsMaxPower());
addPluginDataSource(new FactionsTable());
}
}
}

View File

@ -25,15 +25,18 @@ public class GriefPreventionHook extends Hook {
* @see API
* @throws NoClassDefFoundError when the plugin class can not be found.
*/
public GriefPreventionHook(HookHandler hookH) throws NoClassDefFoundError {
super("me.ryanhamshire.GriefPrevention.GriefPrevention");
public GriefPreventionHook(HookHandler hookH) {
super("me.ryanhamshire.GriefPrevention.GriefPrevention", hookH);
}
public void hook() throws NoClassDefFoundError {
if (enabled) {
DataStore dataStore = getPlugin(GriefPrevention.class).dataStore;
hookH.addPluginDataSource(new GriefPreventionClaims(dataStore));
hookH.addPluginDataSource(new GriefPreventionClaimArea(dataStore));
hookH.addPluginDataSource(new GriefPreventionClaimBlocksAvailable(dataStore));
hookH.addPluginDataSource(new GriefPreventionSoftMuted(dataStore));
hookH.addPluginDataSource(new GriefPreventionClaimTable(dataStore));
addPluginDataSource(new GriefPreventionClaims(dataStore));
addPluginDataSource(new GriefPreventionClaimArea(dataStore));
addPluginDataSource(new GriefPreventionClaimBlocksAvailable(dataStore));
addPluginDataSource(new GriefPreventionSoftMuted(dataStore));
addPluginDataSource(new GriefPreventionClaimTable(dataStore));
}
}
}

View File

@ -21,10 +21,13 @@ public class JobsHook extends Hook {
* @see API
*/
public JobsHook(HookHandler hookH) {
super("com.gamingmesh.jobs.Jobs");
super("com.gamingmesh.jobs.Jobs", hookH);
}
public void hook() throws NoClassDefFoundError {
if (enabled) {
hookH.addPluginDataSource(new JobsInspectJobTable());
hookH.addPluginDataSource(new JobsAnalysisJobTable());
addPluginDataSource(new JobsInspectJobTable());
addPluginDataSource(new JobsAnalysisJobTable());
}
}
}

View File

@ -24,18 +24,21 @@ public class LiteBansHook extends Hook {
* @see API
*/
@SuppressWarnings("ResultOfMethodCallIgnored")
public LiteBansHook(HookHandler hookH) throws NoClassDefFoundError {
public LiteBansHook(HookHandler hookH) {
super();
try {
Database.get();
enabled = true;
} catch (NoSuchFieldError | NoSuchMethodError | Exception e) {
} catch (NoClassDefFoundError | NoSuchFieldError | NoSuchMethodError | Exception e) {
enabled = false;
}
}
public void hook() throws NoClassDefFoundError {
if (enabled) {
LiteBansDatabaseQueries db = new LiteBansDatabaseQueries();
hookH.addPluginDataSource(new LiteBansBansTable(db));
hookH.addPluginDataSource(new LiteBansInspectBansTable(db));
addPluginDataSource(new LiteBansBansTable(db));
addPluginDataSource(new LiteBansInspectBansTable(db));
}
}
}

View File

@ -21,10 +21,13 @@ public class McmmoHook extends Hook {
* @see API
*/
public McmmoHook(HookHandler hookH) {
super("com.gmail.nossr50.mcMMO");
super("com.gmail.nossr50.mcMMO", hookH);
}
public void hook() throws NoClassDefFoundError {
if (enabled) {
hookH.addPluginDataSource(new McmmoInspectSkillTable());
hookH.addPluginDataSource(new McmmoAnalysisSkillTable());
addPluginDataSource(new McmmoInspectSkillTable());
addPluginDataSource(new McmmoAnalysisSkillTable());
}
}
}

View File

@ -21,15 +21,18 @@ public class OnTimeHook extends Hook {
* @see API
* @throws NoClassDefFoundError when the plugin class can not be found.
*/
public OnTimeHook(HookHandler hookH) throws NoClassDefFoundError {
super("me.edge209.OnTime.OnTime");
public OnTimeHook(HookHandler hookH) {
super("me.edge209.OnTime.OnTime", hookH);
}
public void hook() throws NoClassDefFoundError {
if (enabled) {
hookH.addPluginDataSource(new OntimeVotes());
hookH.addPluginDataSource(new OntimeVotesWeek());
hookH.addPluginDataSource(new OntimeVotesMonth());
hookH.addPluginDataSource(new OntimeRefer());
hookH.addPluginDataSource(new OntimeReferWeek());
hookH.addPluginDataSource(new OntimeReferMonth());
addPluginDataSource(new OntimeVotes());
addPluginDataSource(new OntimeVotesWeek());
addPluginDataSource(new OntimeVotesMonth());
addPluginDataSource(new OntimeRefer());
addPluginDataSource(new OntimeReferWeek());
addPluginDataSource(new OntimeReferMonth());
}
}
}

View File

@ -5,6 +5,7 @@ import io.minimum.minecraft.superbvote.SuperbVote;
import io.minimum.minecraft.superbvote.storage.VoteStorage;
import main.java.com.djrapitops.plan.api.API;
import main.java.com.djrapitops.plan.data.additional.HookHandler;
import static org.bukkit.plugin.java.JavaPlugin.getPlugin;
/**
@ -18,19 +19,22 @@ public class SuperbVoteHook extends Hook {
/**
* Hooks the plugin and registers it's PluginData objects.
*
* <p>
* API#addPluginDataSource uses the same method from HookHandler.
*
* @param hookH HookHandler instance for registering the data sources.
* @see API
* @throws NoClassDefFoundError when the plugin class can not be found.
* @see API
*/
public SuperbVoteHook(HookHandler hookH) throws NoClassDefFoundError {
super("io.minimum.minecraft.superbvote.SuperbVote");
public SuperbVoteHook(HookHandler hookH) {
super("io.minimum.minecraft.superbvote.SuperbVote", hookH);
}
public void hook() throws NoClassDefFoundError {
if (enabled) {
VoteStorage store = getPlugin(SuperbVote.class).getVoteStorage();
hookH.addPluginDataSource(new SuperbVoteVotes(store));
hookH.addPluginDataSource(new SuperbVoteVotesTable(store));
addPluginDataSource(new SuperbVoteVotes(store));
addPluginDataSource(new SuperbVoteVotesTable(store));
}
}
}

View File

@ -21,11 +21,14 @@ public class TownyHook extends Hook {
* @see API
* @throws NoClassDefFoundError when the plugin class can not be found.
*/
public TownyHook(HookHandler hookH) throws NoClassDefFoundError {
super("com.palmergames.bukkit.towny.Towny");
public TownyHook(HookHandler hookH) {
super("com.palmergames.bukkit.towny.Towny", hookH);
}
public void hook() throws NoClassDefFoundError {
if (enabled) {
hookH.addPluginDataSource(new TownyTable());
hookH.addPluginDataSource(new TownyTown());
addPluginDataSource(new TownyTable());
addPluginDataSource(new TownyTown());
}
}
}

View File

@ -26,22 +26,25 @@ public class VaultHook extends Hook {
* @see API
*/
public VaultHook(HookHandler hookH) throws NoClassDefFoundError {
super("net.milkbowl.vault.Vault");
super("net.milkbowl.vault.Vault", hookH);
}
public void hook() throws NoClassDefFoundError {
if (!enabled) {
return;
}
try {
Permission permSys = getServer().getServicesManager().getRegistration(Permission.class).getProvider();
hookH.addPluginDataSource(new PermGroup(permSys));
hookH.addPluginDataSource(new PermGroupTable(permSys));
addPluginDataSource(new PermGroup(permSys));
addPluginDataSource(new PermGroupTable(permSys));
} catch (NoSuchFieldError | NoSuchMethodError | Exception e) {
}
try {
Economy econ = getServer().getServicesManager().getRegistration(Economy.class).getProvider();
hookH.addPluginDataSource(new EconomyBalance(econ));
hookH.addPluginDataSource(new EconomyBalanceTable(econ));
addPluginDataSource(new EconomyBalance(econ));
addPluginDataSource(new EconomyBalanceTable(econ));
} catch (NoSuchFieldError | NoSuchMethodError | Exception e) {
}
}

View File

@ -24,11 +24,13 @@ public class ViaVersionHook extends Hook {
* API#addPluginDataSource uses the same method from HookHandler.
*
* @param hookH HookHandler instance for registering the data sources.
* @throws NoClassDefFoundError when the plugin class can not be found.
* @see API
*/
public ViaVersionHook(HookHandler hookH) throws NoClassDefFoundError {
super("us.myles.ViaVersion.ViaVersionPlugin");
public ViaVersionHook(HookHandler hookH) {
super("us.myles.ViaVersion.ViaVersionPlugin", hookH);
}
public void hook() throws NoClassDefFoundError {
if (!enabled) {
return;
}
@ -43,7 +45,7 @@ public class ViaVersionHook extends Hook {
}
PlayerVersionListener l = new PlayerVersionListener(plan, api, table);
plan.registerListener(l);
hookH.addPluginDataSource(new ViaVersionVersionTable(table));
hookH.addPluginDataSource(new ViaVersionVersion(table));
addPluginDataSource(new ViaVersionVersionTable(table));
addPluginDataSource(new ViaVersionVersion(table));
}
}