From cc6fdce63a7973213f0502918c351e536a025941 Mon Sep 17 00:00:00 2001 From: ohnoey Date: Sat, 31 Aug 2024 22:54:35 -0700 Subject: [PATCH] Use dependency injection --- .../net/countercraft/movecraft/Movecraft.java | 294 ++++-------------- .../movecraft/async/AsyncManager.java | 41 ++- .../movecraft/craft/ChunkManager.java | 6 +- .../movecraft/listener/BlockListener.java | 4 + .../listener/CraftPilotListener.java | 3 + .../listener/CraftReleaseListener.java | 3 + .../movecraft/listener/InteractListener.java | 8 +- .../movecraft/listener/PlayerListener.java | 8 +- .../movecraft/localisation/I18nSupport.java | 24 +- .../mapUpdater/MapUpdateManager.java | 23 +- .../movecraft/sign/AscendSign.java | 3 + .../movecraft/sign/CraftSign.java | 8 +- .../movecraft/sign/CruiseSign.java | 3 + .../movecraft/sign/DescendSign.java | 3 + .../countercraft/movecraft/sign/HelmSign.java | 3 + .../countercraft/movecraft/sign/MoveSign.java | 4 + .../countercraft/movecraft/sign/NameSign.java | 5 + .../movecraft/sign/PilotSign.java | 5 + .../movecraft/sign/RelativeMoveSign.java | 4 + .../movecraft/sign/ReleaseSign.java | 4 + .../movecraft/sign/RemoteSign.java | 4 + .../movecraft/sign/ScuttleSign.java | 5 +- .../movecraft/sign/SpeedSign.java | 6 +- .../movecraft/sign/SubcraftRotateSign.java | 8 +- .../movecraft/sign/TeleportSign.java | 4 + .../support/SmoothTeleportFactory.java | 42 +++ .../support/WorldHandlerFactory.java | 41 +++ api/build.gradle.kts | 1 + .../countercraft/movecraft/WorldHandler.java | 1 + .../movecraft/config/DataPackService.java | 121 +++++++ .../movecraft/config/Settings.java | 1 + .../movecraft/config/SettingsService.java | 79 +++++ .../lifecycle/ListenerLifecycleService.java | 24 ++ .../movecraft/lifecycle/Service.java | 6 + .../movecraft/lifecycle/ServiceHost.java | 23 ++ .../movecraft/lifecycle/Worker.java | 13 + .../lifecycle/WorkerServiceHost.java | 38 +++ .../movecraft/processing/WorldManager.java | 23 +- .../movecraft/support/VersionInfo.java | 13 + .../movecraft/support/VersionProvider.java | 24 ++ gradle/libs.versions.toml | 2 + 41 files changed, 666 insertions(+), 269 deletions(-) create mode 100644 Movecraft/src/main/java/net/countercraft/movecraft/support/SmoothTeleportFactory.java create mode 100644 Movecraft/src/main/java/net/countercraft/movecraft/support/WorldHandlerFactory.java create mode 100644 api/src/main/java/net/countercraft/movecraft/config/DataPackService.java create mode 100644 api/src/main/java/net/countercraft/movecraft/config/SettingsService.java create mode 100644 api/src/main/java/net/countercraft/movecraft/lifecycle/ListenerLifecycleService.java create mode 100644 api/src/main/java/net/countercraft/movecraft/lifecycle/Service.java create mode 100644 api/src/main/java/net/countercraft/movecraft/lifecycle/ServiceHost.java create mode 100644 api/src/main/java/net/countercraft/movecraft/lifecycle/Worker.java create mode 100644 api/src/main/java/net/countercraft/movecraft/lifecycle/WorkerServiceHost.java create mode 100644 api/src/main/java/net/countercraft/movecraft/support/VersionInfo.java create mode 100644 api/src/main/java/net/countercraft/movecraft/support/VersionProvider.java diff --git a/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java b/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java index fe69859c1..3d165288f 100644 --- a/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java +++ b/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java @@ -17,37 +17,34 @@ package net.countercraft.movecraft; -import io.papermc.paper.datapack.Datapack; import net.countercraft.movecraft.async.AsyncManager; import net.countercraft.movecraft.commands.*; +import net.countercraft.movecraft.config.DataPackService; import net.countercraft.movecraft.config.Settings; +import net.countercraft.movecraft.config.SettingsService; import net.countercraft.movecraft.craft.ChunkManager; import net.countercraft.movecraft.craft.CraftManager; -import net.countercraft.movecraft.craft.datatag.CraftDataTagRegistry; import net.countercraft.movecraft.features.contacts.ContactsCommand; import net.countercraft.movecraft.features.contacts.ContactsManager; import net.countercraft.movecraft.features.contacts.ContactsSign; import net.countercraft.movecraft.features.fading.WreckManager; import net.countercraft.movecraft.features.status.StatusManager; import net.countercraft.movecraft.features.status.StatusSign; +import net.countercraft.movecraft.lifecycle.ServiceHost; +import net.countercraft.movecraft.lifecycle.WorkerServiceHost; import net.countercraft.movecraft.listener.*; import net.countercraft.movecraft.localisation.I18nSupport; import net.countercraft.movecraft.mapUpdater.MapUpdateManager; import net.countercraft.movecraft.processing.WorldManager; import net.countercraft.movecraft.sign.*; -import net.countercraft.movecraft.util.BukkitTeleport; -import net.countercraft.movecraft.util.Tags; -import org.bukkit.Bukkit; -import org.bukkit.Material; +import net.countercraft.movecraft.support.SmoothTeleportFactory; +import net.countercraft.movecraft.support.WorldHandlerFactory; import org.bukkit.plugin.java.JavaPlugin; +import org.int4.dirk.api.Injector; +import org.int4.dirk.di.Injectors; import org.jetbrains.annotations.NotNull; import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; import java.util.logging.Logger; public class Movecraft extends JavaPlugin { @@ -55,10 +52,7 @@ public class Movecraft extends JavaPlugin { private Logger logger; private boolean shuttingDown; - private WorldHandler worldHandler; - private SmoothTeleport smoothTeleport; - private AsyncManager asyncManager; - private WreckManager wreckManager; + private Injector injector; public static synchronized Movecraft getInstance() { return instance; @@ -67,137 +61,38 @@ public static synchronized Movecraft getInstance() { @Override public void onDisable() { shuttingDown = true; + injector.getInstance(ServiceHost.class).stopAll(); + injector = null; } @Override public void onEnable() { - // Read in config - Settings.LOCALE = getConfig().getString("Locale"); - Settings.Debug = getConfig().getBoolean("Debug", false); - Settings.DisableNMSCompatibilityCheck = getConfig().getBoolean("IReallyKnowWhatIAmDoing", false); - Settings.DisableSpillProtection = getConfig().getBoolean("DisableSpillProtection", false); - Settings.DisableIceForm = getConfig().getBoolean("DisableIceForm", true); - Settings.ReleaseOnDeath = getConfig().getBoolean("ReleaseOnDeath", false); - - String[] localisations = {"en", "cz", "nl", "fr"}; - for (String s : localisations) { - if (!new File(getDataFolder() - + "/localisation/movecraftlang_" + s + ".properties").exists()) { - saveResource("localisation/movecraftlang_" + s + ".properties", false); - } - } - I18nSupport.init(); - - - // if the PilotTool is specified in the config.yml file, use it - String pilotTool = getConfig().getString("PilotTool"); - if (pilotTool != null) { - Material material = Material.getMaterial(pilotTool); - if (material != null) { - logger.info("Recognized PilotTool setting of: " + pilotTool); - Settings.PilotTool = material; - } - else { - logger.info("No PilotTool setting, using default of stick"); - } - } - else { - logger.info("No PilotTool setting, using default of stick"); - } - - String minecraftVersion = getServer().getMinecraftVersion(); - getLogger().info("Loading support for " + minecraftVersion); - try { - final Class worldHandlerClazz = Class.forName("net.countercraft.movecraft.compat." + WorldHandler.getPackageName(minecraftVersion) + ".IWorldHandler"); - // Check if we have a NMSHandler class at that location. - if (WorldHandler.class.isAssignableFrom(worldHandlerClazz)) { // Make sure it actually implements NMS - worldHandler = (WorldHandler) worldHandlerClazz.getConstructor().newInstance(); // Set our handler - - // Try to setup the smooth teleport handler - try { - final Class smoothTeleportClazz = Class.forName("net.countercraft.movecraft.support." + WorldHandler.getPackageName(minecraftVersion) + ".ISmoothTeleport"); - if (SmoothTeleport.class.isAssignableFrom(smoothTeleportClazz)) { - smoothTeleport = (SmoothTeleport) smoothTeleportClazz.getConstructor().newInstance(); - } - else { - smoothTeleport = new BukkitTeleport(); // Fall back to bukkit teleportation - getLogger().warning("Did not find smooth teleport, falling back to bukkit teleportation provider."); - } - } - catch (final ReflectiveOperationException e) { - if (Settings.Debug) { - e.printStackTrace(); - } - smoothTeleport = new BukkitTeleport(); // Fall back to bukkit teleportation - getLogger().warning("Falling back to bukkit teleportation provider."); - } - } - } - catch (final Exception e) { - e.printStackTrace(); - getLogger().severe("Could not find support for this version."); - if (!Settings.DisableNMSCompatibilityCheck) { - // Disable ourselves and exit - setEnabled(false); - return; - } - else { - // Server owner claims to know what they are doing, warn them of the possible consequences - getLogger().severe("WARNING!\n\t" - + "Running Movecraft on an incompatible version can corrupt your world and break EVERYTHING!\n\t" - + "We provide no support for any issues."); - } - } - - - Settings.SinkCheckTicks = getConfig().getDouble("SinkCheckTicks", 100.0); - Settings.ManOverboardTimeout = getConfig().getInt("ManOverboardTimeout", 30); - Settings.ManOverboardDistSquared = Math.pow(getConfig().getDouble("ManOverboardDistance", 1000), 2); - Settings.SilhouetteViewDistance = getConfig().getInt("SilhouetteViewDistance", 200); - Settings.SilhouetteBlockCount = getConfig().getInt("SilhouetteBlockCount", 20); - Settings.ProtectPilotedCrafts = getConfig().getBoolean("ProtectPilotedCrafts", false); - Settings.MaxRemoteSigns = getConfig().getInt("MaxRemoteSigns", -1); - Settings.CraftsUseNetherPortals = getConfig().getBoolean("CraftsUseNetherPortals", false); - Settings.RequireCreatePerm = getConfig().getBoolean("RequireCreatePerm", false); - Settings.RequireNamePerm = getConfig().getBoolean("RequireNamePerm", true); - Settings.FadeWrecksAfter = getConfig().getInt("FadeWrecksAfter", 0); - Settings.FadeTickCooldown = getConfig().getInt("FadeTickCooldown", 20); - Settings.FadePercentageOfWreckPerCycle = getConfig().getDouble("FadePercentageOfWreckPerCycle", 10.0); - if (getConfig().contains("ExtraFadeTimePerBlock")) { - Map temp = getConfig().getConfigurationSection("ExtraFadeTimePerBlock").getValues(false); - for (String str : temp.keySet()) { - Set materials = Tags.parseMaterials(str); - for (Material m : materials) { - Settings.ExtraFadeTimePerBlock.put(m, (Integer) temp.get(str)); - } - } - } - - Settings.ForbiddenRemoteSigns = new HashSet<>(); - for(String s : getConfig().getStringList("ForbiddenRemoteSigns")) { - Settings.ForbiddenRemoteSigns.add(s.toLowerCase()); - } - + injector = Injectors.manual(); + injector.registerInstance(getLogger()); + injector.registerInstance(this); + injector.register(AsyncManager.class); + injector.register(MapUpdateManager.class); + injector.register(SmoothTeleportFactory.class); + injector.register(WorldHandlerFactory.class); + injector.registerInstance(WorldManager.INSTANCE); + injector.register(WreckManager.class); + injector.register(I18nSupport.class); + injector.register(SettingsService.class); + + // TODO: make this work somehow if(shuttingDown && Settings.IGNORE_RESET) { logger.severe("Movecraft is incompatible with the reload command. Movecraft has shut down and will restart when the server is restarted."); logger.severe("If you wish to use the reload command and Movecraft, you may disable this check inside the config.yml by setting 'safeReload: false'"); getPluginLoader().disablePlugin(this); + return; } - // Startup procedure - boolean datapackInitialized = isDatapackEnabled() || initializeDatapack(); - asyncManager = new AsyncManager(); - asyncManager.runTaskTimer(this, 0, 1); - MapUpdateManager.getInstance().runTaskTimer(this, 0, 1); - - - CraftManager.initialize(datapackInitialized); - Bukkit.getScheduler().runTaskTimer(this, WorldManager.INSTANCE::run, 0,1); - wreckManager = new WreckManager(WorldManager.INSTANCE); - - getServer().getPluginManager().registerEvents(new InteractListener(), this); + // TODO: DI for CraftManager + injector.register(DataPackService.class); + CraftManager.initialize(injector.getInstance(DataPackService.class).isDatapackInitialized()); + //TODO: migrate to aikar or brigadier commands, left in place for now getCommand("movecraft").setExecutor(new MovecraftCommand()); getCommand("release").setExecutor(new ReleaseCommand()); getCommand("pilot").setExecutor(new PilotCommand()); @@ -209,26 +104,30 @@ public void onEnable() { getCommand("crafttype").setExecutor(new CraftTypeCommand()); getCommand("craftinfo").setExecutor(new CraftInfoCommand()); - getServer().getPluginManager().registerEvents(new BlockListener(), this); - getServer().getPluginManager().registerEvents(new PlayerListener(), this); - getServer().getPluginManager().registerEvents(new ChunkManager(), this); - getServer().getPluginManager().registerEvents(new AscendSign(), this); - getServer().getPluginManager().registerEvents(new CraftSign(), this); - getServer().getPluginManager().registerEvents(new CruiseSign(), this); - getServer().getPluginManager().registerEvents(new DescendSign(), this); - getServer().getPluginManager().registerEvents(new HelmSign(), this); - getServer().getPluginManager().registerEvents(new MoveSign(), this); - getServer().getPluginManager().registerEvents(new NameSign(), this); - getServer().getPluginManager().registerEvents(new PilotSign(), this); - getServer().getPluginManager().registerEvents(new RelativeMoveSign(), this); - getServer().getPluginManager().registerEvents(new ReleaseSign(), this); - getServer().getPluginManager().registerEvents(new RemoteSign(), this); - getServer().getPluginManager().registerEvents(new SpeedSign(), this); - getServer().getPluginManager().registerEvents(new SubcraftRotateSign(), this); - getServer().getPluginManager().registerEvents(new TeleportSign(), this); - getServer().getPluginManager().registerEvents(new ScuttleSign(), this); - getServer().getPluginManager().registerEvents(new CraftPilotListener(), this); - getServer().getPluginManager().registerEvents(new CraftReleaseListener(), this); + injector.register(InteractListener.class); + injector.register(BlockListener.class); + injector.register(PlayerListener.class); + injector.register(ChunkManager.class); + + // Signs + injector.register(AscendSign.class); + injector.register(CraftSign.class); + injector.register(CruiseSign.class); + injector.register(DescendSign.class); + injector.register(HelmSign.class); + injector.register(MoveSign.class); + injector.register(NameSign.class); + injector.register(PilotSign.class); + injector.register(RelativeMoveSign.class); + injector.register(ReleaseSign.class); + injector.register(RemoteSign.class); + injector.register(SpeedSign.class); + injector.register(SubcraftRotateSign.class); + injector.register(TeleportSign.class); + injector.register(ScuttleSign.class); + + injector.register(CraftPilotListener.class); + injector.register(CraftReleaseListener.class); var contactsManager = new ContactsManager(); contactsManager.runTaskTimerAsynchronously(this, 0, 20); @@ -241,7 +140,11 @@ public void onEnable() { getServer().getPluginManager().registerEvents(statusManager, this); getServer().getPluginManager().registerEvents(new StatusSign(), this); - logger.info("[V " + getDescription().getVersion() + "] has been enabled."); + // Lifecycle management + injector.register(WorkerServiceHost.class); + injector.getInstance(ServiceHost.class).startAll(); + + logger.info("[V %s] has been enabled.".formatted(getDescription().getVersion())); } @Override @@ -252,92 +155,19 @@ public void onLoad() { saveDefaultConfig(); } - private boolean initializeDatapack() { - File datapackDirectory = null; - for(var world : getServer().getWorlds()) { - datapackDirectory = new File(world.getWorldFolder(), "datapacks"); - if(datapackDirectory.exists()) - break; - } - if(datapackDirectory == null) { - logger.severe("Failed to initialize Movecraft data pack due to first time world initialization."); - return false; - } - if(!datapackDirectory.exists()) { - logger.info("Creating a datapack directory at " + datapackDirectory.getPath()); - if(!datapackDirectory.mkdir()) { - logger.severe("Failed to create datapack directory!"); - return false; - } - } - else if(new File(datapackDirectory, "movecraft-data.zip").exists()) { - logger.warning("Conflicting datapack already exists in " + datapackDirectory.getPath() + ". If you would like to regenerate the datapack, delete the existing one."); - return false; - } - if(!datapackDirectory.canWrite()) { - logger.warning("Missing permissions to write to world directory."); - return false; - } - - try(var stream = new FileOutputStream(new File(datapackDirectory, "movecraft-data.zip")); - var pack = getResource("movecraft-data.zip")) { - if(pack == null) { - logger.severe("No internal datapack found, report this."); - return false; - } - pack.transferTo(stream); - } - catch(IOException e) { - e.printStackTrace(); - return false; - } - logger.info("Saved default Movecraft datapack."); - - getServer().dispatchCommand(getServer().createCommandSender(response -> {}), "datapack list"); // list datapacks to trigger the server to check - for (Datapack datapack : getServer().getDatapackManager().getPacks()) { - if (!datapack.getName().equals("file/movecraft-data.zip")) - continue; - - if (!datapack.isEnabled()) { - datapack.setEnabled(true); - logger.info("Datapack enabled."); - } - break; - } - - if (!isDatapackEnabled()) { - logger.severe("Failed to automatically load movecraft datapack. Check if it exists."); - setEnabled(false); - return false; - } - return true; - } - - private boolean isDatapackEnabled() { - getServer().dispatchCommand(getServer().createCommandSender(response -> {}), "datapack list"); // list datapacks to trigger the server to check - for (Datapack datapack : getServer().getDatapackManager().getPacks()) { - if (!datapack.getName().equals("file/movecraft-data.zip")) - continue; - - return datapack.isEnabled(); - } - return false; - } - - public WorldHandler getWorldHandler(){ - return worldHandler; + return injector.getInstance(WorldHandler.class); } public SmoothTeleport getSmoothTeleport() { - return smoothTeleport; + return injector.getInstance(SmoothTeleport.class); } public AsyncManager getAsyncManager() { - return asyncManager; + return injector.getInstance(AsyncManager.class); } public @NotNull WreckManager getWreckManager(){ - return wreckManager; + return injector.getInstance(WreckManager.class); } } diff --git a/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java b/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java index 7825b86e2..6070801a1 100644 --- a/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java +++ b/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java @@ -21,6 +21,7 @@ import net.countercraft.movecraft.CruiseDirection; import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftLocation; +import net.countercraft.movecraft.lifecycle.Service; import net.countercraft.movecraft.async.rotation.RotationTask; import net.countercraft.movecraft.async.translation.TranslationTask; import net.countercraft.movecraft.craft.Craft; @@ -34,26 +35,36 @@ import net.kyori.adventure.text.Component; import org.bukkit.World; import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; import org.bukkit.scheduler.BukkitRunnable; import org.jetbrains.annotations.NotNull; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.WeakHashMap; +import java.util.*; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; @Deprecated -public class AsyncManager extends BukkitRunnable { - private final Map ownershipMap = new HashMap<>(); - private final BlockingQueue finishedAlgorithms = new LinkedBlockingQueue<>(); - private final Set clearanceSet = new HashSet<>(); - private final Map cooldownCache = new WeakHashMap<>(); +public class AsyncManager extends BukkitRunnable implements Service { + private final Map ownershipMap; + private final BlockingQueue finishedAlgorithms; + private final Set clearanceSet; + private final Map cooldownCache; + private final @NotNull Plugin plugin; + private final @NotNull MapUpdateManager mapUpdateManager; + + public AsyncManager(@NotNull Plugin plugin, @NotNull MapUpdateManager mapUpdateManager) { + this.plugin = Objects.requireNonNull(plugin); + this.mapUpdateManager = mapUpdateManager; + ownershipMap = new HashMap<>(); + finishedAlgorithms = new LinkedBlockingQueue<>(); + clearanceSet = new HashSet<>(); + cooldownCache = new WeakHashMap<>(); + } - public AsyncManager() {} + @Override + public void start(){ + this.runTaskTimer(plugin, 0, 1); + } public void submitTask(AsyncTask task, Craft c) { if (c.isNotProcessing()) { @@ -120,14 +131,14 @@ private boolean processTranslation(@NotNull final TranslationTask task, @NotNull if (task.isCollisionExplosion()) { c.setHitBox(task.getNewHitBox()); c.setFluidLocations(task.getNewFluidList()); - MapUpdateManager.getInstance().scheduleUpdates(task.getUpdates()); + mapUpdateManager.scheduleUpdates(task.getUpdates()); CraftManager.getInstance().addReleaseTask(c); return true; } return false; } // The craft is clear to move, perform the block updates - MapUpdateManager.getInstance().scheduleUpdates(task.getUpdates()); + mapUpdateManager.scheduleUpdates(task.getUpdates()); c.setHitBox(task.getNewHitBox()); c.setFluidLocations(task.getNewFluidList()); @@ -153,7 +164,7 @@ private boolean processRotation(@NotNull final RotationTask task, @NotNull final } - MapUpdateManager.getInstance().scheduleUpdates(task.getUpdates()); + mapUpdateManager.scheduleUpdates(task.getUpdates()); c.setHitBox(task.getNewHitBox()); c.setFluidLocations(task.getNewFluidList()); diff --git a/Movecraft/src/main/java/net/countercraft/movecraft/craft/ChunkManager.java b/Movecraft/src/main/java/net/countercraft/movecraft/craft/ChunkManager.java index 65d0497b9..1d8c3a2d9 100644 --- a/Movecraft/src/main/java/net/countercraft/movecraft/craft/ChunkManager.java +++ b/Movecraft/src/main/java/net/countercraft/movecraft/craft/ChunkManager.java @@ -1,5 +1,6 @@ package net.countercraft.movecraft.craft; +import jakarta.inject.Inject; import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftChunk; import net.countercraft.movecraft.MovecraftLocation; @@ -19,7 +20,10 @@ @Deprecated public class ChunkManager implements Listener { - + + @Inject + public ChunkManager(){} + private static final Set chunks = new HashSet<>(); public static void addChunksToLoad(Iterable list) { diff --git a/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java b/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java index 0ce37d5ef..b4ed2427c 100644 --- a/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java +++ b/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java @@ -17,6 +17,7 @@ package net.countercraft.movecraft.listener; +import jakarta.inject.Inject; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; @@ -52,6 +53,9 @@ import org.jetbrains.annotations.NotNull; public class BlockListener implements Listener { + @Inject + public BlockListener(){} + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onBlockBreak(@NotNull BlockBreakEvent e) { if (!Settings.ProtectPilotedCrafts) diff --git a/Movecraft/src/main/java/net/countercraft/movecraft/listener/CraftPilotListener.java b/Movecraft/src/main/java/net/countercraft/movecraft/listener/CraftPilotListener.java index 5901cdace..55fb4131d 100644 --- a/Movecraft/src/main/java/net/countercraft/movecraft/listener/CraftPilotListener.java +++ b/Movecraft/src/main/java/net/countercraft/movecraft/listener/CraftPilotListener.java @@ -1,5 +1,6 @@ package net.countercraft.movecraft.listener; +import jakarta.inject.Inject; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.events.CraftPilotEvent; @@ -10,6 +11,8 @@ import org.jetbrains.annotations.NotNull; public class CraftPilotListener implements Listener { + @Inject + public CraftPilotListener(){} @EventHandler(ignoreCancelled = true) public void onCraftPilot(@NotNull CraftPilotEvent event) { diff --git a/Movecraft/src/main/java/net/countercraft/movecraft/listener/CraftReleaseListener.java b/Movecraft/src/main/java/net/countercraft/movecraft/listener/CraftReleaseListener.java index 26c933cdd..bcccacdca 100644 --- a/Movecraft/src/main/java/net/countercraft/movecraft/listener/CraftReleaseListener.java +++ b/Movecraft/src/main/java/net/countercraft/movecraft/listener/CraftReleaseListener.java @@ -1,5 +1,6 @@ package net.countercraft.movecraft.listener; +import jakarta.inject.Inject; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.events.CraftReleaseEvent; @@ -10,6 +11,8 @@ import org.jetbrains.annotations.NotNull; public class CraftReleaseListener implements Listener { + @Inject + public CraftReleaseListener(){} @EventHandler public void onDisassembly(@NotNull CraftReleaseEvent event) { diff --git a/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java b/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java index b12233858..332cf361a 100644 --- a/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java +++ b/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java @@ -17,6 +17,7 @@ package net.countercraft.movecraft.listener; +import jakarta.inject.Inject; import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.craft.PlayerCraft; @@ -37,7 +38,12 @@ import java.util.WeakHashMap; public final class InteractListener implements Listener { - private final Map timeMap = new WeakHashMap<>(); + private final Map timeMap; + + @Inject + public InteractListener() { + timeMap = new WeakHashMap<>(); + } @EventHandler(priority = EventPriority.LOWEST) // LOWEST so that it runs before the other events public void onPlayerInteract(@NotNull PlayerInteractEvent e) { diff --git a/Movecraft/src/main/java/net/countercraft/movecraft/listener/PlayerListener.java b/Movecraft/src/main/java/net/countercraft/movecraft/listener/PlayerListener.java index b9f829be1..efe47b202 100644 --- a/Movecraft/src/main/java/net/countercraft/movecraft/listener/PlayerListener.java +++ b/Movecraft/src/main/java/net/countercraft/movecraft/listener/PlayerListener.java @@ -17,6 +17,7 @@ package net.countercraft.movecraft.listener; +import jakarta.inject.Inject; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; @@ -42,7 +43,12 @@ import java.util.WeakHashMap; public class PlayerListener implements Listener { - private final Map timeToReleaseAfter = new WeakHashMap<>(); + private final Map timeToReleaseAfter; + + @Inject + public PlayerListener() { + timeToReleaseAfter = new WeakHashMap<>(); + } private Set checkCraftBorders(Craft craft) { Set mergePoints = new HashSet<>(); diff --git a/Movecraft/src/main/java/net/countercraft/movecraft/localisation/I18nSupport.java b/Movecraft/src/main/java/net/countercraft/movecraft/localisation/I18nSupport.java index 1a324425b..4d4a601f9 100644 --- a/Movecraft/src/main/java/net/countercraft/movecraft/localisation/I18nSupport.java +++ b/Movecraft/src/main/java/net/countercraft/movecraft/localisation/I18nSupport.java @@ -19,8 +19,10 @@ import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.config.Settings; +import net.countercraft.movecraft.lifecycle.Service; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.TextComponent; +import org.bukkit.plugin.Plugin; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; @@ -34,10 +36,28 @@ import java.util.Properties; import java.util.logging.Level; -public class I18nSupport { +public class I18nSupport implements Service { private static Properties languageFile; + private final @NotNull Plugin plugin; - public static void init() { + public I18nSupport(@NotNull Plugin plugin){ + this.plugin = plugin; + } + + @Override + public void start() { + String[] localisations = {"en", "cz", "nl", "fr"}; + for (String locale : localisations) { + var file = new File("%s/localisation/movecraftlang_%s.properties".formatted(plugin.getDataFolder(), locale)); + if (!file.exists()) { + plugin.saveResource("localisation/movecraftlang_%s.properties".formatted(locale), false); + } + } + + init(); + } + + private static void init() { languageFile = new Properties(); File localisationDirectory = new File(Movecraft.getInstance().getDataFolder().getAbsolutePath() + "/localisation"); diff --git a/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/MapUpdateManager.java b/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/MapUpdateManager.java index a590212a3..fb813df67 100644 --- a/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/MapUpdateManager.java +++ b/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/MapUpdateManager.java @@ -18,8 +18,10 @@ package net.countercraft.movecraft.mapUpdater; import net.countercraft.movecraft.Movecraft; +import net.countercraft.movecraft.lifecycle.Service; import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.mapUpdater.update.UpdateCommand; +import org.bukkit.plugin.Plugin; import org.bukkit.scheduler.BukkitRunnable; import org.jetbrains.annotations.NotNull; @@ -30,19 +32,18 @@ import java.util.logging.Logger; @Deprecated -public class MapUpdateManager extends BukkitRunnable { +public class MapUpdateManager extends BukkitRunnable implements Service { + private final Queue updates; + private final @NotNull Plugin plugin; - private final Queue updates = new ConcurrentLinkedQueue<>(); -// private final Queue updates = new LinkedBlockingQueue<>(); - //private PriorityQueue updateQueue = new PriorityQueue<>(); - - //@Deprecated - //public HashMap blockUpdatesPerCraft = new HashMap<>(); - - private MapUpdateManager() { } + public MapUpdateManager(@NotNull Plugin plugin) { + this.plugin = plugin; + this.updates = new ConcurrentLinkedQueue<>(); + } - public static MapUpdateManager getInstance() { - return MapUpdateManagerHolder.INSTANCE; + @Override + public void start(){ + this.runTaskTimer(plugin, 0, 1); } public void run() { diff --git a/Movecraft/src/main/java/net/countercraft/movecraft/sign/AscendSign.java b/Movecraft/src/main/java/net/countercraft/movecraft/sign/AscendSign.java index e59193e3b..4e4afad6f 100644 --- a/Movecraft/src/main/java/net/countercraft/movecraft/sign/AscendSign.java +++ b/Movecraft/src/main/java/net/countercraft/movecraft/sign/AscendSign.java @@ -1,5 +1,6 @@ package net.countercraft.movecraft.sign; +import jakarta.inject.Inject; import net.countercraft.movecraft.CruiseDirection; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.craft.Craft; @@ -20,6 +21,8 @@ import org.jetbrains.annotations.NotNull; public class AscendSign implements Listener { + @Inject + public AscendSign(){} @EventHandler public void onCraftDetect(CraftDetectEvent event){ diff --git a/Movecraft/src/main/java/net/countercraft/movecraft/sign/CraftSign.java b/Movecraft/src/main/java/net/countercraft/movecraft/sign/CraftSign.java index ec5a977c5..2d82d4671 100644 --- a/Movecraft/src/main/java/net/countercraft/movecraft/sign/CraftSign.java +++ b/Movecraft/src/main/java/net/countercraft/movecraft/sign/CraftSign.java @@ -1,5 +1,6 @@ package net.countercraft.movecraft.sign; +import jakarta.inject.Inject; import net.countercraft.movecraft.CruiseDirection; import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftLocation; @@ -37,7 +38,12 @@ import java.util.Set; public final class CraftSign implements Listener { - private final Set piloting = new HashSet<>(); + private final Set piloting; + + @Inject + public CraftSign() { + piloting = new HashSet<>(); + } @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) public void onSignChange(@NotNull SignChangeEvent event) { diff --git a/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java b/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java index fd4efec28..a779b9c57 100644 --- a/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java +++ b/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java @@ -1,5 +1,6 @@ package net.countercraft.movecraft.sign; +import jakarta.inject.Inject; import net.countercraft.movecraft.CruiseDirection; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.config.Settings; @@ -24,6 +25,8 @@ import org.jetbrains.annotations.NotNull; public final class CruiseSign implements Listener { + @Inject + public CruiseSign(){} @EventHandler public void onCraftDetect(@NotNull CraftDetectEvent event) { diff --git a/Movecraft/src/main/java/net/countercraft/movecraft/sign/DescendSign.java b/Movecraft/src/main/java/net/countercraft/movecraft/sign/DescendSign.java index 2d638689b..ec66576ce 100644 --- a/Movecraft/src/main/java/net/countercraft/movecraft/sign/DescendSign.java +++ b/Movecraft/src/main/java/net/countercraft/movecraft/sign/DescendSign.java @@ -1,5 +1,6 @@ package net.countercraft.movecraft.sign; +import jakarta.inject.Inject; import net.countercraft.movecraft.CruiseDirection; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.craft.Craft; @@ -19,6 +20,8 @@ import org.jetbrains.annotations.NotNull; public final class DescendSign implements Listener{ + @Inject + public DescendSign(){} @EventHandler public void onCraftDetect(CraftDetectEvent event){ diff --git a/Movecraft/src/main/java/net/countercraft/movecraft/sign/HelmSign.java b/Movecraft/src/main/java/net/countercraft/movecraft/sign/HelmSign.java index 74eef63fa..d62987a8d 100644 --- a/Movecraft/src/main/java/net/countercraft/movecraft/sign/HelmSign.java +++ b/Movecraft/src/main/java/net/countercraft/movecraft/sign/HelmSign.java @@ -1,5 +1,6 @@ package net.countercraft.movecraft.sign; +import jakarta.inject.Inject; import net.countercraft.movecraft.MovecraftRotation; import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.craft.CraftManager; @@ -18,6 +19,8 @@ import org.jetbrains.annotations.NotNull; public final class HelmSign implements Listener { + @Inject + public HelmSign(){} @EventHandler public void onSignChange(SignChangeEvent event){ diff --git a/Movecraft/src/main/java/net/countercraft/movecraft/sign/MoveSign.java b/Movecraft/src/main/java/net/countercraft/movecraft/sign/MoveSign.java index 37c0f00d4..7e83ca1f5 100644 --- a/Movecraft/src/main/java/net/countercraft/movecraft/sign/MoveSign.java +++ b/Movecraft/src/main/java/net/countercraft/movecraft/sign/MoveSign.java @@ -1,5 +1,6 @@ package net.countercraft.movecraft.sign; +import jakarta.inject.Inject; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.craft.type.CraftType; import net.countercraft.movecraft.localisation.I18nSupport; @@ -16,6 +17,9 @@ public final class MoveSign implements Listener{ private static final String HEADER = "Move:"; + @Inject + public MoveSign(){} + @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) public void onSignClick(@NotNull PlayerInteractEvent event) { if (event.getAction() != Action.RIGHT_CLICK_BLOCK) { diff --git a/Movecraft/src/main/java/net/countercraft/movecraft/sign/NameSign.java b/Movecraft/src/main/java/net/countercraft/movecraft/sign/NameSign.java index 787f3711c..25c21d417 100644 --- a/Movecraft/src/main/java/net/countercraft/movecraft/sign/NameSign.java +++ b/Movecraft/src/main/java/net/countercraft/movecraft/sign/NameSign.java @@ -1,5 +1,6 @@ package net.countercraft.movecraft.sign; +import jakarta.inject.Inject; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; @@ -25,6 +26,10 @@ public final class NameSign implements Listener { private static final String HEADER = "Name:"; + + @Inject + public NameSign(){} + @EventHandler public void onCraftDetect(@NotNull CraftDetectEvent event) { Craft c = event.getCraft(); diff --git a/Movecraft/src/main/java/net/countercraft/movecraft/sign/PilotSign.java b/Movecraft/src/main/java/net/countercraft/movecraft/sign/PilotSign.java index 9ed6cd230..bb124f1fb 100644 --- a/Movecraft/src/main/java/net/countercraft/movecraft/sign/PilotSign.java +++ b/Movecraft/src/main/java/net/countercraft/movecraft/sign/PilotSign.java @@ -1,5 +1,6 @@ package net.countercraft.movecraft.sign; +import jakarta.inject.Inject; import org.bukkit.ChatColor; import org.bukkit.block.Block; import org.bukkit.block.Sign; @@ -13,6 +14,10 @@ public final class PilotSign implements Listener { private static final String HEADER = "Pilot:"; + + @Inject + public PilotSign(){} + @EventHandler public final void onSignChange(SignChangeEvent event){ if (event.getLine(0).equalsIgnoreCase(HEADER)) { diff --git a/Movecraft/src/main/java/net/countercraft/movecraft/sign/RelativeMoveSign.java b/Movecraft/src/main/java/net/countercraft/movecraft/sign/RelativeMoveSign.java index 2e187d3fb..a9f23a8ca 100644 --- a/Movecraft/src/main/java/net/countercraft/movecraft/sign/RelativeMoveSign.java +++ b/Movecraft/src/main/java/net/countercraft/movecraft/sign/RelativeMoveSign.java @@ -1,5 +1,6 @@ package net.countercraft.movecraft.sign; +import jakarta.inject.Inject; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.craft.type.CraftType; import net.countercraft.movecraft.localisation.I18nSupport; @@ -16,6 +17,9 @@ public final class RelativeMoveSign implements Listener{ private static final String HEADER = "RMove:"; + @Inject + public RelativeMoveSign(){} + @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) public void onSignClick(@NotNull PlayerInteractEvent event) { if (event.getAction() != Action.RIGHT_CLICK_BLOCK) { diff --git a/Movecraft/src/main/java/net/countercraft/movecraft/sign/ReleaseSign.java b/Movecraft/src/main/java/net/countercraft/movecraft/sign/ReleaseSign.java index 91e9aa544..50f978d04 100644 --- a/Movecraft/src/main/java/net/countercraft/movecraft/sign/ReleaseSign.java +++ b/Movecraft/src/main/java/net/countercraft/movecraft/sign/ReleaseSign.java @@ -1,5 +1,6 @@ package net.countercraft.movecraft.sign; +import jakarta.inject.Inject; import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.events.CraftReleaseEvent; @@ -16,6 +17,9 @@ public final class ReleaseSign implements Listener{ private static final String HEADER = "Release"; + @Inject + public ReleaseSign(){} + @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) public void onSignClick(@NotNull PlayerInteractEvent event) { if (event.getAction() != Action.RIGHT_CLICK_BLOCK) { diff --git a/Movecraft/src/main/java/net/countercraft/movecraft/sign/RemoteSign.java b/Movecraft/src/main/java/net/countercraft/movecraft/sign/RemoteSign.java index f9bad8835..79eb9d5c5 100644 --- a/Movecraft/src/main/java/net/countercraft/movecraft/sign/RemoteSign.java +++ b/Movecraft/src/main/java/net/countercraft/movecraft/sign/RemoteSign.java @@ -1,5 +1,6 @@ package net.countercraft.movecraft.sign; +import jakarta.inject.Inject; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; @@ -28,6 +29,9 @@ public final class RemoteSign implements Listener{ private static final String HEADER = "Remote Sign"; + @Inject + public RemoteSign(){} + @EventHandler public final void onSignChange(SignChangeEvent event) { if (!event.getLine(0).equalsIgnoreCase(HEADER)) { diff --git a/Movecraft/src/main/java/net/countercraft/movecraft/sign/ScuttleSign.java b/Movecraft/src/main/java/net/countercraft/movecraft/sign/ScuttleSign.java index 39f9fd215..e8e33ee7f 100644 --- a/Movecraft/src/main/java/net/countercraft/movecraft/sign/ScuttleSign.java +++ b/Movecraft/src/main/java/net/countercraft/movecraft/sign/ScuttleSign.java @@ -1,5 +1,6 @@ package net.countercraft.movecraft.sign; +import jakarta.inject.Inject; import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.craft.SinkingCraft; @@ -23,9 +24,11 @@ import static net.countercraft.movecraft.util.ChatUtils.MOVECRAFT_COMMAND_PREFIX; public class ScuttleSign implements Listener { - private static final String HEADER = "Scuttle"; + @Inject + public ScuttleSign(){} + @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) public void onSignClick(@NotNull PlayerInteractEvent event) { if (event.getAction() != Action.RIGHT_CLICK_BLOCK) diff --git a/Movecraft/src/main/java/net/countercraft/movecraft/sign/SpeedSign.java b/Movecraft/src/main/java/net/countercraft/movecraft/sign/SpeedSign.java index 1d77fee88..4d3cd5ed1 100644 --- a/Movecraft/src/main/java/net/countercraft/movecraft/sign/SpeedSign.java +++ b/Movecraft/src/main/java/net/countercraft/movecraft/sign/SpeedSign.java @@ -1,5 +1,6 @@ package net.countercraft.movecraft.sign; +import jakarta.inject.Inject; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.craft.CraftManager; @@ -21,7 +22,10 @@ import org.bukkit.event.block.Action; import org.bukkit.event.player.PlayerInteractEvent; -public final class SpeedSign implements Listener{ +public final class SpeedSign implements Listener { + @Inject + public SpeedSign(){} + @EventHandler public void onCraftDetect(CraftDetectEvent event){ World world = event.getCraft().getWorld(); diff --git a/Movecraft/src/main/java/net/countercraft/movecraft/sign/SubcraftRotateSign.java b/Movecraft/src/main/java/net/countercraft/movecraft/sign/SubcraftRotateSign.java index c8469fa38..c2ffc3e28 100644 --- a/Movecraft/src/main/java/net/countercraft/movecraft/sign/SubcraftRotateSign.java +++ b/Movecraft/src/main/java/net/countercraft/movecraft/sign/SubcraftRotateSign.java @@ -1,5 +1,6 @@ package net.countercraft.movecraft.sign; +import jakarta.inject.Inject; import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.MovecraftRotation; @@ -30,7 +31,12 @@ public final class SubcraftRotateSign implements Listener { private static final String HEADER = "Subcraft Rotate"; - private final Set rotating = new HashSet<>(); + private final Set rotating; + + @Inject + public SubcraftRotateSign() { + rotating = new HashSet<>(); + } @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) public void onSignClick(@NotNull PlayerInteractEvent event) { diff --git a/Movecraft/src/main/java/net/countercraft/movecraft/sign/TeleportSign.java b/Movecraft/src/main/java/net/countercraft/movecraft/sign/TeleportSign.java index 4f41f6db5..d6dc2a182 100644 --- a/Movecraft/src/main/java/net/countercraft/movecraft/sign/TeleportSign.java +++ b/Movecraft/src/main/java/net/countercraft/movecraft/sign/TeleportSign.java @@ -1,5 +1,6 @@ package net.countercraft.movecraft.sign; +import jakarta.inject.Inject; import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.craft.type.CraftType; @@ -19,6 +20,9 @@ public final class TeleportSign implements Listener { private static final String HEADER = "Teleport:"; + @Inject + public TeleportSign(){} + @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) public void onSignClick(@NotNull PlayerInteractEvent event) { if (event.getAction() != Action.RIGHT_CLICK_BLOCK) { diff --git a/Movecraft/src/main/java/net/countercraft/movecraft/support/SmoothTeleportFactory.java b/Movecraft/src/main/java/net/countercraft/movecraft/support/SmoothTeleportFactory.java new file mode 100644 index 000000000..4ece5b3f2 --- /dev/null +++ b/Movecraft/src/main/java/net/countercraft/movecraft/support/SmoothTeleportFactory.java @@ -0,0 +1,42 @@ +package net.countercraft.movecraft.support; + +import jakarta.inject.Provider; +import net.countercraft.movecraft.SmoothTeleport; +import net.countercraft.movecraft.config.Settings; +import net.countercraft.movecraft.util.BukkitTeleport; +import org.jetbrains.annotations.NotNull; + +import java.util.logging.Logger; + +public class SmoothTeleportFactory implements Provider { + private final @NotNull Logger logger; + private final @NotNull VersionInfo versionInfo; + + public SmoothTeleportFactory(@NotNull Logger logger, @NotNull VersionInfo versionInfo) { + this.logger = logger; + this.versionInfo = versionInfo; + } + + public SmoothTeleport get(){ + try { + // Try to set up the smooth teleport handler + final Class smoothTeleportClazz = Class.forName("net.countercraft.movecraft.support." + versionInfo.getPackageName() + ".ISmoothTeleport"); + if (SmoothTeleport.class.isAssignableFrom(smoothTeleportClazz)) { + return (SmoothTeleport) smoothTeleportClazz.getConstructor().newInstance(); + } + + // Fall back to bukkit teleportation + logger.warning("Did not find smooth teleport, falling back to bukkit teleportation provider."); + + return new BukkitTeleport(); + } catch (final ReflectiveOperationException e) { + // Fall back to bukkit teleportation + logger.warning("Falling back to bukkit teleportation provider."); + if (Settings.Debug) { + e.printStackTrace(); + } + + return new BukkitTeleport(); + } + } +} diff --git a/Movecraft/src/main/java/net/countercraft/movecraft/support/WorldHandlerFactory.java b/Movecraft/src/main/java/net/countercraft/movecraft/support/WorldHandlerFactory.java new file mode 100644 index 000000000..606bcf6ec --- /dev/null +++ b/Movecraft/src/main/java/net/countercraft/movecraft/support/WorldHandlerFactory.java @@ -0,0 +1,41 @@ +package net.countercraft.movecraft.support; + +import jakarta.inject.Provider; +import net.countercraft.movecraft.WorldHandler; +import net.countercraft.movecraft.config.Settings; +import org.jetbrains.annotations.NotNull; + +import java.util.logging.Logger; + +public class WorldHandlerFactory implements Provider { + private final @NotNull Logger logger; + private final @NotNull VersionInfo versionInfo; + + public WorldHandlerFactory(@NotNull Logger logger, @NotNull VersionInfo versionInfo) { + this.logger = logger; + this.versionInfo = versionInfo; + } + + @Override + public WorldHandler get() { + try { + final Class worldHandlerClazz = Class.forName("net.countercraft.movecraft.compat." + versionInfo.getPackageName() + ".IWorldHandler"); + // Check if we have a NMSHandler class at that location. + if (WorldHandler.class.isAssignableFrom(worldHandlerClazz)) { // Make sure it actually implements NMS + return (WorldHandler) worldHandlerClazz.getConstructor().newInstance(); // Set our handler + } + } catch (final Exception e) { + if (!Settings.DisableNMSCompatibilityCheck) { + throw new IllegalStateException("Could not find support for version %s.".formatted(versionInfo.version())); + } + } + + // Server owner claims to know what they are doing, warn them of the possible consequences + logger.severe(""" + WARNING! + Running Movecraft on an incompatible version can corrupt your world and break EVERYTHING! + We provide no support for any issues."""); + + return null; + } +} diff --git a/api/build.gradle.kts b/api/build.gradle.kts index 9c72f6524..49f01cd96 100644 --- a/api/build.gradle.kts +++ b/api/build.gradle.kts @@ -16,6 +16,7 @@ dependencies { api(libs.it.unimi.dsi.fastutil) api(libs.net.kyori.adventure.api) api(libs.net.kyori.adventure.platform.bukkit) + api(libs.org.int4j.dirk.dirk.di) testImplementation(libs.org.junit.jupiter.junit.jupiter.api) testImplementation(libs.junit.junit) testImplementation(libs.org.hamcrest.hamcrest.library) diff --git a/api/src/main/java/net/countercraft/movecraft/WorldHandler.java b/api/src/main/java/net/countercraft/movecraft/WorldHandler.java index 3b72e569f..d4e629cc3 100644 --- a/api/src/main/java/net/countercraft/movecraft/WorldHandler.java +++ b/api/src/main/java/net/countercraft/movecraft/WorldHandler.java @@ -20,6 +20,7 @@ public abstract class WorldHandler { @Deprecated(forRemoval = true) public abstract void setAccessLocation(@NotNull InventoryView inventoryView, @NotNull Location location); // Not needed for 1.20+, remove when dropping support for 1.18.2 + @Deprecated public static @NotNull String getPackageName(@NotNull String minecraftVersion) { String[] parts = minecraftVersion.split("\\."); if (parts.length < 2) diff --git a/api/src/main/java/net/countercraft/movecraft/config/DataPackService.java b/api/src/main/java/net/countercraft/movecraft/config/DataPackService.java new file mode 100644 index 000000000..19649d12a --- /dev/null +++ b/api/src/main/java/net/countercraft/movecraft/config/DataPackService.java @@ -0,0 +1,121 @@ +package net.countercraft.movecraft.config; + +import io.papermc.paper.datapack.Datapack; +import net.countercraft.movecraft.lifecycle.Service; +import org.bukkit.Server; +import org.bukkit.plugin.Plugin; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.logging.Logger; + +public class DataPackService implements Service { + private final @NotNull Plugin plugin; + private final @NotNull Logger logger; + private boolean isInitialized; + + public DataPackService(@NotNull Plugin plugin, @NotNull Logger logger) { + this.plugin = plugin; + this.logger = logger; + } + + @Override + public void start() { + isInitialized = isDatapackEnabled() || initializeDatapack(); + } + + public boolean isDatapackInitialized(){ + return isInitialized; + } + + private boolean initializeDatapack() { + File datapackDirectory = null; + Server server = plugin.getServer(); + + for(var world : server.getWorlds()) { + datapackDirectory = new File(world.getWorldFolder(), "datapacks"); + if(datapackDirectory.exists()) { + break; + } + } + + if(datapackDirectory == null) { + logger.severe("Failed to initialize Movecraft data pack due to first time world initialization."); + + return false; + } + + if(!datapackDirectory.exists()) { + logger.info("Creating a datapack directory at " + datapackDirectory.getPath()); + if(!datapackDirectory.mkdir()) { + logger.severe("Failed to create datapack directory!"); + + return false; + } + } else if(new File(datapackDirectory, "movecraft-data.zip").exists()) { + logger.warning("Conflicting datapack already exists in " + datapackDirectory.getPath() + ". If you would like to regenerate the datapack, delete the existing one."); + + return false; + } + + if(!datapackDirectory.canWrite()) { + logger.warning("Missing permissions to write to world directory."); + + return false; + } + + try(var stream = new FileOutputStream(new File(datapackDirectory, "movecraft-data.zip")); + var pack = plugin.getResource("movecraft-data.zip")) { + if(pack == null) { + logger.severe("No internal datapack found, report this."); + + return false; + } + + pack.transferTo(stream); + } + catch(IOException e) { + e.printStackTrace(); + + return false; + } + + logger.info("Saved default Movecraft datapack."); + server.dispatchCommand(server.createCommandSender(response -> {}), "datapack list"); // list datapacks to trigger the server to check + for (Datapack datapack : server.getDatapackManager().getPacks()) { + if (!datapack.getName().equals("file/movecraft-data.zip")) { + continue; + } + + if (!datapack.isEnabled()) { + datapack.setEnabled(true); + logger.info("Datapack enabled."); + } + + break; + } + + if (!isDatapackEnabled()) { + throw new IllegalStateException("Failed to automatically load movecraft datapack. Check if it exists."); + } + + return true; + } + + private boolean isDatapackEnabled() { + Server server = plugin.getServer(); + server.dispatchCommand(server.createCommandSender(response -> {}), "datapack list"); // list datapacks to trigger the server to check + for (Datapack datapack : server.getDatapackManager().getPacks()) { + if (!datapack.getName().equals("file/movecraft-data.zip")) { + continue; + } + + return datapack.isEnabled(); + } + + return false; + } + +} diff --git a/api/src/main/java/net/countercraft/movecraft/config/Settings.java b/api/src/main/java/net/countercraft/movecraft/config/Settings.java index 122d0b5a5..d69a94d76 100644 --- a/api/src/main/java/net/countercraft/movecraft/config/Settings.java +++ b/api/src/main/java/net/countercraft/movecraft/config/Settings.java @@ -23,6 +23,7 @@ import java.util.HashSet; import java.util.Map; +// TODO: De-static public class Settings { public static boolean IGNORE_RESET = false; public static boolean Debug = false; diff --git a/api/src/main/java/net/countercraft/movecraft/config/SettingsService.java b/api/src/main/java/net/countercraft/movecraft/config/SettingsService.java new file mode 100644 index 000000000..c1f9a6470 --- /dev/null +++ b/api/src/main/java/net/countercraft/movecraft/config/SettingsService.java @@ -0,0 +1,79 @@ +package net.countercraft.movecraft.config; + +import jakarta.inject.Inject; +import jakarta.inject.Provider; +import net.countercraft.movecraft.lifecycle.Service; +import net.countercraft.movecraft.util.Tags; +import org.bukkit.Material; +import org.bukkit.configuration.Configuration; +import org.int4.dirk.api.Injector; +import org.int4.dirk.di.Injectors; +import org.jetbrains.annotations.NotNull; + +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.logging.Logger; + +public class SettingsService implements Service { + private final @NotNull Configuration configuration; + private final @NotNull Logger logger; + + @Inject + public SettingsService(@NotNull Configuration configuration, @NotNull Logger logger) { + this.configuration = configuration; + this.logger = logger; + } + + @Override + public void start() { + Settings.LOCALE = configuration.getString("Locale"); + Settings.Debug = configuration.getBoolean("Debug", false); + Settings.DisableNMSCompatibilityCheck = configuration.getBoolean("IReallyKnowWhatIAmDoing", false); + Settings.DisableSpillProtection = configuration.getBoolean("DisableSpillProtection", false); + Settings.DisableIceForm = configuration.getBoolean("DisableIceForm", true); + Settings.ReleaseOnDeath = configuration.getBoolean("ReleaseOnDeath", false); + Settings.SinkCheckTicks = configuration.getDouble("SinkCheckTicks", 100.0); + Settings.ManOverboardTimeout = configuration.getInt("ManOverboardTimeout", 30); + Settings.ManOverboardDistSquared = Math.pow(configuration.getDouble("ManOverboardDistance", 1000), 2); + Settings.SilhouetteViewDistance = configuration.getInt("SilhouetteViewDistance", 200); + Settings.SilhouetteBlockCount = configuration.getInt("SilhouetteBlockCount", 20); + Settings.ProtectPilotedCrafts = configuration.getBoolean("ProtectPilotedCrafts", false); + Settings.MaxRemoteSigns = configuration.getInt("MaxRemoteSigns", -1); + Settings.CraftsUseNetherPortals = configuration.getBoolean("CraftsUseNetherPortals", false); + Settings.RequireCreatePerm = configuration.getBoolean("RequireCreatePerm", false); + Settings.RequireNamePerm = configuration.getBoolean("RequireNamePerm", true); + Settings.FadeWrecksAfter = configuration.getInt("FadeWrecksAfter", 0); + Settings.FadeTickCooldown = configuration.getInt("FadeTickCooldown", 20); + Settings.FadePercentageOfWreckPerCycle = configuration.getDouble("FadePercentageOfWreckPerCycle", 10.0); + + // if the PilotTool is specified in the config.yml file, use it + String pilotTool = configuration.getString("PilotTool"); + if (pilotTool != null) { + Material material = Material.getMaterial(pilotTool); + if (material != null) { + logger.info("Recognized PilotTool setting of: " + pilotTool); + Settings.PilotTool = material; + } + else { + logger.info("No PilotTool setting, using default of stick"); + } + } + else { + logger.info("No PilotTool setting, using default of stick"); + } + + if (configuration.contains("ExtraFadeTimePerBlock")) { + Map temp = configuration.getConfigurationSection("ExtraFadeTimePerBlock").getValues(false); + for (String str : temp.keySet()) { + Set materials = Tags.parseMaterials(str); + for (Material m : materials) { + Settings.ExtraFadeTimePerBlock.put(m, (Integer) temp.get(str)); + } + } + } + + Settings.ForbiddenRemoteSigns = new HashSet<>(configuration.getStringList("ForbiddenRemoteSigns")); + } + +} diff --git a/api/src/main/java/net/countercraft/movecraft/lifecycle/ListenerLifecycleService.java b/api/src/main/java/net/countercraft/movecraft/lifecycle/ListenerLifecycleService.java new file mode 100644 index 000000000..9d53931ec --- /dev/null +++ b/api/src/main/java/net/countercraft/movecraft/lifecycle/ListenerLifecycleService.java @@ -0,0 +1,24 @@ +package net.countercraft.movecraft.lifecycle; + +import jakarta.inject.Inject; +import org.bukkit.event.Listener; +import org.bukkit.plugin.Plugin; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public class ListenerLifecycleService implements Service { + private final @NotNull List listeners; + private final @NotNull Plugin plugin; + + @Inject + public ListenerLifecycleService(@NotNull List listeners, @NotNull Plugin plugin){ + this.listeners = listeners; + this.plugin = plugin; + } + + @Override + public void start() { + listeners.forEach(listener -> plugin.getServer().getPluginManager().registerEvents(listener, plugin)); + } +} diff --git a/api/src/main/java/net/countercraft/movecraft/lifecycle/Service.java b/api/src/main/java/net/countercraft/movecraft/lifecycle/Service.java new file mode 100644 index 000000000..543678977 --- /dev/null +++ b/api/src/main/java/net/countercraft/movecraft/lifecycle/Service.java @@ -0,0 +1,6 @@ +package net.countercraft.movecraft.lifecycle; + +public interface Service { + default void start(){} + default void stop(){} +} diff --git a/api/src/main/java/net/countercraft/movecraft/lifecycle/ServiceHost.java b/api/src/main/java/net/countercraft/movecraft/lifecycle/ServiceHost.java new file mode 100644 index 000000000..03973f01b --- /dev/null +++ b/api/src/main/java/net/countercraft/movecraft/lifecycle/ServiceHost.java @@ -0,0 +1,23 @@ +package net.countercraft.movecraft.lifecycle; + +import jakarta.inject.Inject; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public class ServiceHost { + private final @NotNull List services; + + @Inject + public ServiceHost(@NotNull List services) { + this.services = services; + } + + public void startAll(){ + services.forEach(Service::start); + } + + public void stopAll(){ + services.forEach(Service::stop); + } +} diff --git a/api/src/main/java/net/countercraft/movecraft/lifecycle/Worker.java b/api/src/main/java/net/countercraft/movecraft/lifecycle/Worker.java new file mode 100644 index 000000000..a1b89cba5 --- /dev/null +++ b/api/src/main/java/net/countercraft/movecraft/lifecycle/Worker.java @@ -0,0 +1,13 @@ +package net.countercraft.movecraft.lifecycle; + +public interface Worker { + default int getDelay(){ + return 1; + } + + boolean isAsync(); + + int getPeriod(); + + void run(); +} diff --git a/api/src/main/java/net/countercraft/movecraft/lifecycle/WorkerServiceHost.java b/api/src/main/java/net/countercraft/movecraft/lifecycle/WorkerServiceHost.java new file mode 100644 index 000000000..b8c1ee5d1 --- /dev/null +++ b/api/src/main/java/net/countercraft/movecraft/lifecycle/WorkerServiceHost.java @@ -0,0 +1,38 @@ +package net.countercraft.movecraft.lifecycle; + +import org.bukkit.plugin.Plugin; +import org.bukkit.scheduler.BukkitTask; +import org.jetbrains.annotations.NotNull; + +import java.util.List; +import java.util.stream.Collectors; + +public class WorkerServiceHost implements Service { + private final @NotNull Plugin plugin; + private final @NotNull List workers; + private @NotNull List tasks; + + public WorkerServiceHost(@NotNull Plugin plugin, @NotNull List workers) { + this.plugin = plugin; + this.workers = workers; + tasks = List.of(); + } + + @Override + public void start() { + tasks = workers.stream().map(worker -> { + if(worker.isAsync()){ + return plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, worker::run, worker.getDelay(), worker.getPeriod()); + } else { + return plugin.getServer().getScheduler().runTaskTimer(plugin, worker::run, worker.getDelay(), worker.getPeriod()); + } + }).collect(Collectors.toList()); + } + + @Override + public void stop() { + var oldTasks = tasks; + tasks = List.of(); + oldTasks.forEach(BukkitTask::cancel); + } +} diff --git a/api/src/main/java/net/countercraft/movecraft/processing/WorldManager.java b/api/src/main/java/net/countercraft/movecraft/processing/WorldManager.java index 74378240d..894b20171 100644 --- a/api/src/main/java/net/countercraft/movecraft/processing/WorldManager.java +++ b/api/src/main/java/net/countercraft/movecraft/processing/WorldManager.java @@ -1,8 +1,13 @@ package net.countercraft.movecraft.processing; +import jakarta.inject.Inject; +import net.countercraft.movecraft.lifecycle.Service; +import net.countercraft.movecraft.lifecycle.Worker; import net.countercraft.movecraft.processing.effects.Effect; import net.countercraft.movecraft.util.CompletableFutureTask; import org.bukkit.Bukkit; +import org.bukkit.plugin.Plugin; +import org.bukkit.scheduler.BukkitTask; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -20,9 +25,13 @@ /** * */ -public final class WorldManager implements Executor { - +public final class WorldManager implements Executor, Worker { + /** + * @deprecated Prefer dependency injection over static accessors + */ + @Deprecated public static final WorldManager INSTANCE = new WorldManager(); + private static final Runnable POISON = new Runnable() { @Override public void run() {/* No-op */} @@ -39,6 +48,16 @@ public String toString(){ private WorldManager(){} + @Override + public boolean isAsync() { + return false; + } + + @Override + public int getPeriod() { + return 1; + } + public void run() { if(!Bukkit.isPrimaryThread()){ throw new RuntimeException("WorldManager must be executed on the main thread."); diff --git a/api/src/main/java/net/countercraft/movecraft/support/VersionInfo.java b/api/src/main/java/net/countercraft/movecraft/support/VersionInfo.java new file mode 100644 index 000000000..a03412dea --- /dev/null +++ b/api/src/main/java/net/countercraft/movecraft/support/VersionInfo.java @@ -0,0 +1,13 @@ +package net.countercraft.movecraft.support; + +import org.jetbrains.annotations.NotNull; + +public record VersionInfo(String version) { + public @NotNull String getPackageName() { + String[] parts = version.split("\\."); + if (parts.length < 2) + throw new IllegalArgumentException(); + + return "v1_" + parts[1]; + } +} diff --git a/api/src/main/java/net/countercraft/movecraft/support/VersionProvider.java b/api/src/main/java/net/countercraft/movecraft/support/VersionProvider.java new file mode 100644 index 000000000..6a820773c --- /dev/null +++ b/api/src/main/java/net/countercraft/movecraft/support/VersionProvider.java @@ -0,0 +1,24 @@ +package net.countercraft.movecraft.support; + +import jakarta.inject.Provider; +import net.countercraft.movecraft.WorldHandler; +import net.countercraft.movecraft.config.Settings; +import org.bukkit.plugin.Plugin; +import org.jetbrains.annotations.NotNull; + +import java.util.logging.Logger; + +public class VersionProvider implements Provider { + private final @NotNull Plugin plugin; + + public VersionProvider(@NotNull Plugin plugin) { + this.plugin = plugin; + } + + @Override + public VersionInfo get() { + String minecraftVersion = plugin.getServer().getMinecraftVersion(); + + return new VersionInfo(minecraftVersion); + } +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8ab52af61..541dfbd79 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,6 +8,7 @@ junit-junit = "4.13.2" net-kyori-adventure-api = "4.17.0" net-kyori-adventure-platform-bukkit = "4.3.2" org-hamcrest-hamcrest-library = "1.3" +org-int4j-dirk-dirk-di = "1.0.0-beta1" org-jetbrains-annotations = "24.1.0" org-junit-jupiter-junit-jupiter-api = "5.10.2" org-openjdk-jmh-jmh-core = "1.37" @@ -22,6 +23,7 @@ junit-junit = { module = "junit:junit", version.ref = "junit-junit" } net-kyori-adventure-api = { module = "net.kyori:adventure-api", version.ref = "net-kyori-adventure-api" } net-kyori-adventure-platform-bukkit = { module = "net.kyori:adventure-platform-bukkit", version.ref = "net-kyori-adventure-platform-bukkit" } org-hamcrest-hamcrest-library = { module = "org.hamcrest:hamcrest-library", version.ref = "org-hamcrest-hamcrest-library" } +org-int4j-dirk-dirk-di = { module = "org.int4.dirk:dirk-di", version.ref = "org-int4j-dirk-dirk-di" } org-jetbrains-annotations = { module = "org.jetbrains:annotations", version.ref = "org-jetbrains-annotations" } org-junit-jupiter-junit-jupiter-api = { module = "org.junit.jupiter:junit-jupiter-api", version.ref = "org-junit-jupiter-junit-jupiter-api" } org-openjdk-jmh-jmh-core = { module = "org.openjdk.jmh:jmh-core", version.ref = "org-openjdk-jmh-jmh-core" }