diff options
Diffstat (limited to 'spark-fabric/src/main/java/me/lucko/spark')
10 files changed, 194 insertions, 144 deletions
diff --git a/spark-fabric/src/main/java/me/lucko/spark/fabric/FabricCommandSender.java b/spark-fabric/src/main/java/me/lucko/spark/fabric/FabricCommandSender.java index 3a8d128..fea877c 100644 --- a/spark-fabric/src/main/java/me/lucko/spark/fabric/FabricCommandSender.java +++ b/spark-fabric/src/main/java/me/lucko/spark/fabric/FabricCommandSender.java @@ -21,6 +21,7 @@ package me.lucko.spark.fabric; import me.lucko.spark.common.CommandSender; +import me.lucko.spark.fabric.plugin.FabricSparkPlugin; import net.kyori.text.Component; import net.kyori.text.serializer.gson.GsonComponentSerializer; import net.minecraft.entity.player.PlayerEntity; @@ -31,13 +32,12 @@ import net.minecraft.text.Text; import java.util.UUID; public class FabricCommandSender implements CommandSender { - - private final VanillaPermission permission; private final CommandOutput sender; + private final FabricSparkPlugin plugin; - public FabricCommandSender(VanillaPermission permission, CommandOutput sender) { - this.permission = permission; + public FabricCommandSender(CommandOutput sender, FabricSparkPlugin plugin) { this.sender = sender; + this.plugin = plugin; } @Override @@ -67,7 +67,7 @@ public class FabricCommandSender implements CommandSender { @Override public boolean hasPermission(String permission) { - return this.permission.hasPermissionLevel(4); // Require /stop access, reasonable + return this.plugin.hasPermission(this.sender, permission); } @Override @@ -86,9 +86,4 @@ public class FabricCommandSender implements CommandSender { public int hashCode() { return this.sender.hashCode(); } - - public interface VanillaPermission { - - boolean hasPermissionLevel(int level); - } } diff --git a/spark-fabric/src/main/java/me/lucko/spark/fabric/FabricSparkGameHooks.java b/spark-fabric/src/main/java/me/lucko/spark/fabric/FabricSparkGameHooks.java new file mode 100644 index 0000000..d046ab8 --- /dev/null +++ b/spark-fabric/src/main/java/me/lucko/spark/fabric/FabricSparkGameHooks.java @@ -0,0 +1,73 @@ +/* + * This file is part of spark. + * + * Copyright (c) lucko (Luck) <luck@lucko.me> + * Copyright (c) contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package me.lucko.spark.fabric; + +import java.util.HashSet; +import java.util.Set; +import java.util.function.Predicate; + +public enum FabricSparkGameHooks { + INSTANCE; + + private final Set<FabricTickCounter> clientCounters = new HashSet<>(); + private final Set<FabricTickCounter> serverCounters = new HashSet<>(); + + // Use events from Fabric API later + // Return true to abort sending to server + private Predicate<String> chatSendCallback = s -> false; + + public void setChatSendCallback(Predicate<String> callback) { + this.chatSendCallback = callback; + } + + public boolean tryProcessChat(String message) { + return this.chatSendCallback.test(message); + } + + public void addClientCounter(FabricTickCounter counter) { + this.clientCounters.add(counter); + } + + public void removeClientCounter(FabricTickCounter counter) { + this.clientCounters.remove(counter); + } + + public void addServerCounter(FabricTickCounter counter) { + this.serverCounters.add(counter); + } + + public void removeServerCounter(FabricTickCounter counter) { + this.serverCounters.remove(counter); + } + + public void tickClientCounters() { + for (FabricTickCounter counter : this.clientCounters) { + counter.onTick(); + } + } + + public void tickServerCounters() { + for (FabricTickCounter counter : this.serverCounters) { + counter.onTick(); + } + } + +} diff --git a/spark-fabric/src/main/java/me/lucko/spark/fabric/FabricSparkMod.java b/spark-fabric/src/main/java/me/lucko/spark/fabric/FabricSparkMod.java index 4e4468b..0f6fb1f 100644 --- a/spark-fabric/src/main/java/me/lucko/spark/fabric/FabricSparkMod.java +++ b/spark-fabric/src/main/java/me/lucko/spark/fabric/FabricSparkMod.java @@ -22,85 +22,38 @@ package me.lucko.spark.fabric; import net.fabricmc.api.ModInitializer; import net.fabricmc.loader.api.FabricLoader; +import net.fabricmc.loader.api.ModContainer; import java.nio.file.Path; -import java.util.HashSet; -import java.util.Set; -import java.util.function.Predicate; public class FabricSparkMod implements ModInitializer { + private static FabricSparkMod mod; - private static FabricSparkMod instance; - private final Set<FabricTickCounter> clientCounters = new HashSet<>(); - private final Set<FabricTickCounter> serverCounters = new HashSet<>(); - private String version; - private Path configDir; - // Use events from Fabric API later - // Return true to abort sending to server - private Predicate<String> chatSendCallback = s -> false; - - public FabricSparkMod() { + public static FabricSparkMod getMod() { + return mod; } - public static FabricSparkMod getInstance() { - return instance; - } + private ModContainer container; + private Path configDirectory; @Override public void onInitialize() { - FabricSparkMod.instance = this; - FabricLoader loader = FabricLoader.getInstance(); - this.version = loader.getModContainer("spark") - .orElseThrow(() -> new IllegalStateException("Spark loaded incorrectly!")) - .getMetadata() - .getVersion() - .getFriendlyString(); - this.configDir = loader.getConfigDirectory().toPath().resolve("spark"); + FabricSparkMod.mod = this; - // When Fabric API is available, we will register event listeners here + FabricLoader loader = FabricLoader.getInstance(); + this.container = loader.getModContainer("spark") + .orElseThrow(() -> new IllegalStateException("Unable to get container for spark")); + this.configDirectory = loader.getConfigDirectory().toPath().resolve("spark"); } public String getVersion() { - return version; + return this.container.getMetadata().getVersion().getFriendlyString(); } public Path getConfigDirectory() { - return configDir; - } - - public void setChatSendCallback(Predicate<String> callback) { - this.chatSendCallback = callback; - } - - public boolean tryProcessChat(String message) { - return chatSendCallback.test(message); - } - - public void addClientCounter(FabricTickCounter counter) { - this.clientCounters.add(counter); - } - - public void removeClientCounter(FabricTickCounter counter) { - this.clientCounters.remove(counter); - } - - public void addServerCounter(FabricTickCounter counter) { - this.serverCounters.add(counter); - } - - public void removeServerCounter(FabricTickCounter counter) { - this.serverCounters.remove(counter); - } - - public void tickClientCounters() { - for (FabricTickCounter each : clientCounters) { - each.onTick(); - } - } - - public void tickServerCounters() { - for (FabricTickCounter each : serverCounters) { - each.onTick(); + if (this.configDirectory == null) { + throw new IllegalStateException("Config directory not set"); } + return this.configDirectory; } } diff --git a/spark-fabric/src/main/java/me/lucko/spark/fabric/FabricTickCounter.java b/spark-fabric/src/main/java/me/lucko/spark/fabric/FabricTickCounter.java index 03d00b2..b189e3f 100644 --- a/spark-fabric/src/main/java/me/lucko/spark/fabric/FabricTickCounter.java +++ b/spark-fabric/src/main/java/me/lucko/spark/fabric/FabricTickCounter.java @@ -24,20 +24,11 @@ import me.lucko.spark.common.sampler.TickCounter; import java.util.HashSet; import java.util.Set; -import java.util.function.Consumer; - -public class FabricTickCounter implements TickCounter { +public abstract class FabricTickCounter implements TickCounter { private final Set<TickTask> tasks = new HashSet<>(); - private final Consumer<FabricTickCounter> adder; - private final Consumer<FabricTickCounter> remover; private int tick = 0; - public FabricTickCounter(Consumer<FabricTickCounter> adder, Consumer<FabricTickCounter> remover) { - this.adder = adder; - this.remover = remover; - } - public void onTick() { for (TickTask r : this.tasks) { r.onTick(this); @@ -46,16 +37,6 @@ public class FabricTickCounter implements TickCounter { } @Override - public void start() { - this.adder.accept(this); - } - - @Override - public void close() { - this.remover.accept(this); - } - - @Override public int getCurrentTick() { return this.tick; } @@ -69,4 +50,28 @@ public class FabricTickCounter implements TickCounter { public void removeTickTask(TickTask runnable) { this.tasks.remove(runnable); } + + public static final class Server extends FabricTickCounter { + @Override + public void start() { + FabricSparkGameHooks.INSTANCE.addServerCounter(this); + } + + @Override + public void close() { + FabricSparkGameHooks.INSTANCE.removeServerCounter(this); + } + } + + public static final class Client extends FabricTickCounter { + @Override + public void start() { + FabricSparkGameHooks.INSTANCE.addClientCounter(this); + } + + @Override + public void close() { + FabricSparkGameHooks.INSTANCE.removeClientCounter(this); + } + } } diff --git a/spark-fabric/src/main/java/me/lucko/spark/fabric/mixin/ClientPlayerEntityMixin.java b/spark-fabric/src/main/java/me/lucko/spark/fabric/mixin/ClientPlayerEntityMixin.java index 3ce57b1..8085567 100644 --- a/spark-fabric/src/main/java/me/lucko/spark/fabric/mixin/ClientPlayerEntityMixin.java +++ b/spark-fabric/src/main/java/me/lucko/spark/fabric/mixin/ClientPlayerEntityMixin.java @@ -21,7 +21,7 @@ package me.lucko.spark.fabric.mixin; import com.mojang.authlib.GameProfile; -import me.lucko.spark.fabric.FabricSparkMod; +import me.lucko.spark.fabric.FabricSparkGameHooks; import net.minecraft.client.network.AbstractClientPlayerEntity; import net.minecraft.client.network.ClientPlayerEntity; import net.minecraft.client.world.ClientWorld; @@ -42,7 +42,7 @@ public abstract class ClientPlayerEntityMixin extends AbstractClientPlayerEntity locals = LocalCapture.CAPTURE_FAILHARD, cancellable = true) public void onSendChatMessage(String message, CallbackInfo ci) { - if (FabricSparkMod.getInstance().tryProcessChat(message)) { + if (FabricSparkGameHooks.INSTANCE.tryProcessChat(message)) { ci.cancel(); } } diff --git a/spark-fabric/src/main/java/me/lucko/spark/fabric/mixin/MinecraftClientMixin.java b/spark-fabric/src/main/java/me/lucko/spark/fabric/mixin/MinecraftClientMixin.java index b987ca6..ae7ef5f 100644 --- a/spark-fabric/src/main/java/me/lucko/spark/fabric/mixin/MinecraftClientMixin.java +++ b/spark-fabric/src/main/java/me/lucko/spark/fabric/mixin/MinecraftClientMixin.java @@ -20,8 +20,9 @@ package me.lucko.spark.fabric.mixin; -import me.lucko.spark.fabric.FabricClientSparkPlugin; +import me.lucko.spark.fabric.FabricSparkGameHooks; import me.lucko.spark.fabric.FabricSparkMod; +import me.lucko.spark.fabric.plugin.FabricClientSparkPlugin; import net.minecraft.client.MinecraftClient; import net.minecraft.util.NonBlockingThreadExecutor; import org.spongepowered.asm.mixin.Mixin; @@ -40,12 +41,12 @@ public abstract class MinecraftClientMixin extends NonBlockingThreadExecutor<Run @Inject(method = "init()V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/SplashScreen;method_18819(Lnet/minecraft/client/MinecraftClient;)V")) public void onInit(CallbackInfo ci) { - FabricClientSparkPlugin.register(FabricSparkMod.getInstance(), (MinecraftClient) (Object) this); + FabricClientSparkPlugin.register(FabricSparkMod.getMod(), (MinecraftClient) (Object) this); } @Inject(method = "tick()V", at = @At("RETURN")) public void onTick(CallbackInfo ci) { - FabricSparkMod.getInstance().tickClientCounters(); + FabricSparkGameHooks.INSTANCE.tickClientCounters(); } } diff --git a/spark-fabric/src/main/java/me/lucko/spark/fabric/mixin/MinecraftServerMixin.java b/spark-fabric/src/main/java/me/lucko/spark/fabric/mixin/MinecraftServerMixin.java index bb14b64..4e3a0ab 100644 --- a/spark-fabric/src/main/java/me/lucko/spark/fabric/mixin/MinecraftServerMixin.java +++ b/spark-fabric/src/main/java/me/lucko/spark/fabric/mixin/MinecraftServerMixin.java @@ -20,8 +20,9 @@ package me.lucko.spark.fabric.mixin; -import me.lucko.spark.fabric.FabricServerSparkPlugin; +import me.lucko.spark.fabric.FabricSparkGameHooks; import me.lucko.spark.fabric.FabricSparkMod; +import me.lucko.spark.fabric.plugin.FabricServerSparkPlugin; import net.minecraft.server.MinecraftServer; import net.minecraft.server.ServerTask; import net.minecraft.util.NonBlockingThreadExecutor; @@ -41,12 +42,12 @@ public abstract class MinecraftServerMixin extends NonBlockingThreadExecutor<Ser @Inject(method = "run()V", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/MinecraftServer;setFavicon(Lnet/minecraft/server/ServerMetadata;)V")) public void onRun(CallbackInfo ci) { - FabricServerSparkPlugin.register(FabricSparkMod.getInstance(), (MinecraftServer) (Object) this); + FabricServerSparkPlugin.register(FabricSparkMod.getMod(), (MinecraftServer) (Object) this); } @Inject(method = "tick(Ljava/util/function/BooleanSupplier;)V", at = @At("RETURN")) public void onTick(CallbackInfo ci) { - FabricSparkMod.getInstance().tickServerCounters(); + FabricSparkGameHooks.INSTANCE.tickServerCounters(); } } diff --git a/spark-fabric/src/main/java/me/lucko/spark/fabric/FabricClientSparkPlugin.java b/spark-fabric/src/main/java/me/lucko/spark/fabric/plugin/FabricClientSparkPlugin.java index 1421779..d87d5be 100644 --- a/spark-fabric/src/main/java/me/lucko/spark/fabric/FabricClientSparkPlugin.java +++ b/spark-fabric/src/main/java/me/lucko/spark/fabric/plugin/FabricClientSparkPlugin.java @@ -18,13 +18,18 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -package me.lucko.spark.fabric; +package me.lucko.spark.fabric.plugin; import com.mojang.brigadier.CommandDispatcher; import me.lucko.spark.common.sampler.TickCounter; +import me.lucko.spark.fabric.FabricCommandSender; +import me.lucko.spark.fabric.FabricSparkGameHooks; +import me.lucko.spark.fabric.FabricSparkMod; +import me.lucko.spark.fabric.FabricTickCounter; import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.ClientPlayNetworkHandler; import net.minecraft.client.network.ClientPlayerEntity; +import net.minecraft.server.command.CommandOutput; import net.minecraft.server.command.CommandSource; import java.util.Arrays; @@ -33,6 +38,12 @@ import java.util.stream.Stream; public class FabricClientSparkPlugin extends FabricSparkPlugin { + public static void register(FabricSparkMod mod, MinecraftClient client) { + FabricClientSparkPlugin plugin = new FabricClientSparkPlugin(mod, client); + + plugin.scheduler.scheduleWithFixedDelay(plugin::checkCommandRegistered, 10, 10, TimeUnit.SECONDS); + } + private final MinecraftClient minecraft; private CommandDispatcher<CommandSource> dispatcher; @@ -41,12 +52,6 @@ public class FabricClientSparkPlugin extends FabricSparkPlugin { this.minecraft = minecraft; } - public static void register(FabricSparkMod mod, MinecraftClient client) { - FabricClientSparkPlugin plugin = new FabricClientSparkPlugin(mod, client); - - plugin.scheduler.scheduleWithFixedDelay(plugin::checkCommandRegistered, 10, 10, TimeUnit.SECONDS); - } - private void checkCommandRegistered() { ClientPlayerEntity player = this.minecraft.player; if (player == null) { @@ -63,17 +68,13 @@ public class FabricClientSparkPlugin extends FabricSparkPlugin { if (dispatcher != this.dispatcher) { this.dispatcher = dispatcher; registerCommands(this.dispatcher, c -> 0, "sparkc", "sparkclient"); - this.mod.setChatSendCallback(this::onClientChat); + FabricSparkGameHooks.INSTANCE.setChatSendCallback(this::onClientChat); } } catch (Exception e) { e.printStackTrace(); } } - private FabricCommandSender createClientSender() { - return new FabricCommandSender(this.minecraft.player.networkHandler.getCommandSource()::hasPermissionLevel, this.minecraft.player); - } - public boolean onClientChat(String chat) { String[] split = chat.split(" "); if (split.length == 0 || (!split[0].equals("/sparkc") && !split[0].equals("/sparkclient"))) { @@ -81,19 +82,24 @@ public class FabricClientSparkPlugin extends FabricSparkPlugin { } String[] args = Arrays.copyOfRange(split, 1, split.length); - this.platform.executeCommand(createClientSender(), args); + this.platform.executeCommand(new FabricCommandSender(this.minecraft.player, this), args); this.minecraft.inGameHud.getChatHud().addToMessageHistory(chat); return true; } @Override + public boolean hasPermission(CommandOutput sender, String permission) { + return true; + } + + @Override public Stream<FabricCommandSender> getSendersWithPermission(String permission) { - return Stream.of(createClientSender()); + return Stream.of(new FabricCommandSender(this.minecraft.player, this)); } @Override public TickCounter createTickCounter() { - return new FabricTickCounter(FabricSparkMod.getInstance()::addClientCounter, FabricSparkMod.getInstance()::removeClientCounter); + return new FabricTickCounter.Client(); } @Override diff --git a/spark-fabric/src/main/java/me/lucko/spark/fabric/FabricServerSparkPlugin.java b/spark-fabric/src/main/java/me/lucko/spark/fabric/plugin/FabricServerSparkPlugin.java index 01bc442..9729e55 100644 --- a/spark-fabric/src/main/java/me/lucko/spark/fabric/FabricServerSparkPlugin.java +++ b/spark-fabric/src/main/java/me/lucko/spark/fabric/plugin/FabricServerSparkPlugin.java @@ -18,63 +18,74 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -package me.lucko.spark.fabric; +package me.lucko.spark.fabric.plugin; import com.mojang.brigadier.Command; import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; import me.lucko.spark.common.sampler.TickCounter; +import me.lucko.spark.fabric.FabricCommandSender; +import me.lucko.spark.fabric.FabricSparkMod; +import me.lucko.spark.fabric.FabricTickCounter; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.server.MinecraftServer; +import net.minecraft.server.command.CommandOutput; import net.minecraft.server.command.ServerCommandSource; -import net.minecraft.text.LiteralText; import java.util.Arrays; import java.util.stream.Stream; public class FabricServerSparkPlugin extends FabricSparkPlugin implements Command<ServerCommandSource> { - private final MinecraftServer server; - - public FabricServerSparkPlugin(FabricSparkMod mod, MinecraftServer server) { - super(mod); - this.server = server; - } - public static void register(FabricSparkMod mod, MinecraftServer server) { CommandDispatcher<ServerCommandSource> dispatcher = server.getCommandManager().getDispatcher(); FabricServerSparkPlugin plugin = new FabricServerSparkPlugin(mod, server); registerCommands(dispatcher, plugin, "spark"); - // PermissionAPI.registerNode("spark", DefaultPermissionLevel.OP, "Access to the spark command"); + } + + private final MinecraftServer server; + + public FabricServerSparkPlugin(FabricSparkMod mod, MinecraftServer server) { + super(mod); + this.server = server; } @Override public int run(CommandContext<ServerCommandSource> context) throws CommandSyntaxException { String[] split = context.getInput().split(" "); if (split.length == 0 || !split[0].equals("/spark")) { - context.getSource().sendError(new LiteralText("Wrong split started with " + (split.length == 0 ? "nothing" : split[0]))); return 0; } String[] args = Arrays.copyOfRange(split, 1, split.length); - this.platform.executeCommand(new FabricCommandSender(context.getSource()::hasPermissionLevel, context.getSource().getPlayer()), args); + this.platform.executeCommand(new FabricCommandSender(context.getSource().getPlayer(), this), args); return 1; } @Override + public boolean hasPermission(CommandOutput sender, String permission) { + if (sender instanceof PlayerEntity) { + return this.server.getPermissionLevel(((PlayerEntity) sender).getGameProfile()) >= 4; + } else { + return true; + } + } + + @Override public Stream<FabricCommandSender> getSendersWithPermission(String permission) { return Stream.concat( this.server.getPlayerManager().getPlayerList().stream() - .filter(player -> this.server.getPermissionLevel(player.getGameProfile()) == 4), + .filter(player -> hasPermission(player, permission)), Stream.of(this.server) - ).map(sender -> new FabricCommandSender(i -> true, sender)); + ).map(sender -> new FabricCommandSender(sender, this)); } @Override public TickCounter createTickCounter() { - return new FabricTickCounter(FabricSparkMod.getInstance()::addServerCounter, FabricSparkMod.getInstance()::removeServerCounter); + return new FabricTickCounter.Server(); } @Override diff --git a/spark-fabric/src/main/java/me/lucko/spark/fabric/FabricSparkPlugin.java b/spark-fabric/src/main/java/me/lucko/spark/fabric/plugin/FabricSparkPlugin.java index a0f6cf0..6672358 100644 --- a/spark-fabric/src/main/java/me/lucko/spark/fabric/FabricSparkPlugin.java +++ b/spark-fabric/src/main/java/me/lucko/spark/fabric/plugin/FabricSparkPlugin.java @@ -18,7 +18,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -package me.lucko.spark.fabric; +package me.lucko.spark.fabric.plugin; import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.mojang.brigadier.Command; @@ -30,6 +30,8 @@ import com.mojang.brigadier.tree.LiteralCommandNode; import me.lucko.spark.common.SparkPlatform; import me.lucko.spark.common.SparkPlugin; import me.lucko.spark.common.sampler.ThreadDumper; +import me.lucko.spark.fabric.FabricSparkMod; +import net.minecraft.server.command.CommandOutput; import java.nio.file.Path; import java.util.concurrent.Executors; @@ -37,23 +39,11 @@ import java.util.concurrent.ScheduledExecutorService; public abstract class FabricSparkPlugin implements SparkPlugin { - protected final ScheduledExecutorService scheduler; - protected final SparkPlatform platform; - protected final FabricSparkMod mod; - - protected FabricSparkPlugin(FabricSparkMod mod) { - this.mod = mod; - this.scheduler = Executors.newSingleThreadScheduledExecutor( - new ThreadFactoryBuilder().setNameFormat("spark-fabric-async-worker").build() - ); - this.platform = new SparkPlatform(this); - this.platform.enable(); - } - public static <T> void registerCommands(CommandDispatcher<T> dispatcher, Command<T> executor, String... aliases) { if (aliases.length == 0) { return; } + String mainName = aliases[0]; LiteralArgumentBuilder<T> command = LiteralArgumentBuilder.<T>literal(mainName) .executes(executor) @@ -67,6 +57,21 @@ public abstract class FabricSparkPlugin implements SparkPlugin { } } + private final FabricSparkMod mod; + protected final ScheduledExecutorService scheduler; + protected final SparkPlatform platform; + + protected FabricSparkPlugin(FabricSparkMod mod) { + this.mod = mod; + this.scheduler = Executors.newSingleThreadScheduledExecutor( + new ThreadFactoryBuilder().setNameFormat("spark-fabric-async-worker").build() + ); + this.platform = new SparkPlatform(this); + this.platform.enable(); + } + + public abstract boolean hasPermission(CommandOutput sender, String permission); + @Override public String getVersion() { return this.mod.getVersion(); |