mirror of
https://github.com/WiIIiam278/HuskSync.git
synced 2026-01-04 15:31:37 +00:00
v2.2.6: Crafting inventory safety, Maria v11 support (#153)
* Clear player inventory crafting slots on sync * Bundle Maria driver for v11 support
This commit is contained in:
@@ -14,8 +14,10 @@ defaultTasks 'licenseFormat', 'build'
|
||||
ext {
|
||||
set 'version', version.toString()
|
||||
set 'description', description.toString()
|
||||
|
||||
set 'jedis_version', jedis_version.toString()
|
||||
set 'mysql_driver_version', mysql_driver_version.toString()
|
||||
set 'mariadb_driver_version', mariadb_driver_version.toString()
|
||||
set 'snappy_version', snappy_version.toString()
|
||||
set 'commons_text_version', commons_text_version.toString()
|
||||
}
|
||||
|
||||
@@ -130,8 +130,8 @@ public class BukkitHuskSync extends JavaPlugin implements HuskSync {
|
||||
|
||||
// Prepare database connection
|
||||
this.database = new MySqlDatabase(this);
|
||||
log(Level.INFO, "Attempting to establish connection to the " + settings.getSqlType().getDisplayName() + " database...");
|
||||
initialized.set(this.database.initialize());
|
||||
log(Level.INFO, "Attempting to establish connection to the " + settings.getDatabaseType().getDisplayName() + " database...");
|
||||
this.database.initialize();
|
||||
if (initialized.get()) {
|
||||
log(Level.INFO, "Successfully established a connection to the database");
|
||||
} else {
|
||||
@@ -195,7 +195,7 @@ public class BukkitHuskSync extends JavaPlugin implements HuskSync {
|
||||
"An update is available for HuskSync, v" + newVersion
|
||||
+ " (Currently running v" + getPluginVersion() + ")")));
|
||||
}
|
||||
} catch (HuskSyncInitializationException exception) {
|
||||
} catch (IllegalStateException exception) {
|
||||
log(Level.SEVERE, """
|
||||
***************************************************
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ import org.bukkit.event.entity.PlayerDeathEvent;
|
||||
import org.bukkit.event.entity.ProjectileLaunchEvent;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.event.inventory.InventoryOpenEvent;
|
||||
import org.bukkit.event.inventory.PrepareItemCraftEvent;
|
||||
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
|
||||
import org.bukkit.event.player.PlayerDropItemEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEntityEvent;
|
||||
@@ -172,6 +173,10 @@ public class BukkitEventListener extends EventListener implements BukkitJoinEven
|
||||
event.setCancelled(cancelPlayerEvent(event.getWhoClicked().getUniqueId()));
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onCraftItem(@NotNull PrepareItemCraftEvent event) {
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onPlayerTakeDamage(@NotNull EntityDamageEvent event) {
|
||||
if (event.getEntity() instanceof Player player) {
|
||||
|
||||
@@ -36,6 +36,7 @@ import org.bukkit.advancement.AdvancementProgress;
|
||||
import org.bukkit.attribute.Attribute;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.inventory.InventoryType;
|
||||
import org.bukkit.event.player.PlayerTeleportEvent;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
@@ -178,6 +179,7 @@ public class BukkitPlayer extends OnlineUser {
|
||||
return BukkitSerializer.deserializeInventory(itemData.serializedItems).thenApplyAsync(contents -> {
|
||||
final CompletableFuture<Void> inventorySetFuture = new CompletableFuture<>();
|
||||
Bukkit.getScheduler().runTask(plugin, () -> {
|
||||
this.clearInventoryCraftingSlots();
|
||||
player.setItemOnCursor(null);
|
||||
player.getInventory().setContents(contents.getContents());
|
||||
player.updateInventory();
|
||||
@@ -187,6 +189,16 @@ public class BukkitPlayer extends OnlineUser {
|
||||
});
|
||||
}
|
||||
|
||||
// Clears any items the player may have in the crafting slots of their inventory
|
||||
private void clearInventoryCraftingSlots() {
|
||||
final Inventory inventory = player.getOpenInventory().getTopInventory();
|
||||
if (inventory.getType() == InventoryType.CRAFTING) {
|
||||
for (int slot = 0; slot < 5; slot++) {
|
||||
inventory.setItem(slot, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<ItemData> getEnderChest() {
|
||||
final Inventory enderChest = player.getEnderChest();
|
||||
|
||||
@@ -11,6 +11,7 @@ softdepend:
|
||||
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}'
|
||||
- 'org.apache.commons:commons-text:${commons_text_version}'
|
||||
|
||||
|
||||
@@ -22,9 +22,9 @@ package net.william278.husksync;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Indicates an exception occurred while initialising the HuskSync plugin
|
||||
* Indicates an exception occurred while initializing the HuskSync plugin
|
||||
*/
|
||||
public class HuskSyncInitializationException extends RuntimeException {
|
||||
public class HuskSyncInitializationException extends IllegalStateException {
|
||||
public HuskSyncInitializationException(@NotNull String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
@@ -174,7 +174,7 @@ public class Settings {
|
||||
|
||||
|
||||
@NotNull
|
||||
public Database.Type getSqlType() {
|
||||
public Database.Type getDatabaseType() {
|
||||
return databaseType;
|
||||
}
|
||||
|
||||
|
||||
@@ -75,10 +75,8 @@ public abstract class Database {
|
||||
|
||||
/**
|
||||
* Initialize the database and ensure tables are present; create tables if they do not exist.
|
||||
*
|
||||
* @return A future returning boolean - if the connection could be established.
|
||||
*/
|
||||
public abstract boolean initialize();
|
||||
public abstract void initialize();
|
||||
|
||||
/**
|
||||
* Ensure a {@link User} has an entry in the database and that their username is up-to-date
|
||||
|
||||
@@ -40,57 +40,13 @@ import java.util.logging.Level;
|
||||
|
||||
public class MySqlDatabase extends Database {
|
||||
|
||||
/**
|
||||
* MySQL protocol
|
||||
*/
|
||||
private final Database.Type type;
|
||||
|
||||
/**
|
||||
* MySQL server hostname
|
||||
*/
|
||||
private final String mySqlHost;
|
||||
|
||||
/**
|
||||
* MySQL server port
|
||||
*/
|
||||
private final int mySqlPort;
|
||||
|
||||
/**
|
||||
* Database to use on the MySQL server
|
||||
*/
|
||||
private final String mySqlDatabaseName;
|
||||
private final String mySqlUsername;
|
||||
private final String mySqlPassword;
|
||||
private final String mySqlConnectionParameters;
|
||||
|
||||
private final int hikariMaximumPoolSize;
|
||||
private final int hikariMinimumIdle;
|
||||
private final long hikariMaximumLifetime;
|
||||
private final long hikariKeepAliveTime;
|
||||
private final long hikariConnectionTimeOut;
|
||||
|
||||
private static final String DATA_POOL_NAME = "HuskSyncHikariPool";
|
||||
|
||||
/**
|
||||
* The Hikari data source - a pool of database connections that can be fetched on-demand
|
||||
*/
|
||||
private HikariDataSource connectionPool;
|
||||
private final String protocol;
|
||||
private HikariDataSource dataSource;
|
||||
|
||||
public MySqlDatabase(@NotNull HuskSync plugin) {
|
||||
super(plugin);
|
||||
final Settings settings = plugin.getSettings();
|
||||
this.type = settings.getSqlType();
|
||||
this.mySqlHost = settings.getMySqlHost();
|
||||
this.mySqlPort = settings.getMySqlPort();
|
||||
this.mySqlDatabaseName = settings.getMySqlDatabase();
|
||||
this.mySqlUsername = settings.getMySqlUsername();
|
||||
this.mySqlPassword = settings.getMySqlPassword();
|
||||
this.mySqlConnectionParameters = settings.getMySqlConnectionParameters();
|
||||
this.hikariMaximumPoolSize = settings.getMySqlConnectionPoolSize();
|
||||
this.hikariMinimumIdle = settings.getMySqlConnectionPoolIdle();
|
||||
this.hikariMaximumLifetime = settings.getMySqlConnectionPoolLifetime();
|
||||
this.hikariKeepAliveTime = settings.getMySqlConnectionPoolKeepAlive();
|
||||
this.hikariConnectionTimeOut = settings.getMySqlConnectionPoolTimeout();
|
||||
this.protocol = plugin.getSettings().getDatabaseType().getProtocol();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -100,46 +56,68 @@ public class MySqlDatabase extends Database {
|
||||
* @throws SQLException if the connection fails for some reason
|
||||
*/
|
||||
private Connection getConnection() throws SQLException {
|
||||
return connectionPool.getConnection();
|
||||
return dataSource.getConnection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean initialize() {
|
||||
try {
|
||||
// Create jdbc driver connection url
|
||||
final String jdbcUrl = "jdbc:" + type.getProtocol() + "://" + mySqlHost + ":" + mySqlPort + "/" + mySqlDatabaseName + mySqlConnectionParameters;
|
||||
connectionPool = new HikariDataSource();
|
||||
connectionPool.setJdbcUrl(jdbcUrl);
|
||||
public void initialize() throws IllegalStateException {
|
||||
// Initialize the Hikari pooled connection
|
||||
dataSource = new HikariDataSource();
|
||||
dataSource.setJdbcUrl(String.format("jdbc:%s://%s:%s/%s%s",
|
||||
protocol,
|
||||
plugin.getSettings().getMySqlHost(),
|
||||
plugin.getSettings().getMySqlPort(),
|
||||
plugin.getSettings().getMySqlDatabase(),
|
||||
plugin.getSettings().getMySqlConnectionParameters()
|
||||
));
|
||||
|
||||
// Authenticate
|
||||
connectionPool.setUsername(mySqlUsername);
|
||||
connectionPool.setPassword(mySqlPassword);
|
||||
// Authenticate with the database
|
||||
dataSource.setUsername(plugin.getSettings().getMySqlUsername());
|
||||
dataSource.setPassword(plugin.getSettings().getMySqlPassword());
|
||||
|
||||
// Set various additional parameters
|
||||
connectionPool.setMaximumPoolSize(hikariMaximumPoolSize);
|
||||
connectionPool.setMinimumIdle(hikariMinimumIdle);
|
||||
connectionPool.setMaxLifetime(hikariMaximumLifetime);
|
||||
connectionPool.setKeepaliveTime(hikariKeepAliveTime);
|
||||
connectionPool.setConnectionTimeout(hikariConnectionTimeOut);
|
||||
connectionPool.setPoolName(DATA_POOL_NAME);
|
||||
// Set connection pool options
|
||||
dataSource.setMaximumPoolSize(plugin.getSettings().getMySqlConnectionPoolSize());
|
||||
dataSource.setMinimumIdle(plugin.getSettings().getMySqlConnectionPoolIdle());
|
||||
dataSource.setMaxLifetime(plugin.getSettings().getMySqlConnectionPoolLifetime());
|
||||
dataSource.setKeepaliveTime(plugin.getSettings().getMySqlConnectionPoolKeepAlive());
|
||||
dataSource.setConnectionTimeout(plugin.getSettings().getMySqlConnectionPoolTimeout());
|
||||
dataSource.setPoolName(DATA_POOL_NAME);
|
||||
|
||||
// Set additional connection pool properties
|
||||
final Properties properties = new Properties();
|
||||
properties.putAll(
|
||||
Map.of("cachePrepStmts", "true",
|
||||
"prepStmtCacheSize", "250",
|
||||
"prepStmtCacheSqlLimit", "2048",
|
||||
"useServerPrepStmts", "true",
|
||||
"useLocalSessionState", "true",
|
||||
"useLocalTransactionState", "true"
|
||||
));
|
||||
properties.putAll(
|
||||
Map.of(
|
||||
"rewriteBatchedStatements", "true",
|
||||
"cacheResultSetMetadata", "true",
|
||||
"cacheServerConfiguration", "true",
|
||||
"elideSetAutoCommits", "true",
|
||||
"maintainTimeStats", "false")
|
||||
);
|
||||
dataSource.setDataSourceProperties(properties);
|
||||
|
||||
// Prepare database schema; make tables if they don't exist
|
||||
try (Connection connection = connectionPool.getConnection()) {
|
||||
// Load database schema CREATE statements from schema file
|
||||
final String[] databaseSchema = getSchemaStatements("database/mysql_schema.sql");
|
||||
try (Connection connection = dataSource.getConnection()) {
|
||||
final String[] databaseSchema = getSchemaStatements(String.format("database/%s_schema.sql", protocol));
|
||||
try (Statement statement = connection.createStatement()) {
|
||||
for (String tableCreationStatement : databaseSchema) {
|
||||
statement.execute(tableCreationStatement);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
throw new IllegalStateException("Failed to create database tables. Please ensure you are running MySQL v8.0+ " +
|
||||
"and that your connecting user account has privileges to create tables.", e);
|
||||
}
|
||||
return true;
|
||||
} catch (SQLException | IOException e) {
|
||||
plugin.log(Level.SEVERE, "Failed to perform database setup: " + e.getMessage());
|
||||
throw new IllegalStateException("Failed to establish a connection to the MySQL database. " +
|
||||
"Please check the supplied database credentials in the config file", e);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
plugin.log(Level.SEVERE, "An unhandled exception occurred during database setup!", e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -445,9 +423,9 @@ public class MySqlDatabase extends Database {
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (connectionPool != null) {
|
||||
if (!connectionPool.isClosed()) {
|
||||
connectionPool.close();
|
||||
if (dataSource != null) {
|
||||
if (!dataSource.isClosed()) {
|
||||
dataSource.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,11 +3,12 @@ org.gradle.jvmargs='-Dfile.encoding=UTF-8'
|
||||
org.gradle.daemon=true
|
||||
javaVersion=16
|
||||
|
||||
plugin_version=2.2.5
|
||||
plugin_version=2.2.6
|
||||
plugin_archive=husksync
|
||||
plugin_description=A modern, cross-server player data synchronization system
|
||||
|
||||
jedis_version=4.3.2
|
||||
mysql_driver_version=8.0.32
|
||||
mysql_driver_version=8.1.0
|
||||
mariadb_driver_version=3.1.4
|
||||
snappy_version=1.1.9.1
|
||||
commons_text_version=1.10.0
|
||||
Reference in New Issue
Block a user