From 3fbb4827ca8511043871949b33dd182a5042e10a Mon Sep 17 00:00:00 2001 From: nossr50 Date: Wed, 3 Jan 2024 00:19:57 -0800 Subject: [PATCH] Update SQL schema when missing columns --- .../nossr50/database/SQLDatabaseManager.java | 97 +++++++++++++++---- .../skills/crossbows/CrossbowsManager.java | 35 ++++++- .../gmail/nossr50/util/MetadataConstants.java | 1 + .../com/gmail/nossr50/util/Permissions.java | 3 + 4 files changed, 110 insertions(+), 26 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java index 69dffb644..deae24ee9 100644 --- a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java @@ -567,8 +567,8 @@ public final class SQLDatabaseManager implements DatabaseManager { try { statement = connection.prepareStatement( "UPDATE `" + tablePrefix + "users` " - + "SET \"USER\" = ? " - + "WHERE \"USER\" = ?"); + + "SET `USER` = ? " + + "WHERE `USER` = ?"); statement.setString(1, "_INVALID_OLD_USERNAME_"); statement.setString(2, playerName); statement.executeUpdate(); @@ -650,9 +650,9 @@ public final class SQLDatabaseManager implements DatabaseManager { statement = connection.prepareStatement( "SELECT " + "S.TAMING, S.MINING, S.REPAIR, S.WOODCUTTING, S.UNARMED, S.HERBALISM, S.EXCAVATION, S.ARCHERY, S.SWORDS, S.AXES, S.ACROBATICS, S.FISHING, S.ALCHEMY, S.CROSSBOWS, S.TRIDENTS, " + - "E.TAMING, E.MINING, E.REPAIR, E.WOODCUTTING, E.UNARMED, E.HERBALISM, E.EXCAVATION, E.ARCHERY, E.SWORDS, E.AXES, E.ACROBATICS, E.FISHING, E.ALCHEMY, S.CROSSBOWS, S.TRIDENTS, " + + "E.TAMING, E.MINING, E.REPAIR, E.WOODCUTTING, E.UNARMED, E.HERBALISM, E.EXCAVATION, E.ARCHERY, E.SWORDS, E.AXES, E.ACROBATICS, E.FISHING, E.ALCHEMY, E.CROSSBOWS, E.TRIDENTS, " + "C.TAMING, C.MINING, C.REPAIR, C.WOODCUTTING, C.UNARMED, C.HERBALISM, C.EXCAVATION, C.ARCHERY, C.SWORDS, C.AXES, C.ACROBATICS, C.BLAST_MINING, C.CHIMAERA_WING, C.CROSSBOWS, C.TRIDENTS, " + - "H.MOBHEALTHBAR, H.SCOREBOARDTIPS, U.UUID, U.\"USER\" " + + "H.MOBHEALTHBAR, H.SCOREBOARDTIPS, U.UUID, U.`USER` " + "FROM " + tablePrefix + "USERS U " + "JOIN " + tablePrefix + "SKILLS S ON U.ID = S.USER_ID " + "JOIN " + tablePrefix + "EXPERIENCE E ON U.ID = E.USER_ID " + @@ -664,6 +664,7 @@ public final class SQLDatabaseManager implements DatabaseManager { resultSet = statement.executeQuery(); + if (resultSet.next()) { try { PlayerProfile profile = loadFromResult(playerName, resultSet); @@ -677,15 +678,15 @@ public final class SQLDatabaseManager implements DatabaseManager { && uuid != null) { statement = connection.prepareStatement( "UPDATE `" + tablePrefix + "users` " - + "SET \"USER\" = ? " - + "WHERE \"USER\" = ?"); + + "SET `USER` = ? " + + "WHERE `USER` = ?"); statement.setString(1, "_INVALID_OLD_USERNAME_"); statement.setString(2, name); statement.executeUpdate(); statement.close(); statement = connection.prepareStatement( "UPDATE `" + tablePrefix + "users` " - + "SET \"USER\" = ?, uuid = ? " + + "SET `USER` = ?, uuid = ? " + "WHERE id = ?"); statement.setString(1, playerName); statement.setString(2, uuid.toString()); @@ -859,7 +860,6 @@ public final class SQLDatabaseManager implements DatabaseManager { * Checks that the database structure is present and correct */ private void checkStructure() { - PreparedStatement statement = null; Statement createStatement = null; ResultSet resultSet = null; @@ -1019,6 +1019,68 @@ public final class SQLDatabaseManager implements DatabaseManager { tryClose(connection); } + updateStructure("SKILLS", "CROSSBOWS", String.valueOf(32)); + updateStructure("SKILLS", "TRIDENTS", String.valueOf(32)); + + updateStructure("EXPERIENCE", "CROSSBOWS", String.valueOf(10)); + updateStructure("EXPERIENCE", "TRIDENTS", String.valueOf(10)); + + updateStructure("COOLDOWNS", "CROSSBOWS", String.valueOf(10)); + updateStructure("COOLDOWNS", "TRIDENTS", String.valueOf(10)); + } + + private void updateStructure(String tableName, String columnName, String columnSize) { + boolean columnExists = false; + DatabaseMetaData metaData = null; + + try(Connection connection = getConnection(PoolIdentifier.MISC)) { + metaData = connection.getMetaData(); + ResultSet rs = null; + + try { + // Replace "YOUR_SCHEMA" with your database schema name if necessary, or use null to not filter by schema. + // Replace "YOUR_TABLE" with the actual table name, and "YOUR_COLUMN" with the column you're checking for. + rs = metaData.getColumns(null, null, tablePrefix + tableName, columnName); + + if (rs.next()) { + // If the result set is not empty, the column exists + columnExists = true; + } + } catch (SQLException e) { + e.printStackTrace(); // Handle the exception appropriately + } finally { + if (rs != null) { + try { + rs.close(); + } catch (SQLException e) { + e.printStackTrace(); // Handle the exception appropriately + } + } + } + + if (!columnExists) { + // Alter the table to add the column + Statement createStatement = null; + try { + createStatement = connection.createStatement(); + String startingLevel = "'" + mcMMO.p.getAdvancedConfig().getStartingLevel() + "'"; + createStatement.executeUpdate("ALTER TABLE `" + tablePrefix + tableName + "` " + + "ADD COLUMN `" + columnName + "` int(" + columnSize + ") unsigned NOT NULL DEFAULT " + startingLevel); + } catch (SQLException e) { + e.printStackTrace(); // Handle the exception appropriately + } finally { + if (createStatement != null) { + try { + createStatement.close(); + } catch (SQLException e) { + e.printStackTrace(); // Handle the exception appropriately + } + } + } + } + } catch (SQLException e) { + throw new RuntimeException(e); + } } private void setStatementQuery(PreparedStatement statement, String tableName) throws SQLException { @@ -1032,19 +1094,12 @@ public final class SQLDatabaseManager implements DatabaseManager { } } - protected Connection getConnection(PoolIdentifier identifier) throws SQLException { - Connection connection = null; - switch (identifier) { - case LOAD: - connection = loadPool.getConnection(); - break; - case MISC: - connection = miscPool.getConnection(); - break; - case SAVE: - connection = savePool.getConnection(); - break; - } + Connection getConnection(PoolIdentifier identifier) throws SQLException { + Connection connection = switch (identifier) { + case LOAD -> loadPool.getConnection(); + case MISC -> miscPool.getConnection(); + case SAVE -> savePool.getConnection(); + }; if (connection == null) { throw new RuntimeException("getConnection() for " + identifier.name().toLowerCase(Locale.ENGLISH) + " pool timed out. Increase max connections settings."); } diff --git a/src/main/java/com/gmail/nossr50/skills/crossbows/CrossbowsManager.java b/src/main/java/com/gmail/nossr50/skills/crossbows/CrossbowsManager.java index 8cb3337eb..17918f4c3 100644 --- a/src/main/java/com/gmail/nossr50/skills/crossbows/CrossbowsManager.java +++ b/src/main/java/com/gmail/nossr50/skills/crossbows/CrossbowsManager.java @@ -2,8 +2,12 @@ package com.gmail.nossr50.skills.crossbows; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; +import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.skills.SkillManager; import com.gmail.nossr50.util.MetadataConstants; +import com.gmail.nossr50.util.Permissions; +import com.gmail.nossr50.util.random.ProbabilityUtil; +import com.gmail.nossr50.util.skills.RankUtils; import org.bukkit.Location; import org.bukkit.entity.Arrow; import org.bukkit.metadata.FixedMetadataValue; @@ -12,19 +16,34 @@ import org.bukkit.projectiles.ProjectileSource; import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; +import static com.gmail.nossr50.util.random.ProbabilityUtil.isStaticSkillRNGSuccessful; + public class CrossbowsManager extends SkillManager { public CrossbowsManager(McMMOPlayer mmoPlayer) { super(mmoPlayer, PrimarySkillType.CROSSBOWS); } public void handleRicochet(@NotNull Plugin pluginRef, @NotNull Arrow originalArrow, @NotNull Vector hitBlockNormal) { - // Reflect arrow in new direction - // cleanup metadata on original arrow + // Check player permission + if (!Permissions.trickShot(mmoPlayer.getPlayer())) { + return; + } + // TODO: Add an event for this for plugins to hook into spawnReflectedArrow(pluginRef, originalArrow, originalArrow.getLocation(), hitBlockNormal); } - public void spawnReflectedArrow(@NotNull Plugin pluginRef, @NotNull Arrow originalArrow, @NotNull Location origin, @NotNull Vector normal) { + public void spawnReflectedArrow(@NotNull Plugin pluginRef, @NotNull Arrow originalArrow, + @NotNull Location origin, @NotNull Vector normal) { + int bounceCount = 0; + + if (originalArrow.hasMetadata(MetadataConstants.METADATA_KEY_BOUNCE_COUNT)) { + bounceCount = originalArrow.getMetadata(MetadataConstants.METADATA_KEY_BOUNCE_COUNT).get(0).asInt(); + if (bounceCount >= getTrickShotMaxBounceCount()) { + return; + } + } + final ProjectileSource originalArrowShooter = originalArrow.getShooter(); final Vector arrowInBlockVector = originalArrow.getVelocity(); final Vector reflectedDirection = arrowInBlockVector.subtract(normal.multiply(2 * arrowInBlockVector.dot(normal))); @@ -40,12 +59,18 @@ public class CrossbowsManager extends SkillManager { Arrow arrow = originalArrow.getWorld().spawnArrow(origin, reflectedDirection, 1, 1); arrow.setShooter(originalArrowShooter); + arrow.setMetadata(MetadataConstants.METADATA_KEY_BOUNCE_COUNT, + new FixedMetadataValue(pluginRef, bounceCount + 1)); arrow.setMetadata(MetadataConstants.METADATA_KEY_SPAWNED_ARROW, new FixedMetadataValue(pluginRef, originalArrowShooter)); - - // TODO: This metadata needs to get cleaned up at some point arrow.setMetadata(MetadataConstants.METADATA_KEY_BOW_TYPE, new FixedMetadataValue(pluginRef, originalArrow.getMetadata( MetadataConstants.METADATA_KEY_BOW_TYPE).get(0))); + + originalArrow.remove(); + } + + public int getTrickShotMaxBounceCount() { + return RankUtils.getRank(mmoPlayer, SubSkillType.CROSSBOWS_TRICK_SHOT); } } diff --git a/src/main/java/com/gmail/nossr50/util/MetadataConstants.java b/src/main/java/com/gmail/nossr50/util/MetadataConstants.java index 321dcf2a1..48aaa8955 100644 --- a/src/main/java/com/gmail/nossr50/util/MetadataConstants.java +++ b/src/main/java/com/gmail/nossr50/util/MetadataConstants.java @@ -15,6 +15,7 @@ public class MetadataConstants { */ public static final @NotNull String METADATA_KEY_REPLANT = "mcMMO: Recently Replanted"; public static final @NotNull String METADATA_KEY_SPAWNED_ARROW = "mcMMO: Spawned Arrow"; + public static final @NotNull String METADATA_KEY_BOUNCE_COUNT = "mcMMO: Arrow Bounce Count"; public static final @NotNull String METADATA_KEY_BOW_TYPE = "mcMMO: Bow Type"; public static final @NotNull String METADATA_KEY_EXPLOSION_FROM_RUPTURE = "mcMMO: Rupture Explosion"; public static final @NotNull String METADATA_KEY_FISH_HOOK_REF = "mcMMO: Fish Hook Tracker"; diff --git a/src/main/java/com/gmail/nossr50/util/Permissions.java b/src/main/java/com/gmail/nossr50/util/Permissions.java index e184ef8b9..c966711f3 100644 --- a/src/main/java/com/gmail/nossr50/util/Permissions.java +++ b/src/main/java/com/gmail/nossr50/util/Permissions.java @@ -228,6 +228,9 @@ public final class Permissions { public static boolean treeFeller(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.woodcutting.treefeller"); } /* CROSSBOWS */ public static boolean superShotgun(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.crossbows.supershotgun"); } + public static boolean trickShot(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.crossbows.trickshot"); } + + /* TRIDENTS */ public static boolean tridentsSuper(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.tridents.superability"); } public static boolean tridentsLimitBreak(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.tridents.superability"); }