aboutsummaryrefslogtreecommitdiffstats
path: root/bukkit/src/main/java
diff options
context:
space:
mode:
authorLMBishop <13875753+LMBishop@users.noreply.github.com>2022-05-01 15:52:52 +0100
committerLMBishop <13875753+LMBishop@users.noreply.github.com>2022-05-01 15:52:52 +0100
commitca46689e34da35a8d5b4b8fe8627ef745537073a (patch)
treea449b3e71a8f60c6785e16340820917ae6e3e41c /bukkit/src/main/java
parent89b5cba356f8395ad07df5913d589c9f84f3fe39 (diff)
Add started field to progress files & database migration
Diffstat (limited to 'bukkit/src/main/java')
-rw-r--r--bukkit/src/main/java/com/leonardobishop/quests/bukkit/BukkitQuestsPlugin.java1
-rw-r--r--bukkit/src/main/java/com/leonardobishop/quests/bukkit/questcontroller/NormalQuestController.java4
-rw-r--r--bukkit/src/main/java/com/leonardobishop/quests/bukkit/storage/MySqlStorageProvider.java122
-rw-r--r--bukkit/src/main/java/com/leonardobishop/quests/bukkit/storage/YamlStorageProvider.java4
4 files changed, 118 insertions, 13 deletions
diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/BukkitQuestsPlugin.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/BukkitQuestsPlugin.java
index c5b13504..39dd4159 100644
--- a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/BukkitQuestsPlugin.java
+++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/BukkitQuestsPlugin.java
@@ -179,6 +179,7 @@ public class BukkitQuestsPlugin extends JavaPlugin implements Quests {
}
try {
+ questsLogger.info("Initialising storage provider '" + storageProvider.getName());
storageProvider.init();
} catch (Exception e) {
questsLogger.severe("An error occurred initialising the storage provider.");
diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/questcontroller/NormalQuestController.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/questcontroller/NormalQuestController.java
index 4b8d5a44..3a8dbb5c 100644
--- a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/questcontroller/NormalQuestController.java
+++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/questcontroller/NormalQuestController.java
@@ -92,6 +92,7 @@ public class NormalQuestController implements QuestController {
if (code == QuestStartResult.QUEST_SUCCESS) {
QuestProgress questProgress = qPlayer.getQuestProgressFile().getQuestProgress(quest);
questProgress.setStarted(true);
+ questProgress.setStartedDate(System.currentTimeMillis());
for (TaskProgress taskProgress : questProgress.getTaskProgress()) {
taskProgress.setCompleted(false);
taskProgress.setProgress(null);
@@ -198,6 +199,7 @@ public class NormalQuestController implements QuestController {
public boolean completeQuestForPlayer(QPlayer qPlayer, Quest quest) {
QuestProgress questProgress = qPlayer.getQuestProgressFile().getQuestProgress(quest);
questProgress.setStarted(false);
+ questProgress.setStartedDate(System.currentTimeMillis());
for (TaskProgress taskProgress : questProgress.getTaskProgress()) {
taskProgress.setCompleted(false);
taskProgress.setProgress(null);
@@ -271,7 +273,9 @@ public class NormalQuestController implements QuestController {
return false;
}
questProgress.setStarted(false);
+ questProgress.setStartedDate(System.currentTimeMillis());
for (TaskProgress taskProgress : questProgress.getTaskProgress()) {
+ taskProgress.setCompleted(false);
taskProgress.setProgress(null);
}
if (player != null) {
diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/storage/MySqlStorageProvider.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/storage/MySqlStorageProvider.java
index 5400afb0..5d57dc2e 100644
--- a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/storage/MySqlStorageProvider.java
+++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/storage/MySqlStorageProvider.java
@@ -24,6 +24,7 @@ public class MySqlStorageProvider implements StorageProvider {
" `uuid` VARCHAR(36) NOT NULL," +
" `quest_id` VARCHAR(50) NOT NULL," +
" `started` BOOL NOT NULL," +
+ " `started_date` BIGINT NOT NULL," +
" `completed` BOOL NOT NULL," +
" `completed_before` BOOL NOT NULL," +
" `completion_date` BIGINT NOT NULL," +
@@ -37,6 +38,11 @@ public class MySqlStorageProvider implements StorageProvider {
" `progress` VARCHAR(64) NULL," +
" `data_type` VARCHAR(10) NULL," +
" PRIMARY KEY (`uuid`, `quest_id`, `task_id`));";
+ private static final String CREATE_TABLE_DATABASE_INFORMATION =
+ "CREATE TABLE IF NOT EXISTS `{prefix}database_information` (" +
+ " `key` VARCHAR(255) NOT NULL," +
+ " `value` VARCHAR(255) NOT NULL," +
+ " PRIMARY KEY (`key`));";
private static final String SELECT_PLAYER_QUEST_PROGRESS =
"SELECT quest_id, started, completed, completed_before, completion_date FROM `{prefix}quest_progress` WHERE uuid=?;";
private static final String SELECT_PLAYER_TASK_PROGRESS =
@@ -48,7 +54,7 @@ public class MySqlStorageProvider implements StorageProvider {
private static final String SELECT_KNOWN_PLAYER_TASK_PROGRESS =
"SELECT quest_id, task_id FROM `{prefix}task_progress` WHERE uuid=?;";
private static final String WRITE_PLAYER_QUEST_PROGRESS =
- "INSERT INTO `{prefix}quest_progress` (uuid, quest_id, started, completed, completed_before, completion_date) VALUES (?,?,?,?,?,?) ON DUPLICATE KEY UPDATE started=?, completed=?, completed_before=?, completion_date=?";
+ "INSERT INTO `{prefix}quest_progress` (uuid, quest_id, started, started_date, completed, completed_before, completion_date) VALUES (?,?,?,?,?,?) ON DUPLICATE KEY UPDATE started=?, started_date=?, completed=?, completed_before=?, completion_date=?";
private static final String WRITE_PLAYER_TASK_PROGRESS =
"INSERT INTO `{prefix}task_progress` (uuid, quest_id, task_id, completed, progress, data_type) VALUES (?,?,?,?,?,?) ON DUPLICATE KEY UPDATE completed=?, progress=?, data_type=?";
@@ -115,9 +121,17 @@ public class MySqlStorageProvider implements StorageProvider {
plugin.getQuestsLogger().debug("Creating default tables");
s.addBatch(this.statementProcessor.apply(CREATE_TABLE_QUEST_PROGRESS));
s.addBatch(this.statementProcessor.apply(CREATE_TABLE_TASK_PROGRESS));
+ s.addBatch(this.statementProcessor.apply(CREATE_TABLE_DATABASE_INFORMATION));
s.executeBatch();
}
+ DatabaseMigrator migrator = new DatabaseMigrator(connection);
+
+ int currentVersion = migrator.getCurrentSchemaVersion();
+ if (currentVersion < DatabaseMigrator.CURRENT_SCHEMA_VERSION) {
+ plugin.getQuestsLogger().info("Automatically upgrading database schema from version " + currentVersion + " to " + DatabaseMigrator.CURRENT_SCHEMA_VERSION);
+ migrator.upgrade(currentVersion);
+ }
} catch (SQLException e) {
throw new RuntimeException(e);
}
@@ -149,12 +163,13 @@ public class MySqlStorageProvider implements StorageProvider {
while (rs.next()) {
String questId = rs.getString(1);
boolean started = rs.getBoolean(2);
- boolean completed = rs.getBoolean(3);
- boolean completedBefore = rs.getBoolean(4);
- long completionDate = rs.getLong(5);
+ long startedDate = rs.getLong(3);
+ boolean completed = rs.getBoolean(4);
+ boolean completedBefore = rs.getBoolean(5);
+ long completionDate = rs.getLong(6);
if (validateQuests && !presentQuests.containsKey(questId)) continue;
- QuestProgress questProgress = new QuestProgress(plugin, questId, completed, completedBefore, completionDate, uuid, started);
+ QuestProgress questProgress = new QuestProgress(plugin, questId, completed, completedBefore, completionDate, uuid, started, startedDate);
questProgressMap.put(questId, questProgress);
}
}
@@ -238,13 +253,15 @@ public class MySqlStorageProvider implements StorageProvider {
writeQuestProgress.setString(1, uuid.toString());
writeQuestProgress.setString(2, questProgress.getQuestId());
writeQuestProgress.setBoolean(3, questProgress.isStarted());
- writeQuestProgress.setBoolean(4, questProgress.isCompleted());
- writeQuestProgress.setBoolean(5, questProgress.isCompletedBefore());
- writeQuestProgress.setLong(6, questProgress.getCompletionDate());
- writeQuestProgress.setBoolean(7, questProgress.isStarted());
- writeQuestProgress.setBoolean(8, questProgress.isCompleted());
- writeQuestProgress.setBoolean(9, questProgress.isCompletedBefore());
- writeQuestProgress.setLong(10, questProgress.getCompletionDate());
+ writeQuestProgress.setLong(4, questProgress.getStartedDate());
+ writeQuestProgress.setBoolean(5, questProgress.isCompleted());
+ writeQuestProgress.setBoolean(6, questProgress.isCompletedBefore());
+ writeQuestProgress.setLong(7, questProgress.getCompletionDate());
+ writeQuestProgress.setBoolean(8, questProgress.isStarted());
+ writeQuestProgress.setLong(9, questProgress.getStartedDate());
+ writeQuestProgress.setBoolean(10, questProgress.isCompleted());
+ writeQuestProgress.setBoolean(11, questProgress.isCompletedBefore());
+ writeQuestProgress.setLong(12, questProgress.getCompletionDate());
writeQuestProgress.addBatch();
for (TaskProgress taskProgress : questProgress.getTaskProgress()) {
@@ -335,4 +352,85 @@ public class MySqlStorageProvider implements StorageProvider {
saveProgressFile(file.getPlayerUUID(), file);
}
}
+
+ private class DatabaseMigrator {
+ private static final String GET_STARTED_DATE_COLUMN =
+ "SHOW COLUMNS from `{prefix}quest_progress` LIKE 'started_date';";
+ private static final String SELECT_SCHEMA_VERSION =
+ "SELECT value FROM `{prefix}database_information` WHERE `key`='schema_version';";
+ private static final String UPDATE_DATABASE_INFORMATION =
+ "INSERT INTO `{prefix}database_information` (`key`, `value`) VALUES (?,?) ON DUPLICATE KEY UPDATE `value`=?;";
+ private static final int CURRENT_SCHEMA_VERSION = 2;
+
+ private final Map<Integer, String> migrationStatements = new HashMap<>();
+
+ private final Connection connection;
+
+ public DatabaseMigrator(Connection connection) {
+ this.connection = connection;
+
+ this.migrationStatements.put(1,
+ "ALTER TABLE `{prefix}quest_progress` ADD COLUMN `started_date` BIGINT NOT NULL DEFAULT 0 AFTER `started`;");
+ }
+
+ public int getInitialSchemaVersion() {
+ try (Statement statement = connection.createStatement()) {
+ plugin.getQuestsLogger().debug("Getting initial schema version for new database");
+ ResultSet rs = statement.executeQuery(statementProcessor.apply(GET_STARTED_DATE_COLUMN));
+ boolean hasStartedDateColumn = rs.next();
+
+ return hasStartedDateColumn ? CURRENT_SCHEMA_VERSION : 1;
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public int getCurrentSchemaVersion() {
+ try (Statement statement = connection.createStatement()) {
+ plugin.getQuestsLogger().debug("Getting current schema version");
+ ResultSet rs = statement.executeQuery(statementProcessor.apply(SELECT_SCHEMA_VERSION));
+ if (rs.next()) {
+ int version = Integer.parseInt(rs.getString(1));
+ plugin.getQuestsLogger().debug("Current schema version: " + version);
+ return version;
+ } else {
+ int initialVersion = getInitialSchemaVersion();
+ updateSchemaVersion(initialVersion);
+ return initialVersion;
+ }
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void upgrade(int initialSchemaVersion) {
+ plugin.getQuestsLogger().debug("Starting upgrade from version " + initialSchemaVersion + " to " + CURRENT_SCHEMA_VERSION);
+ for (int i = initialSchemaVersion; i < CURRENT_SCHEMA_VERSION; i++) {
+ String statement = statementProcessor.apply(migrationStatements.get(i));
+ plugin.getQuestsLogger().debug("Running migration statement: " + statement);
+ try (Statement stmt = connection.createStatement()) {
+ stmt.execute(statementProcessor.apply(statement));
+ } catch (SQLException e) {
+ plugin.getQuestsLogger().severe("Failed to run migration statement (" + i + " -> " + (i + 1) + "): " + statement);
+ plugin.getQuestsLogger().severe("Quests will attempt to save current migration progress to prevent database corruption, but may not be able to do so");
+ updateSchemaVersion(i);
+ throw new RuntimeException(e);
+ }
+ }
+ updateSchemaVersion(CURRENT_SCHEMA_VERSION);
+ }
+
+ public void updateSchemaVersion(int version) {
+ plugin.getQuestsLogger().debug("Updating schema version to " + version);
+ try (PreparedStatement stmt = connection.prepareStatement(statementProcessor.apply(UPDATE_DATABASE_INFORMATION))) {
+ stmt.setString(1, "schema_version");
+ stmt.setString(2, String.valueOf(version));
+ stmt.setString(3, String.valueOf(version));
+
+ stmt.execute();
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
}
diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/storage/YamlStorageProvider.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/storage/YamlStorageProvider.java
index e6848e06..c5aae904 100644
--- a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/storage/YamlStorageProvider.java
+++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/storage/YamlStorageProvider.java
@@ -68,13 +68,14 @@ public class YamlStorageProvider implements StorageProvider {
if (data.isConfigurationSection("quest-progress")) { //Same job as "isSet" + it checks if is CfgSection
for (String id : data.getConfigurationSection("quest-progress").getKeys(false)) {
boolean started = data.getBoolean("quest-progress." + id + ".started");
+ long startedDate = data.getLong("quest-progress." + id + ".started-date");
boolean completed = data.getBoolean("quest-progress." + id + ".completed");
boolean completedBefore = data.getBoolean("quest-progress." + id + ".completed-before");
long completionDate = data.getLong("quest-progress." + id + ".completion-date");
if (validateQuests && !presentQuests.containsKey(id)) continue;
- QuestProgress questProgress = new QuestProgress(plugin, id, completed, completedBefore, completionDate, uuid, started, true);
+ QuestProgress questProgress = new QuestProgress(plugin, id, completed, completedBefore, completionDate, uuid, started, startedDate, true);
if (data.isConfigurationSection("quest-progress." + id + ".task-progress")) {
for (String taskid : data.getConfigurationSection("quest-progress." + id + ".task-progress").getKeys(false)) {
@@ -131,6 +132,7 @@ public class YamlStorageProvider implements StorageProvider {
for (QuestProgress questProgress : questProgressValues) {
if (!questProgress.isModified()) continue;
data.set("quest-progress." + questProgress.getQuestId() + ".started", questProgress.isStarted());
+ data.set("quest-progress." + questProgress.getQuestId() + ".started-date", questProgress.getStartedDate());
data.set("quest-progress." + questProgress.getQuestId() + ".completed", questProgress.isCompleted());
data.set("quest-progress." + questProgress.getQuestId() + ".completed-before", questProgress.isCompletedBefore());
data.set("quest-progress." + questProgress.getQuestId() + ".completion-date", questProgress.getCompletionDate());