diff --git a/build.gradle b/build.gradle index 6a385620..0f807fca 100644 --- a/build.gradle +++ b/build.gradle @@ -77,7 +77,11 @@ subprojects { from '../LICENSE' } - if (['bukkit', 'plugin'].contains(project.name)) { + if (['paper'].contains(project.name)) { + compileJava.options.release.set 17 + } + + if (['bukkit', 'paper', 'plugin'].contains(project.name)) { shadowJar { destinationDirectory.set(file("$rootDir/target")) archiveClassifier.set('') diff --git a/bukkit/src/main/java/net/william278/husksync/BukkitHuskSync.java b/bukkit/src/main/java/net/william278/husksync/BukkitHuskSync.java index 8c44f263..37b93097 100644 --- a/bukkit/src/main/java/net/william278/husksync/BukkitHuskSync.java +++ b/bukkit/src/main/java/net/william278/husksync/BukkitHuskSync.java @@ -168,7 +168,7 @@ public class BukkitHuskSync extends JavaPlugin implements HuskSync, BukkitTask.S }); // Register events - initialize("events", (plugin) -> this.eventListener = new BukkitEventListener(this)); + initialize("events", (plugin) -> this.eventListener = createEventListener()); // Register commands initialize("commands", (plugin) -> BukkitCommand.Type.registerCommands(this)); @@ -209,6 +209,11 @@ public class BukkitHuskSync extends JavaPlugin implements HuskSync, BukkitTask.S log(Level.INFO, "Successfully disabled HuskSync v" + getPluginVersion()); } + @NotNull + protected BukkitEventListener createEventListener() { + return new BukkitEventListener(this); + } + @Override @NotNull public Set getOnlineUsers() { @@ -259,6 +264,7 @@ public class BukkitHuskSync extends JavaPlugin implements HuskSync, BukkitTask.S @NotNull @Override + @SuppressWarnings("unchecked") public Map> getSerializers() { return serializers; } diff --git a/common/src/main/java/net/william278/husksync/HuskSync.java b/common/src/main/java/net/william278/husksync/HuskSync.java index 96ae402a..fc7b8b10 100644 --- a/common/src/main/java/net/william278/husksync/HuskSync.java +++ b/common/src/main/java/net/william278/husksync/HuskSync.java @@ -294,10 +294,16 @@ public interface HuskSync extends Task.Supplier, EventDispatcher { default void loadConfigs() { try { // Load settings - setSettings(Annotaml.create(new File(getDataFolder(), "config.yml"), Settings.class).get()); + setSettings(Annotaml.create( + new File(getDataFolder(), "config.yml"), + Settings.class + ).get()); // Load server name - setServer(Annotaml.create(new File(getDataFolder(), "server.yml"), Server.class).get()); + setServer(Annotaml.create( + new File(getDataFolder(), "server.yml"), + Server.getDefault(this) + ).get()); // Load locales from language preset default final Locales languagePresets = Annotaml.create( diff --git a/common/src/main/java/net/william278/husksync/config/Server.java b/common/src/main/java/net/william278/husksync/config/Server.java index b3bb9e7c..bf7771d3 100644 --- a/common/src/main/java/net/william278/husksync/config/Server.java +++ b/common/src/main/java/net/william278/husksync/config/Server.java @@ -19,11 +19,15 @@ package net.william278.husksync.config; +import net.william278.annotaml.Annotaml; import net.william278.annotaml.YamlFile; import net.william278.annotaml.YamlKey; +import net.william278.husksync.HuskSync; import org.jetbrains.annotations.NotNull; +import java.io.File; import java.nio.file.Path; +import java.util.List; /** * Represents a server on a proxied network. @@ -37,26 +41,44 @@ import java.nio.file.Path; ┗╸ If you join it using /server alpha, then set it to 'alpha' (case-sensitive)""") public class Server { + @YamlKey("name") + private String serverName; + + private Server(@NotNull String serverName) { + this.serverName = serverName; + } + + @SuppressWarnings("unused") + private Server() { + } + + @NotNull + public static Server getDefault(@NotNull HuskSync plugin) { + return new Server(getDefaultServerName(plugin)); + } + /** - * Default server identifier. + * Find a sensible default name for the server name property */ @NotNull - public static String getDefaultServerName() { + private static String getDefaultServerName(@NotNull HuskSync plugin) { try { + // Fetch server default from supported plugins if present + for (String s : List.of("HuskHomes", "HuskTowns")) { + final File serverFile = Path.of(plugin.getDataFolder().getParent(), s, "server.yml").toFile(); + if (serverFile.exists()) { + return Annotaml.create(serverFile, Server.class).get().getName(); + } + } + + // Fetch server default from user dir name final Path serverDirectory = Path.of(System.getProperty("user.dir")); return serverDirectory.getFileName().toString().trim(); - } catch (Exception e) { + } catch (Throwable e) { return "server"; } } - @YamlKey("name") - private String serverName = getDefaultServerName(); - - @SuppressWarnings("unused") - private Server() { - } - @Override public boolean equals(@NotNull Object other) { // If the name of this server matches another, the servers are the same. diff --git a/common/src/main/java/net/william278/husksync/config/Settings.java b/common/src/main/java/net/william278/husksync/config/Settings.java index 609427f7..5223c6c4 100644 --- a/common/src/main/java/net/william278/husksync/config/Settings.java +++ b/common/src/main/java/net/william278/husksync/config/Settings.java @@ -165,12 +165,21 @@ public class Settings { private boolean saveOnWorldSave = true; @YamlComment("Whether to create a snapshot for users when they die (containing their death drops)") - @YamlKey("synchronization.save_on_death") + @YamlKey("synchronization.save_on_death.enabled") private boolean saveOnDeath = false; - @YamlComment("Whether to save empty death drops for users when they die") - @YamlKey("synchronization.save_empty_drops_on_death") - private boolean saveEmptyDropsOnDeath = true; + @YamlComment("What items to save in death snapshots? (DROPS or ITEMS_TO_KEEP). " + + " Note that ITEMS_TO_KEEP (suggested for keepInventory servers) requires a Paper 1.19.4+ server.") + @YamlKey("synchronization.save_on_death.items_to_save") + private DeathItemsMode deathItemsMode = DeathItemsMode.DROPS; + + @YamlComment("Should a death snapshot still be created even if the items to save on the player's death are empty?") + @YamlKey("synchronization.save_on_death.save_empty_items") + private boolean saveEmptyDeathItems = true; + + @YamlComment("Whether dead players who log out and log in to a different server should have their items saved.") + @YamlKey("synchronization.save_on_death.sync_dead_players_changing_server") + private boolean synchronizeDeadPlayersChangingServer = true; @YamlComment("Whether to use the snappy data compression algorithm. Keep on unless you know what you're doing") @YamlKey("synchronization.compress_data") @@ -188,11 +197,6 @@ public class Settings { @YamlKey("synchronization.synchronize_max_health") private boolean synchronizeMaxHealth = true; - @YamlComment("Whether dead players who log out and log in to a different server should have their items saved. " - + "You may need to modify this if you're using the keepInventory gamerule.") - @YamlKey("synchronization.synchronize_dead_players_changing_server") - private boolean synchronizeDeadPlayersChangingServer = true; - @YamlComment("If using the DELAY sync method, how long should this server listen for Redis key data updates before " + "pulling data from the database instead (i.e., if the user did not change servers).") @YamlKey("synchronization.network_latency_milliseconds") @@ -341,8 +345,13 @@ public class Settings { return saveOnDeath; } - public boolean doSaveEmptyDropsOnDeath() { - return saveEmptyDropsOnDeath; + @NotNull + public DeathItemsMode getDeathItemsMode() { + return deathItemsMode; + } + + public boolean doSaveEmptyDeathItems() { + return saveEmptyDeathItems; } public boolean doCompressData() { @@ -397,6 +406,14 @@ public class Settings { } } + /** + * Represents the mode of saving items on death + */ + public enum DeathItemsMode { + DROPS, + ITEMS_TO_KEEP + } + /** * Represents the names of tables in the database */ diff --git a/common/src/main/java/net/william278/husksync/listener/EventListener.java b/common/src/main/java/net/william278/husksync/listener/EventListener.java index b3caff15..144fc970 100644 --- a/common/src/main/java/net/william278/husksync/listener/EventListener.java +++ b/common/src/main/java/net/william278/husksync/listener/EventListener.java @@ -88,16 +88,16 @@ public abstract class EventListener { * Handles the saving of data when a player dies * * @param user The user who died - * @param drops The items that this user would have dropped + * @param items The items that should be saved for this user on their death */ - protected void saveOnPlayerDeath(@NotNull OnlineUser user, @NotNull Data.Items drops) { + protected void saveOnPlayerDeath(@NotNull OnlineUser user, @NotNull Data.Items items) { if (plugin.isDisabling() || !plugin.getSettings().doSaveOnDeath() || plugin.isLocked(user.getUuid()) - || user.isNpc() || (!plugin.getSettings().doSaveEmptyDropsOnDeath() && drops.isEmpty())) { + || user.isNpc() || (!plugin.getSettings().doSaveEmptyDeathItems() && items.isEmpty())) { return; } final DataSnapshot.Packed snapshot = user.createSnapshot(DataSnapshot.SaveCause.DEATH); - snapshot.edit(plugin, (data -> data.getInventory().ifPresent(inventory -> inventory.setContents(drops)))); + snapshot.edit(plugin, (data -> data.getInventory().ifPresent(inventory -> inventory.setContents(items)))); plugin.getDatabase().addSnapshot(user, snapshot); } diff --git a/docs/Config-File.md b/docs/Config-File.md index 6fb95715..a168fe49 100644 --- a/docs/Config-File.md +++ b/docs/Config-File.md @@ -75,10 +75,15 @@ synchronization: - MPDB_MIGRATION # Whether to create a snapshot for users on a world when the server saves that world save_on_world_save: true - # Whether to create a snapshot for users when they die (containing their death drops) - save_on_death: false - # Whether to save empty death drops for users when they die - save_empty_drops_on_death: true + save_on_death: + # Whether to create a snapshot for users when they die (containing their death drops) + enabled: true + # What items to save in death snapshots? (DROPS or ITEMS_TO_KEEP). Note that ITEMS_TO_KEEP (suggested for keepInventory servers) requires a Paper 1.19.4+ server + items_to_save: DROPS + # Should a death snapshot still be created even if the items to save on the player's death are empty? + save_empty_items: false + # Whether dead players who log out and log in to a different server should have their items saved. + sync_dead_players_changing_server: true # Whether to use the snappy data compression algorithm. Keep on unless you know what you're doing compress_data: true # Where to display sync notifications (ACTION_BAR, CHAT, TOAST or NONE) @@ -87,8 +92,6 @@ synchronization: persist_locked_maps: true # Whether to synchronize player max health (requires health syncing to be enabled) synchronize_max_health: true - # Whether dead players who log out and log in to a different server should have their items saved. You may need to modify this if you're using the keepInventory gamerule. - synchronize_dead_players_changing_server: true # If using the DELAY sync method, how long should this server listen for Redis key data updates before pulling data from the database instead (i.e., if the user did not change servers). network_latency_milliseconds: 500 # Which data types to synchronize (Docs: https://william278.net/docs/husksync/sync-features) diff --git a/docs/Keep-Inventory.md b/docs/Keep-Inventory.md index 9d6da1ae..b6ebe730 100644 --- a/docs/Keep-Inventory.md +++ b/docs/Keep-Inventory.md @@ -8,23 +8,27 @@ HuskSync has some special handling when players die, to account for scenarios wh * **Snapshot creation on death**—HuskSync can create a special snapshot for backup purposes when a player dies, formed by taking their drops and setting this to their inventory. When `keepInventory` is enabled, the player drops are empty, so this creates an inaccurate snapshot. This option is disabled by default. ## How can this be fixed? -You will need to set the `synchronization.save_on_death` (which controls making snapshots on death), `save_empty_drops_on_death` (which controls whether snapshots of players who have no items to drop should be created), and `synchronization.synchronize_dead_players_changing_server` (which controls whether to sync dead players when they change servers) options to `false` in `config.yml`. +You should change the `items_to_save` mode to `ITEMS_TO_KEEP` instead of drops. Also, ensure `save_empty_items` and `sync_dead_players_changing_server` are enabled.
- Example in config.yml - - ```yml - synchronization: - # ... - save_on_death: false # <-- Set this to false - save_empty_drops_on_death: false # <-- Set this to false - # ... - synchronize_dead_players_changing_server: false # <-- Set this to false - ``` - +Example in config.yml + +```yml + synchronization: + #... + save_on_death: + # Whether to create a snapshot for users when they die (containing their death drops) + enabled: true + # What items to save in death snapshots? (DROPS or ITEMS_TO_KEEP). Note that ITEMS_TO_KEEP (suggested for keepInventory servers) requires a Paper 1.19.4+ server + items_to_save: ITEMS_TO_KEEP + # Should a death snapshot still be created even if the items to save on the player's death are empty? + save_empty_items: true + # Whether dead players who log out and log in to a different server should have their items saved. + sync_dead_players_changing_server: true + #... +```
- ## Troubleshooting with custom keepInventory setups If the above doesn't work for you, you may need to do more things to get this to work properly. diff --git a/docs/Setup.md b/docs/Setup.md index 1bf43e8c..3763996a 100644 --- a/docs/Setup.md +++ b/docs/Setup.md @@ -1,6 +1,8 @@ This will walk you through installing HuskSync on your network of Spigot servers. ## Requirements +> **Note:** If the plugin fails to load, please check that you are not running an [incompatible version combination](Unsupported-Versions) + * A MySQL Database (v8.0+) * A Redis Database (v5.0+) — see [[FAQs]] for more details. * Any number of Spigot servers, connected by a BungeeCord or Velocity-based proxy (Minecraft v1.16.5+, running Java 16+) diff --git a/docs/Sync-Modes.md b/docs/Sync-Modes.md index d48b6007..281c48e9 100644 --- a/docs/Sync-Modes.md +++ b/docs/Sync-Modes.md @@ -1,5 +1,8 @@ -HuskSync offers two built-in **synchronization modes**. These sync modes change the way data is synced between servers. This page details the two sync modes available and how they work. +HuskSync offers two built-in **synchronization modes** that utilise Redis and MySQL to optimally sync data as users change servers (illustrated below). These sync modes change the way data is synced between servers, and can be changed in the `config.yml` file. +![Overall architecture of the synchronisation systems](https://raw.githubusercontent.com/WiIIiam278/HuskSync/master/images/system-diagram.png) + +## Available Modes * The `DELAY` sync mode is the default sync mode, that use the `network_latency_miliseconds` value to apply a delay before listening to Redis data * The `LOCKSTEP` sync mode uses a data checkout system to ensure that all servers are in sync regardless of network latency or tick rate fluctuations. This mode was introduced in HuskSync v3.1 @@ -18,8 +21,6 @@ synchronization: ## Delay -![Delay diagram](https://raw.githubusercontent.com/WiIIiam278/HuskSync/master/images/system-diagram.png) - The `DELAY` sync mode works as described below: * When a user disconnects from a server, a `SERVER_SWITCH` key is immediately set on Redis, followed by a `DATA_UPDATE` key which contains the user's packed and serialized Data Snapshot. * When the user connects to a server, they are marked as locked (unable to break blocks, use containers, etc.) diff --git a/docs/Unsupported-Versions.md b/docs/Unsupported-Versions.md new file mode 100644 index 00000000..7dad2dc0 --- /dev/null +++ b/docs/Unsupported-Versions.md @@ -0,0 +1,10 @@ +This plugin does not support the following software-Minecraft version combinations. The plugin will fail to load if you attempt to run it with these versions. Apologies for the inconvenience. + +## Incompatibility table +| Minecraft Versions | Server Software | Notes | +|--------------------|-------------------------------------------|----------------------------------------| +| 1.19.4 | Only: `Purpur, Pufferfish`† | Older Paper builds also not supported. | +| 1.19.3 | Only: `Paper, Purpur, Pufferfish`† | Upgrade to 1.19.4 or use Spigot | +| below 1.16.5 | _All_ | Upgrade to 1.16.5 | + +†Further downstream forks of this server software are also affected. \ No newline at end of file diff --git a/paper/build.gradle b/paper/build.gradle new file mode 100644 index 00000000..829628ce --- /dev/null +++ b/paper/build.gradle @@ -0,0 +1,41 @@ +dependencies { + implementation project(':bukkit') + compileOnly project(':common') + + compileOnly 'io.papermc.paper:paper-api:1.19.4-R0.1-SNAPSHOT' +} + +shadowJar { + dependencies { + exclude(dependency('com.mojang:brigadier')) + } + + relocate 'org.apache.commons.io', 'net.william278.husksync.libraries.commons.io' + relocate 'org.apache.commons.text', 'net.william278.husksync.libraries.commons.text' + relocate 'org.apache.commons.lang3', 'net.william278.husksync.libraries.commons.lang3' + relocate 'com.google.gson', 'net.william278.husksync.libraries.gson' + relocate 'org.json', 'net.william278.husksync.libraries.json' + relocate 'com.fatboyindustrial', 'net.william278.husksync.libraries' + relocate 'de.themoep', 'net.william278.husksync.libraries' + relocate 'net.kyori', 'net.william278.husksync.libraries' + relocate 'org.jetbrains', 'net.william278.husksync.libraries' + relocate 'org.intellij', 'net.william278.husksync.libraries' + relocate 'com.zaxxer', 'net.william278.husksync.libraries' + relocate 'dev.dejvokep', 'net.william278.husksync.libraries' + relocate 'net.william278.desertwell', 'net.william278.husksync.libraries.desertwell' + relocate 'net.william278.paginedown', 'net.william278.husksync.libraries.paginedown' + relocate 'net.william278.mapdataapi', 'net.william278.husksync.libraries.mapdataapi' + relocate 'net.william278.andjam', 'net.william278.husksync.libraries.andjam' + relocate 'net.querz', 'net.william278.husksync.libraries.nbtparser' + relocate 'net.roxeez', 'net.william278.husksync.libraries' + + relocate 'me.lucko.commodore', 'net.william278.husksync.libraries.commodore' + relocate 'net.byteflux.libby', 'net.william278.husksync.libraries.libby' + relocate 'org.bstats', 'net.william278.husksync.libraries.bstats' + relocate 'dev.triumphteam.gui', 'net.william278.husksync.libraries.triumphgui' + relocate 'net.william278.mpdbconverter', 'net.william278.husksync.libraries.mpdbconverter' + relocate 'net.william278.hslmigrator', 'net.william278.husksync.libraries.hslconverter' + relocate 'net.william278.annotaml', 'net.william278.husksync.libraries.annotaml' + relocate 'space.arim.morepaperlib', 'net.william278.husksync.libraries.paperlib' + relocate 'de.tr7zw.changeme.nbtapi', 'net.william278.husksync.libraries.nbtapi' +} \ No newline at end of file diff --git a/paper/src/main/java/net/william278/husksync/PaperHuskSync.java b/paper/src/main/java/net/william278/husksync/PaperHuskSync.java new file mode 100644 index 00000000..77ede88a --- /dev/null +++ b/paper/src/main/java/net/william278/husksync/PaperHuskSync.java @@ -0,0 +1,35 @@ +/* + * This file is part of HuskSync, licensed under the Apache License 2.0. + * + * Copyright (c) William278 + * Copyright (c) contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.william278.husksync; + +import net.william278.husksync.listener.BukkitEventListener; +import net.william278.husksync.listener.PaperEventListener; +import org.jetbrains.annotations.NotNull; + +@SuppressWarnings("unused") +public class PaperHuskSync extends BukkitHuskSync { + + @NotNull + @Override + protected BukkitEventListener createEventListener() { + return new PaperEventListener(this); + } + +} diff --git a/paper/src/main/java/net/william278/husksync/PaperHuskSyncLoader.java b/paper/src/main/java/net/william278/husksync/PaperHuskSyncLoader.java new file mode 100644 index 00000000..117e879a --- /dev/null +++ b/paper/src/main/java/net/william278/husksync/PaperHuskSyncLoader.java @@ -0,0 +1,82 @@ +/* + * This file is part of HuskSync, licensed under the Apache License 2.0. + * + * Copyright (c) William278 + * Copyright (c) contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.william278.husksync; + +import io.papermc.paper.plugin.loader.PluginClasspathBuilder; +import io.papermc.paper.plugin.loader.PluginLoader; +import io.papermc.paper.plugin.loader.library.impl.MavenLibraryResolver; +import net.william278.annotaml.Annotaml; +import net.william278.annotaml.YamlFile; +import net.william278.annotaml.YamlKey; +import org.eclipse.aether.artifact.DefaultArtifact; +import org.eclipse.aether.graph.Dependency; +import org.eclipse.aether.repository.RemoteRepository; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.InputStream; +import java.util.List; +import java.util.Objects; + +@SuppressWarnings({"UnstableApiUsage", "unused"}) +public class PaperHuskSyncLoader implements PluginLoader { + + @Override + public void classloader(@NotNull PluginClasspathBuilder classpathBuilder) { + MavenLibraryResolver resolver = new MavenLibraryResolver(); + + resolveLibraries(classpathBuilder).stream() + .map(DefaultArtifact::new) + .forEach(artifact -> resolver.addDependency(new Dependency(artifact, null))); + resolver.addRepository(new RemoteRepository.Builder( + "maven", "default", "https://repo.maven.apache.org/maven2/" + ).build()); + + classpathBuilder.addLibrary(resolver); + } + + @NotNull + private static List resolveLibraries(@NotNull PluginClasspathBuilder classpathBuilder) { + try (InputStream input = getLibraryListFile()) { + return Annotaml.create(PaperLibraries.class, Objects.requireNonNull(input)).get().libraries; + } catch (Exception e) { + classpathBuilder.getContext().getLogger().error("Failed to resolve libraries", e); + } + return List.of(); + } + + @Nullable + private static InputStream getLibraryListFile() { + return PaperHuskSyncLoader.class.getClassLoader().getResourceAsStream("paper-libraries.yml"); + } + + @YamlFile(header = "Dependencies for HuskSync on Paper") + public static class PaperLibraries { + + @YamlKey("libraries") + private List libraries; + + @SuppressWarnings("unused") + private PaperLibraries() { + } + + } + +} \ No newline at end of file diff --git a/paper/src/main/java/net/william278/husksync/listener/PaperEventListener.java b/paper/src/main/java/net/william278/husksync/listener/PaperEventListener.java new file mode 100644 index 00000000..9259c0db --- /dev/null +++ b/paper/src/main/java/net/william278/husksync/listener/PaperEventListener.java @@ -0,0 +1,65 @@ +/* + * This file is part of HuskSync, licensed under the Apache License 2.0. + * + * Copyright (c) William278 + * Copyright (c) contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.william278.husksync.listener; + +import net.william278.husksync.BukkitHuskSync; +import net.william278.husksync.data.BukkitData; +import net.william278.husksync.user.BukkitUser; +import net.william278.husksync.user.OnlineUser; +import org.bukkit.event.entity.PlayerDeathEvent; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public class PaperEventListener extends BukkitEventListener { + + public PaperEventListener(@NotNull BukkitHuskSync plugin) { + super(plugin); + } + + @Override + public void handlePlayerDeath(@NotNull PlayerDeathEvent event) { + // If the player is locked or the plugin disabling, clear their drops + final OnlineUser user = BukkitUser.adapt(event.getEntity(), plugin); + if (cancelPlayerEvent(user.getUuid())) { + event.getDrops().clear(); + event.getItemsToKeep().clear(); + return; + } + + // Handle saving player data snapshots on death + if (!plugin.getSettings().doSaveOnDeath()) { + return; + } + + // Paper - support saving the player's items to keep if enabled + final int maxInventorySize = BukkitData.Items.Inventory.INVENTORY_SLOT_COUNT; + final List itemsToSave = switch (plugin.getSettings().getDeathItemsMode()) { + case DROPS -> event.getDrops(); + case ITEMS_TO_KEEP -> event.getItemsToKeep(); + }; + if (itemsToSave.size() > maxInventorySize) { + itemsToSave.subList(maxInventorySize, itemsToSave.size()).clear(); + } + super.saveOnPlayerDeath(user, BukkitData.Items.ItemArray.adapt(itemsToSave)); + } + +} diff --git a/paper/src/main/resources/paper-libraries.yml b/paper/src/main/resources/paper-libraries.yml new file mode 100644 index 00000000..808e6b30 --- /dev/null +++ b/paper/src/main/resources/paper-libraries.yml @@ -0,0 +1,6 @@ +# Dependencies for HuskSync on Paper +libraries: + - 'redis.clients:jedis:${jedis_version}' + - 'com.mysql:mysql-connector-j:${mysql_driver_version}' + - 'org.mariadb.jdbc:mariadb-java-client:${mariadb_driver_version}' + - 'org.xerial.snappy:snappy-java:${snappy_version}' \ No newline at end of file diff --git a/paper/src/main/resources/paper-plugin.yml b/paper/src/main/resources/paper-plugin.yml new file mode 100644 index 00000000..50383884 --- /dev/null +++ b/paper/src/main/resources/paper-plugin.yml @@ -0,0 +1,18 @@ +name: 'HuskSync' +description: '${description}' +author: 'William278' +website: 'https://william278.net/' +main: 'net.william278.husksync.PaperHuskSync' +loader: 'net.william278.husksync.PaperHuskSyncLoader' +version: '${version}' +api-version: '1.19' +dependencies: + server: + MysqlPlayerDataBridge: + required: false + load: BEFORE + join-classpath: true + Plan: + required: false + load: BEFORE + join-classpath: true \ No newline at end of file diff --git a/plugin/build.gradle b/plugin/build.gradle index ecaed565..e5b85eb6 100644 --- a/plugin/build.gradle +++ b/plugin/build.gradle @@ -1,3 +1,4 @@ dependencies { implementation project(path: ':bukkit', configuration: 'shadow') + runtimeOnly project(path: ':paper') } \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index c0e4840c..451f8f1d 100644 --- a/settings.gradle +++ b/settings.gradle @@ -5,7 +5,9 @@ pluginManagement { } rootProject.name = 'HuskSync' - -include 'common' -include 'bukkit' -include 'plugin' \ No newline at end of file +include( + 'common', + 'bukkit', + 'paper', + 'plugin' +) \ No newline at end of file