mirror of
https://github.com/Xiao-MoMi/Custom-Fishing.git
synced 2025-12-23 17:09:33 +00:00
added export legacy command
This commit is contained in:
@@ -21,6 +21,7 @@ import net.momirealms.customfishing.api.data.user.OfflineUser;
|
|||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
@@ -31,9 +32,13 @@ public interface DataStorageInterface {
|
|||||||
|
|
||||||
StorageType getStorageType();
|
StorageType getStorageType();
|
||||||
|
|
||||||
CompletableFuture<Optional<PlayerData>> getPlayerData(UUID uuid, boolean force);
|
CompletableFuture<Optional<PlayerData>> getPlayerData(UUID uuid, boolean lock);
|
||||||
|
|
||||||
CompletableFuture<Boolean> savePlayerData(UUID uuid, PlayerData playerData, boolean unlock);
|
CompletableFuture<Boolean> savePlayerData(UUID uuid, PlayerData playerData, boolean unlock);
|
||||||
|
|
||||||
void savePlayersData(Collection<? extends OfflineUser> users, boolean unlock);
|
void savePlayersData(Collection<? extends OfflineUser> users, boolean unlock);
|
||||||
|
|
||||||
|
void lockPlayerData(UUID uuid, boolean lock);
|
||||||
|
|
||||||
|
Set<UUID> getUniqueUsers(boolean legacy);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package net.momirealms.customfishing.api.data;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
public interface LegacyDataStorageInterface extends DataStorageInterface {
|
||||||
|
|
||||||
|
CompletableFuture<Optional<PlayerData>> getLegacyPlayerData(UUID uuid);
|
||||||
|
}
|
||||||
@@ -25,7 +25,7 @@ import java.util.Map;
|
|||||||
|
|
||||||
public class StatisticData {
|
public class StatisticData {
|
||||||
|
|
||||||
@SerializedName("stats")
|
@SerializedName("map")
|
||||||
public Map<String, Integer> statisticMap;
|
public Map<String, Integer> statisticMap;
|
||||||
|
|
||||||
public StatisticData(@NotNull Map<String, Integer> data) {
|
public StatisticData(@NotNull Map<String, Integer> data) {
|
||||||
|
|||||||
@@ -27,5 +27,4 @@ public enum StorageType {
|
|||||||
MariaDB,
|
MariaDB,
|
||||||
MongoDB,
|
MongoDB,
|
||||||
Redis
|
Redis
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,14 +44,13 @@ public interface StorageManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an offline user's data
|
* Get an offline user's data
|
||||||
* force reading would ignore the database lock
|
|
||||||
* Otherwise it would return Optional.empty() if data is locked
|
* Otherwise it would return Optional.empty() if data is locked
|
||||||
* It an offline user never played the server, its name would equal "" (empty string)
|
* It an offline user never played the server, its name would equal "" (empty string)
|
||||||
* @param uuid uuid
|
* @param uuid uuid
|
||||||
* @param force force
|
* @param lock lock
|
||||||
* @return offline user data
|
* @return offline user data
|
||||||
*/
|
*/
|
||||||
CompletableFuture<Optional<OfflineUser>> getOfflineUser(UUID uuid, boolean force);
|
CompletableFuture<Optional<OfflineUser>> getOfflineUser(UUID uuid, boolean lock);
|
||||||
|
|
||||||
CompletableFuture<Boolean> saveUserData(OfflineUser offlineUser, boolean unlock);
|
CompletableFuture<Boolean> saveUserData(OfflineUser offlineUser, boolean unlock);
|
||||||
|
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ public class CommandManagerImpl implements CommandManager {
|
|||||||
getReloadCommand(),
|
getReloadCommand(),
|
||||||
getMarketCommand(),
|
getMarketCommand(),
|
||||||
getAboutCommand(),
|
getAboutCommand(),
|
||||||
|
DataCommand.INSTANCE.getDataCommand(),
|
||||||
CompetitionCommand.INSTANCE.getCompetitionCommand(),
|
CompetitionCommand.INSTANCE.getCompetitionCommand(),
|
||||||
ItemCommand.INSTANCE.getItemCommand(),
|
ItemCommand.INSTANCE.getItemCommand(),
|
||||||
DebugCommand.INSTANCE.getDebugCommand(),
|
DebugCommand.INSTANCE.getDebugCommand(),
|
||||||
|
|||||||
@@ -0,0 +1,112 @@
|
|||||||
|
package net.momirealms.customfishing.command.sub;
|
||||||
|
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import dev.jorel.commandapi.CommandAPICommand;
|
||||||
|
import dev.jorel.commandapi.arguments.ArgumentSuggestions;
|
||||||
|
import dev.jorel.commandapi.arguments.StringArgument;
|
||||||
|
import net.momirealms.customfishing.adventure.AdventureManagerImpl;
|
||||||
|
import net.momirealms.customfishing.api.CustomFishingPlugin;
|
||||||
|
import net.momirealms.customfishing.api.data.LegacyDataStorageInterface;
|
||||||
|
import net.momirealms.customfishing.api.util.LogUtils;
|
||||||
|
import net.momirealms.customfishing.storage.method.database.sql.MariaDBImpl;
|
||||||
|
import net.momirealms.customfishing.storage.method.database.sql.MySQLImpl;
|
||||||
|
import net.momirealms.customfishing.storage.method.file.YAMLImpl;
|
||||||
|
import net.momirealms.customfishing.util.CompletableFutures;
|
||||||
|
|
||||||
|
import java.io.BufferedWriter;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.zip.GZIPOutputStream;
|
||||||
|
|
||||||
|
public class DataCommand {
|
||||||
|
|
||||||
|
public static DataCommand INSTANCE = new DataCommand();
|
||||||
|
|
||||||
|
public CommandAPICommand getDataCommand() {
|
||||||
|
return new CommandAPICommand("data")
|
||||||
|
.withSubcommands(
|
||||||
|
getExportLegacyCommand()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandAPICommand getExportLegacyCommand() {
|
||||||
|
return new CommandAPICommand("export-legacy")
|
||||||
|
.withArguments(new StringArgument("method")
|
||||||
|
.replaceSuggestions(ArgumentSuggestions.strings("MySQL", "MariaDB", "YAML")))
|
||||||
|
.executes((sender, args) -> {
|
||||||
|
String arg = (String) args.get("method");
|
||||||
|
if (arg == null) return;
|
||||||
|
CustomFishingPlugin plugin = CustomFishingPlugin.get();
|
||||||
|
plugin.getScheduler().runTaskAsync(() -> {
|
||||||
|
LegacyDataStorageInterface dataStorageInterface;
|
||||||
|
switch (arg) {
|
||||||
|
case "MySQL" -> dataStorageInterface = new MySQLImpl(plugin);
|
||||||
|
case "MariaDB" -> dataStorageInterface = new MariaDBImpl(plugin);
|
||||||
|
case "YAML" -> dataStorageInterface = new YAMLImpl(plugin);
|
||||||
|
default -> {
|
||||||
|
AdventureManagerImpl.getInstance().sendMessageWithPrefix(sender, "No such legacy storage method.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dataStorageInterface.initialize();
|
||||||
|
Set<UUID> uuids = dataStorageInterface.getUniqueUsers(true);
|
||||||
|
Set<CompletableFuture<Void>> futures = new HashSet<>();
|
||||||
|
AtomicInteger userCount = new AtomicInteger(0);
|
||||||
|
Map<UUID, String> out = Collections.synchronizedMap(new TreeMap<>());
|
||||||
|
|
||||||
|
for (UUID uuid : uuids) {
|
||||||
|
futures.add(dataStorageInterface.getLegacyPlayerData(uuid).thenAccept(it -> {
|
||||||
|
if (it.isPresent()) {
|
||||||
|
out.put(uuid, plugin.getStorageManager().toJson(it.get()));
|
||||||
|
userCount.incrementAndGet();
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
CompletableFuture<Void> overallFuture = CompletableFutures.allOf(futures);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
overallFuture.get(3, TimeUnit.SECONDS);
|
||||||
|
} catch (InterruptedException | ExecutionException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
break;
|
||||||
|
} catch (TimeoutException e) {
|
||||||
|
LogUtils.info("Progress: " + userCount.get() + "/" + uuids.size());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonObject outJson = new JsonObject();
|
||||||
|
for (Map.Entry<UUID, String> entry : out.entrySet()) {
|
||||||
|
outJson.addProperty(entry.getKey().toString(), entry.getValue());
|
||||||
|
}
|
||||||
|
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm");
|
||||||
|
String formattedDate = formatter.format(new Date());
|
||||||
|
File outFile = new File(plugin.getDataFolder(), "exported-" + formattedDate + ".json.gz");
|
||||||
|
try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new GZIPOutputStream(Files.newOutputStream(outFile.toPath())), StandardCharsets.UTF_8))) {
|
||||||
|
new GsonBuilder().disableHtmlEscaping().create().toJson(outJson, writer);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin.getScheduler().runTaskAsyncLater(dataStorageInterface::disable, 1, TimeUnit.SECONDS);
|
||||||
|
|
||||||
|
AdventureManagerImpl.getInstance().sendMessageWithPrefix(sender, "Finished.");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,6 +23,7 @@ import dev.jorel.commandapi.arguments.UUIDArgument;
|
|||||||
import net.momirealms.customfishing.adventure.AdventureManagerImpl;
|
import net.momirealms.customfishing.adventure.AdventureManagerImpl;
|
||||||
import net.momirealms.customfishing.api.CustomFishingPlugin;
|
import net.momirealms.customfishing.api.CustomFishingPlugin;
|
||||||
import net.momirealms.customfishing.api.data.user.OfflineUser;
|
import net.momirealms.customfishing.api.data.user.OfflineUser;
|
||||||
|
import net.momirealms.customfishing.setting.CFConfig;
|
||||||
import net.momirealms.customfishing.setting.CFLocale;
|
import net.momirealms.customfishing.setting.CFLocale;
|
||||||
import net.momirealms.customfishing.storage.user.OfflineUserImpl;
|
import net.momirealms.customfishing.storage.user.OfflineUserImpl;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
@@ -79,7 +80,7 @@ public class FishingBagCommand {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CustomFishingPlugin.get().getStorageManager().getOfflineUser(uuid, false).thenAccept(optional -> {
|
CustomFishingPlugin.get().getStorageManager().getOfflineUser(uuid, CFConfig.lockData).thenAccept(optional -> {
|
||||||
if (optional.isEmpty()) {
|
if (optional.isEmpty()) {
|
||||||
AdventureManagerImpl.getInstance().sendMessageWithPrefix(player, CFLocale.MSG_Never_Played);
|
AdventureManagerImpl.getInstance().sendMessageWithPrefix(player, CFLocale.MSG_Never_Played);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -83,6 +83,8 @@ public class CFConfig {
|
|||||||
|
|
||||||
// Data save interval
|
// Data save interval
|
||||||
public static int dataSaveInterval;
|
public static int dataSaveInterval;
|
||||||
|
// Lock data on join
|
||||||
|
public static boolean lockData;
|
||||||
|
|
||||||
// Legacy color code support
|
// Legacy color code support
|
||||||
public static boolean legacyColorSupport;
|
public static boolean legacyColorSupport;
|
||||||
@@ -140,6 +142,7 @@ public class CFConfig {
|
|||||||
placeholderLimit = config.getInt("mechanics.competition.placeholder-limit", 3);
|
placeholderLimit = config.getInt("mechanics.competition.placeholder-limit", 3);
|
||||||
|
|
||||||
dataSaveInterval = config.getInt("other-settings.data-saving-interval", 600);
|
dataSaveInterval = config.getInt("other-settings.data-saving-interval", 600);
|
||||||
|
lockData = config.getBoolean("other-settings.lock-data", true);
|
||||||
legacyColorSupport = config.getBoolean("other-settings.legacy-color-code-support", false);
|
legacyColorSupport = config.getBoolean("other-settings.legacy-color-code-support", false);
|
||||||
|
|
||||||
OffsetUtils.loadConfig(config.getConfigurationSection("other-settings.offset-characters"));
|
OffsetUtils.loadConfig(config.getConfigurationSection("other-settings.offset-characters"));
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ public class StorageManagerImpl implements StorageManager, Listener {
|
|||||||
this.timerSaveTask = this.plugin.getScheduler().runTaskAsyncTimer(
|
this.timerSaveTask = this.plugin.getScheduler().runTaskAsyncTimer(
|
||||||
() -> {
|
() -> {
|
||||||
long time1 = System.currentTimeMillis();
|
long time1 = System.currentTimeMillis();
|
||||||
this.dataSource.savePlayersData(this.onlineUserMap.values(), false);
|
this.dataSource.savePlayersData(this.onlineUserMap.values(), !CFConfig.lockData);
|
||||||
LogUtils.info("Data Saved for online players. Took " + (System.currentTimeMillis() - time1) + "ms.");
|
LogUtils.info("Data Saved for online players. Took " + (System.currentTimeMillis() - time1) + "ms.");
|
||||||
},
|
},
|
||||||
CFConfig.dataSaveInterval,
|
CFConfig.dataSaveInterval,
|
||||||
@@ -143,8 +143,8 @@ public class StorageManagerImpl implements StorageManager, Listener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Optional<OfflineUser>> getOfflineUser(UUID uuid, boolean force) {
|
public CompletableFuture<Optional<OfflineUser>> getOfflineUser(UUID uuid, boolean lock) {
|
||||||
var optionalDataFuture = dataSource.getPlayerData(uuid, force);
|
var optionalDataFuture = dataSource.getPlayerData(uuid, lock);
|
||||||
return optionalDataFuture.thenCompose(optionalUser -> {
|
return optionalDataFuture.thenCompose(optionalUser -> {
|
||||||
if (optionalUser.isEmpty()) {
|
if (optionalUser.isEmpty()) {
|
||||||
// locked
|
// locked
|
||||||
@@ -252,6 +252,7 @@ public class StorageManagerImpl implements StorageManager, Listener {
|
|||||||
if (optionalData.isPresent()) {
|
if (optionalData.isPresent()) {
|
||||||
putDataInCache(player, optionalData.get());
|
putDataInCache(player, optionalData.get());
|
||||||
task.cancel();
|
task.cancel();
|
||||||
|
if (CFConfig.lockData) dataSource.lockPlayerData(uuid, true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -264,7 +265,7 @@ public class StorageManagerImpl implements StorageManager, Listener {
|
|||||||
var player = Bukkit.getPlayer(uuid);
|
var player = Bukkit.getPlayer(uuid);
|
||||||
if (player == null || !player.isOnline() || times > 3)
|
if (player == null || !player.isOnline() || times > 3)
|
||||||
return;
|
return;
|
||||||
this.dataSource.getPlayerData(uuid, false).thenAccept(optionalData -> {
|
this.dataSource.getPlayerData(uuid, CFConfig.lockData).thenAccept(optionalData -> {
|
||||||
// should not be empty
|
// should not be empty
|
||||||
if (optionalData.isEmpty())
|
if (optionalData.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import net.momirealms.customfishing.api.data.user.OfflineUser;
|
|||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
public abstract class AbstractStorage implements DataStorageInterface {
|
public abstract class AbstractStorage implements DataStorageInterface {
|
||||||
|
|
||||||
@@ -52,4 +53,8 @@ public abstract class AbstractStorage implements DataStorageInterface {
|
|||||||
this.savePlayerData(user.getUUID(), user.getPlayerData(), unlock);
|
this.savePlayerData(user.getUUID(), user.getPlayerData(), unlock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void lockPlayerData(UUID uuid, boolean lock) {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,25 +18,20 @@
|
|||||||
package net.momirealms.customfishing.storage.method.database.nosql;
|
package net.momirealms.customfishing.storage.method.database.nosql;
|
||||||
|
|
||||||
import com.mongodb.*;
|
import com.mongodb.*;
|
||||||
import com.mongodb.bulk.BulkWriteResult;
|
import com.mongodb.client.*;
|
||||||
import com.mongodb.client.MongoClient;
|
|
||||||
import com.mongodb.client.MongoClients;
|
|
||||||
import com.mongodb.client.MongoCollection;
|
|
||||||
import com.mongodb.client.MongoDatabase;
|
|
||||||
import com.mongodb.client.model.*;
|
import com.mongodb.client.model.*;
|
||||||
import com.mongodb.client.result.InsertOneResult;
|
|
||||||
import com.mongodb.client.result.UpdateResult;
|
import com.mongodb.client.result.UpdateResult;
|
||||||
import net.momirealms.customfishing.api.CustomFishingPlugin;
|
import net.momirealms.customfishing.api.CustomFishingPlugin;
|
||||||
import net.momirealms.customfishing.api.data.PlayerData;
|
import net.momirealms.customfishing.api.data.PlayerData;
|
||||||
import net.momirealms.customfishing.api.data.StorageType;
|
import net.momirealms.customfishing.api.data.StorageType;
|
||||||
import net.momirealms.customfishing.api.data.user.OfflineUser;
|
import net.momirealms.customfishing.api.data.user.OfflineUser;
|
||||||
import net.momirealms.customfishing.api.util.LogUtils;
|
import net.momirealms.customfishing.api.util.LogUtils;
|
||||||
|
import net.momirealms.customfishing.setting.CFConfig;
|
||||||
import net.momirealms.customfishing.storage.method.AbstractStorage;
|
import net.momirealms.customfishing.storage.method.AbstractStorage;
|
||||||
import org.bson.Document;
|
import org.bson.Document;
|
||||||
import org.bson.UuidRepresentation;
|
import org.bson.UuidRepresentation;
|
||||||
import org.bson.conversions.Bson;
|
import org.bson.conversions.Bson;
|
||||||
import org.bson.types.Binary;
|
import org.bson.types.Binary;
|
||||||
import org.bson.types.ObjectId;
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.configuration.ConfigurationSection;
|
import org.bukkit.configuration.ConfigurationSection;
|
||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
@@ -109,23 +104,25 @@ public class MongoDBImpl extends AbstractStorage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Optional<PlayerData>> getPlayerData(UUID uuid, boolean force) {
|
public CompletableFuture<Optional<PlayerData>> getPlayerData(UUID uuid, boolean lock) {
|
||||||
var future = new CompletableFuture<Optional<PlayerData>>();
|
var future = new CompletableFuture<Optional<PlayerData>>();
|
||||||
plugin.getScheduler().runTaskAsync(() -> {
|
plugin.getScheduler().runTaskAsync(() -> {
|
||||||
MongoCollection<Document> collection = database.getCollection(getCollectionName("data"));
|
MongoCollection<Document> collection = database.getCollection(getCollectionName("data"));
|
||||||
Document doc = collection.find(Filters.eq("uuid", uuid)).first();
|
Document doc = collection.find(Filters.eq("uuid", uuid)).first();
|
||||||
if (doc == null) {
|
if (doc == null) {
|
||||||
if (Bukkit.getPlayer(uuid) != null) {
|
if (Bukkit.getPlayer(uuid) != null) {
|
||||||
|
if (lock) lockPlayerData(uuid, true);
|
||||||
future.complete(Optional.of(PlayerData.empty()));
|
future.complete(Optional.of(PlayerData.empty()));
|
||||||
} else {
|
} else {
|
||||||
future.complete(Optional.empty());
|
future.complete(Optional.empty());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!force && doc.getInteger("lock") != 0) {
|
if (doc.getInteger("lock") != 0 && getCurrentSeconds() - CFConfig.dataSaveInterval <= doc.getInteger("lock")) {
|
||||||
future.complete(Optional.of(PlayerData.LOCKED));
|
future.complete(Optional.of(PlayerData.LOCKED));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Binary binary = (Binary) doc.get("data");
|
Binary binary = (Binary) doc.get("data");
|
||||||
|
if (lock) lockPlayerData(uuid, true);
|
||||||
future.complete(Optional.of(plugin.getStorageManager().fromBytes(binary.getData())));
|
future.complete(Optional.of(plugin.getStorageManager().fromBytes(binary.getData())));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -172,4 +169,35 @@ public class MongoDBImpl extends AbstractStorage {
|
|||||||
LogUtils.warn("Failed to update data for online players", e);
|
LogUtils.warn("Failed to update data for online players", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void lockPlayerData(UUID uuid, boolean lock) {
|
||||||
|
MongoCollection<Document> collection = database.getCollection(getCollectionName("data"));
|
||||||
|
try {
|
||||||
|
Document query = new Document("uuid", uuid);
|
||||||
|
Bson updates = Updates.combine(Updates.set("lock", !lock ? 0 : getCurrentSeconds()));
|
||||||
|
UpdateOptions options = new UpdateOptions().upsert(true);
|
||||||
|
collection.updateOne(query, updates, options);
|
||||||
|
} catch (MongoException e) {
|
||||||
|
LogUtils.warn("Failed to lock data for " + uuid, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<UUID> getUniqueUsers(boolean legacy) {
|
||||||
|
// no legacy files
|
||||||
|
Set<UUID> uuids = new HashSet<>();
|
||||||
|
MongoCollection<Document> collection = database.getCollection(getCollectionName("data"));
|
||||||
|
try {
|
||||||
|
Bson projectionFields = Projections.fields(Projections.include("uuid"));
|
||||||
|
try (MongoCursor<Document> cursor = collection.find().projection(projectionFields).iterator()) {
|
||||||
|
while (cursor.hasNext()) {
|
||||||
|
uuids.add(cursor.next().get("uuid", UUID.class));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (MongoException e) {
|
||||||
|
LogUtils.warn("Failed to get unique data.", e);
|
||||||
|
}
|
||||||
|
return uuids;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,9 @@ import redis.clients.jedis.resps.Tuple;
|
|||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
@@ -226,7 +228,7 @@ public class RedisManager extends AbstractStorage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Optional<PlayerData>> getPlayerData(UUID uuid, boolean ignore) {
|
public CompletableFuture<Optional<PlayerData>> getPlayerData(UUID uuid, boolean lock) {
|
||||||
var future = new CompletableFuture<Optional<PlayerData>>();
|
var future = new CompletableFuture<Optional<PlayerData>>();
|
||||||
plugin.getScheduler().runTaskAsync(() -> {
|
plugin.getScheduler().runTaskAsync(() -> {
|
||||||
try (Jedis jedis = jedisPool.getResource()) {
|
try (Jedis jedis = jedisPool.getResource()) {
|
||||||
@@ -268,6 +270,11 @@ public class RedisManager extends AbstractStorage {
|
|||||||
return future;
|
return future;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<UUID> getUniqueUsers(boolean legacy) {
|
||||||
|
return new HashSet<>();
|
||||||
|
}
|
||||||
|
|
||||||
private byte[] getRedisKey(String key, @NotNull UUID uuid) {
|
private byte[] getRedisKey(String key, @NotNull UUID uuid) {
|
||||||
return (key + ":" + uuid).getBytes(StandardCharsets.UTF_8);
|
return (key + ":" + uuid).getBytes(StandardCharsets.UTF_8);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,18 +19,20 @@ package net.momirealms.customfishing.storage.method.database.sql;
|
|||||||
|
|
||||||
import com.zaxxer.hikari.HikariDataSource;
|
import com.zaxxer.hikari.HikariDataSource;
|
||||||
import net.momirealms.customfishing.api.CustomFishingPlugin;
|
import net.momirealms.customfishing.api.CustomFishingPlugin;
|
||||||
import net.momirealms.customfishing.api.data.StorageType;
|
import net.momirealms.customfishing.api.data.*;
|
||||||
import net.momirealms.customfishing.api.util.LogUtils;
|
import net.momirealms.customfishing.api.util.LogUtils;
|
||||||
import org.bukkit.configuration.ConfigurationSection;
|
import org.bukkit.configuration.ConfigurationSection;
|
||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
|
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.Locale;
|
import java.util.*;
|
||||||
import java.util.Map;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.Properties;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public abstract class AbstractHikariDatabase extends AbstractSQLDatabase {
|
public abstract class AbstractHikariDatabase extends AbstractSQLDatabase implements LegacyDataStorageInterface {
|
||||||
|
|
||||||
private HikariDataSource dataSource;
|
private HikariDataSource dataSource;
|
||||||
private final String driverClass;
|
private final String driverClass;
|
||||||
@@ -117,4 +119,56 @@ public abstract class AbstractHikariDatabase extends AbstractSQLDatabase {
|
|||||||
public Connection getConnection() throws SQLException {
|
public Connection getConnection() throws SQLException {
|
||||||
return dataSource.getConnection();
|
return dataSource.getConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletableFuture<Optional<PlayerData>> getLegacyPlayerData(UUID uuid) {
|
||||||
|
var future = new CompletableFuture<Optional<PlayerData>>();
|
||||||
|
plugin.getScheduler().runTaskAsync(() -> {
|
||||||
|
try (
|
||||||
|
Connection connection = getConnection()
|
||||||
|
) {
|
||||||
|
var builder = new PlayerData.Builder().setName("");
|
||||||
|
PreparedStatement statementOne = connection.prepareStatement(String.format(SqlConstants.SQL_SELECT_BY_UUID, getTableName("fishingbag")));
|
||||||
|
statementOne.setString(1, uuid.toString());
|
||||||
|
ResultSet rsOne = statementOne.executeQuery();
|
||||||
|
if (rsOne.next()) {
|
||||||
|
int size = rsOne.getInt("size");
|
||||||
|
String contents = rsOne.getString("contents");
|
||||||
|
builder.setBagData(new InventoryData(contents, size));
|
||||||
|
} else {
|
||||||
|
builder.setBagData(InventoryData.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
PreparedStatement statementTwo = connection.prepareStatement(String.format(SqlConstants.SQL_SELECT_BY_UUID, getTableName("selldata")));
|
||||||
|
statementTwo.setString(1, uuid.toString());
|
||||||
|
ResultSet rsTwo = statementTwo.executeQuery();
|
||||||
|
if (rsTwo.next()) {
|
||||||
|
int date = rsTwo.getInt("date");
|
||||||
|
double money = rsTwo.getInt("money");
|
||||||
|
builder.setEarningData(new EarningData(money, date));
|
||||||
|
} else {
|
||||||
|
builder.setEarningData(EarningData.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
PreparedStatement statementThree = connection.prepareStatement(String.format(SqlConstants.SQL_SELECT_BY_UUID, getTableName("statistics")));
|
||||||
|
statementThree.setString(1, uuid.toString());
|
||||||
|
ResultSet rsThree = statementThree.executeQuery();
|
||||||
|
if (rsThree.next()) {
|
||||||
|
String stats = rsThree.getString("stats");
|
||||||
|
var amountMap = (Map<String, Integer>) Arrays.stream(stats.split(";"))
|
||||||
|
.map(element -> element.split(":"))
|
||||||
|
.filter(pair -> pair.length == 2)
|
||||||
|
.collect(Collectors.toMap(pair -> pair[0], pair -> Integer.parseInt(pair[1])));
|
||||||
|
builder.setStats(new StatisticData(amountMap));
|
||||||
|
} else {
|
||||||
|
builder.setStats(StatisticData.empty());
|
||||||
|
}
|
||||||
|
future.complete(Optional.of(builder.build()));
|
||||||
|
} catch (SQLException e) {
|
||||||
|
LogUtils.warn("Failed to get " + uuid + "'s data.", e);
|
||||||
|
future.completeExceptionally(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return future;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ public abstract class AbstractSQLDatabase extends AbstractStorage {
|
|||||||
|
|
||||||
@SuppressWarnings("DuplicatedCode")
|
@SuppressWarnings("DuplicatedCode")
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Optional<PlayerData>> getPlayerData(UUID uuid, boolean force) {
|
public CompletableFuture<Optional<PlayerData>> getPlayerData(UUID uuid, boolean lock) {
|
||||||
var future = new CompletableFuture<Optional<PlayerData>>();
|
var future = new CompletableFuture<Optional<PlayerData>>();
|
||||||
plugin.getScheduler().runTaskAsync(() -> {
|
plugin.getScheduler().runTaskAsync(() -> {
|
||||||
try (
|
try (
|
||||||
@@ -89,10 +89,8 @@ public abstract class AbstractSQLDatabase extends AbstractStorage {
|
|||||||
statement.setString(1, uuid.toString());
|
statement.setString(1, uuid.toString());
|
||||||
ResultSet rs = statement.executeQuery();
|
ResultSet rs = statement.executeQuery();
|
||||||
if (rs.next()) {
|
if (rs.next()) {
|
||||||
int lock = rs.getInt(2);
|
int lockValue = rs.getInt(2);
|
||||||
if (!force && (lock != 0 && getCurrentSeconds() - CFConfig.dataSaveInterval <= lock)) {
|
if (lockValue != 0 && getCurrentSeconds() - CFConfig.dataSaveInterval <= lockValue) {
|
||||||
statement.close();
|
|
||||||
rs.close();
|
|
||||||
connection.close();
|
connection.close();
|
||||||
future.complete(Optional.of(PlayerData.LOCKED));
|
future.complete(Optional.of(PlayerData.LOCKED));
|
||||||
return;
|
return;
|
||||||
@@ -100,11 +98,11 @@ public abstract class AbstractSQLDatabase extends AbstractStorage {
|
|||||||
final Blob blob = rs.getBlob("data");
|
final Blob blob = rs.getBlob("data");
|
||||||
final byte[] dataByteArray = blob.getBytes(1, (int) blob.length());
|
final byte[] dataByteArray = blob.getBytes(1, (int) blob.length());
|
||||||
blob.free();
|
blob.free();
|
||||||
lockPlayerData(uuid);
|
if (lock) lockPlayerData(uuid, true);
|
||||||
future.complete(Optional.of(plugin.getStorageManager().fromBytes(dataByteArray)));
|
future.complete(Optional.of(plugin.getStorageManager().fromBytes(dataByteArray)));
|
||||||
} else if (Bukkit.getPlayer(uuid) != null) {
|
} else if (Bukkit.getPlayer(uuid) != null) {
|
||||||
var data = PlayerData.empty();
|
var data = PlayerData.empty();
|
||||||
insertPlayerData(uuid, data);
|
insertPlayerData(uuid, data, lock);
|
||||||
future.complete(Optional.of(data));
|
future.complete(Optional.of(data));
|
||||||
} else {
|
} else {
|
||||||
future.complete(Optional.empty());
|
future.complete(Optional.empty());
|
||||||
@@ -162,13 +160,13 @@ public abstract class AbstractSQLDatabase extends AbstractStorage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void insertPlayerData(UUID uuid, PlayerData playerData) {
|
public void insertPlayerData(UUID uuid, PlayerData playerData, boolean lock) {
|
||||||
try (
|
try (
|
||||||
Connection connection = getConnection();
|
Connection connection = getConnection();
|
||||||
PreparedStatement statement = connection.prepareStatement(String.format(SqlConstants.SQL_INSERT_DATA_BY_UUID, getTableName("data")))
|
PreparedStatement statement = connection.prepareStatement(String.format(SqlConstants.SQL_INSERT_DATA_BY_UUID, getTableName("data")))
|
||||||
) {
|
) {
|
||||||
statement.setString(1, uuid.toString());
|
statement.setString(1, uuid.toString());
|
||||||
statement.setInt(2, getCurrentSeconds());
|
statement.setInt(2, lock ? getCurrentSeconds() : 0);
|
||||||
statement.setBlob(3, new ByteArrayInputStream(plugin.getStorageManager().toBytes(playerData)));
|
statement.setBlob(3, new ByteArrayInputStream(plugin.getStorageManager().toBytes(playerData)));
|
||||||
statement.execute();
|
statement.execute();
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
@@ -176,12 +174,13 @@ public abstract class AbstractSQLDatabase extends AbstractStorage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void lockPlayerData(UUID uuid) {
|
@Override
|
||||||
|
public void lockPlayerData(UUID uuid, boolean lock) {
|
||||||
try (
|
try (
|
||||||
Connection connection = getConnection();
|
Connection connection = getConnection();
|
||||||
PreparedStatement statement = connection.prepareStatement(String.format(SqlConstants.SQL_LOCK_BY_UUID, getTableName("data")))
|
PreparedStatement statement = connection.prepareStatement(String.format(SqlConstants.SQL_LOCK_BY_UUID, getTableName("data")))
|
||||||
) {
|
) {
|
||||||
statement.setInt(1, getCurrentSeconds());
|
statement.setInt(1, lock ? getCurrentSeconds() : 0);
|
||||||
statement.setString(2, uuid.toString());
|
statement.setString(2, uuid.toString());
|
||||||
statement.execute();
|
statement.execute();
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
@@ -189,8 +188,26 @@ public abstract class AbstractSQLDatabase extends AbstractStorage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<UUID> getUniqueUsers(boolean legacy) {
|
||||||
|
Set<UUID> uuids = new HashSet<>();
|
||||||
|
try (Connection connection = getConnection();
|
||||||
|
PreparedStatement statement = connection.prepareStatement(String.format(SqlConstants.SQL_SELECT_ALL_UUID, legacy ? getTableName("fishingbag") : getTableName("data")))) {
|
||||||
|
try (ResultSet rs = statement.executeQuery()) {
|
||||||
|
while (rs.next()) {
|
||||||
|
UUID uuid = UUID.fromString(rs.getString("uuid"));
|
||||||
|
uuids.add(uuid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
LogUtils.warn("Failed to get unique data.", e);
|
||||||
|
}
|
||||||
|
return uuids;
|
||||||
|
}
|
||||||
|
|
||||||
public static class SqlConstants {
|
public static class SqlConstants {
|
||||||
public static final String SQL_SELECT_BY_UUID = "SELECT * FROM `%s` WHERE `uuid` = ?";
|
public static final String SQL_SELECT_BY_UUID = "SELECT * FROM `%s` WHERE `uuid` = ?";
|
||||||
|
public static final String SQL_SELECT_ALL_UUID = "SELECT uuid FROM `%s`";
|
||||||
public static final String SQL_UPDATE_BY_UUID = "UPDATE `%s` SET `lock` = ?, `data` = ? WHERE `uuid` = ?";
|
public static final String SQL_UPDATE_BY_UUID = "UPDATE `%s` SET `lock` = ?, `data` = ? WHERE `uuid` = ?";
|
||||||
public static final String SQL_LOCK_BY_UUID = "UPDATE `%s` SET `lock` = ? WHERE `uuid` = ?";
|
public static final String SQL_LOCK_BY_UUID = "UPDATE `%s` SET `lock` = ? WHERE `uuid` = ?";
|
||||||
public static final String SQL_INSERT_DATA_BY_UUID = "INSERT INTO `%s`(`uuid`, `lock`, `data`) VALUES(?, ?, ?)";
|
public static final String SQL_INSERT_DATA_BY_UUID = "INSERT INTO `%s`(`uuid`, `lock`, `data`) VALUES(?, ?, ?)";
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ public class SQLiteImpl extends AbstractSQLDatabase {
|
|||||||
|
|
||||||
@SuppressWarnings("DuplicatedCode")
|
@SuppressWarnings("DuplicatedCode")
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Optional<PlayerData>> getPlayerData(UUID uuid, boolean force) {
|
public CompletableFuture<Optional<PlayerData>> getPlayerData(UUID uuid, boolean lock) {
|
||||||
var future = new CompletableFuture<Optional<PlayerData>>();
|
var future = new CompletableFuture<Optional<PlayerData>>();
|
||||||
plugin.getScheduler().runTaskAsync(() -> {
|
plugin.getScheduler().runTaskAsync(() -> {
|
||||||
try (
|
try (
|
||||||
@@ -87,20 +87,18 @@ public class SQLiteImpl extends AbstractSQLDatabase {
|
|||||||
statement.setString(1, uuid.toString());
|
statement.setString(1, uuid.toString());
|
||||||
ResultSet rs = statement.executeQuery();
|
ResultSet rs = statement.executeQuery();
|
||||||
if (rs.next()) {
|
if (rs.next()) {
|
||||||
int lock = rs.getInt(2);
|
int lockValue = rs.getInt(2);
|
||||||
if (!force && (lock != 0 && getCurrentSeconds() - CFConfig.dataSaveInterval <= lock)) {
|
if (lockValue != 0 && getCurrentSeconds() - CFConfig.dataSaveInterval <= lockValue) {
|
||||||
statement.close();
|
|
||||||
rs.close();
|
|
||||||
connection.close();
|
connection.close();
|
||||||
future.complete(Optional.of(PlayerData.LOCKED));
|
future.complete(Optional.of(PlayerData.LOCKED));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final byte[] dataByteArray = rs.getBytes("data");
|
final byte[] dataByteArray = rs.getBytes("data");
|
||||||
lockPlayerData(uuid);
|
if (lock) lockPlayerData(uuid, true);
|
||||||
future.complete(Optional.of(plugin.getStorageManager().fromBytes(dataByteArray)));
|
future.complete(Optional.of(plugin.getStorageManager().fromBytes(dataByteArray)));
|
||||||
} else if (Bukkit.getPlayer(uuid) != null) {
|
} else if (Bukkit.getPlayer(uuid) != null) {
|
||||||
var data = PlayerData.empty();
|
var data = PlayerData.empty();
|
||||||
insertPlayerData(uuid, data);
|
insertPlayerData(uuid, data, lock);
|
||||||
future.complete(Optional.of(data));
|
future.complete(Optional.of(data));
|
||||||
} else {
|
} else {
|
||||||
future.complete(Optional.empty());
|
future.complete(Optional.empty());
|
||||||
@@ -158,13 +156,13 @@ public class SQLiteImpl extends AbstractSQLDatabase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void insertPlayerData(UUID uuid, PlayerData playerData) {
|
public void insertPlayerData(UUID uuid, PlayerData playerData, boolean lock) {
|
||||||
try (
|
try (
|
||||||
Connection connection = getConnection();
|
Connection connection = getConnection();
|
||||||
PreparedStatement statement = connection.prepareStatement(String.format(SqlConstants.SQL_INSERT_DATA_BY_UUID, getTableName("data")))
|
PreparedStatement statement = connection.prepareStatement(String.format(SqlConstants.SQL_INSERT_DATA_BY_UUID, getTableName("data")))
|
||||||
) {
|
) {
|
||||||
statement.setString(1, uuid.toString());
|
statement.setString(1, uuid.toString());
|
||||||
statement.setInt(2, getCurrentSeconds());
|
statement.setInt(2, lock ? getCurrentSeconds() : 0);
|
||||||
statement.setBytes(3, plugin.getStorageManager().toBytes(playerData));
|
statement.setBytes(3, plugin.getStorageManager().toBytes(playerData));
|
||||||
statement.execute();
|
statement.execute();
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
|
|||||||
@@ -29,12 +29,15 @@ import java.io.FileInputStream;
|
|||||||
import java.io.FileWriter;
|
import java.io.FileWriter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
public class JsonImpl extends AbstractStorage {
|
public class JsonImpl extends AbstractStorage {
|
||||||
|
|
||||||
|
@SuppressWarnings("ResultOfMethodCallIgnored")
|
||||||
public JsonImpl(CustomFishingPlugin plugin) {
|
public JsonImpl(CustomFishingPlugin plugin) {
|
||||||
super(plugin);
|
super(plugin);
|
||||||
File folder = new File(plugin.getDataFolder(), "data");
|
File folder = new File(plugin.getDataFolder(), "data");
|
||||||
@@ -47,7 +50,7 @@ public class JsonImpl extends AbstractStorage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Optional<PlayerData>> getPlayerData(UUID uuid, boolean ignore) {
|
public CompletableFuture<Optional<PlayerData>> getPlayerData(UUID uuid, boolean lock) {
|
||||||
File file = getPlayerDataFile(uuid);
|
File file = getPlayerDataFile(uuid);
|
||||||
PlayerData playerData;
|
PlayerData playerData;
|
||||||
if (file.exists()) {
|
if (file.exists()) {
|
||||||
@@ -94,4 +97,20 @@ public class JsonImpl extends AbstractStorage {
|
|||||||
}
|
}
|
||||||
return fileBytes;
|
return fileBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<UUID> getUniqueUsers(boolean legacy) {
|
||||||
|
// No legacy files
|
||||||
|
File folder = new File(plugin.getDataFolder(), "data");
|
||||||
|
Set<UUID> uuids = new HashSet<>();
|
||||||
|
if (folder.exists()) {
|
||||||
|
File[] files = folder.listFiles();
|
||||||
|
if (files != null) {
|
||||||
|
for (File file : files) {
|
||||||
|
uuids.add(UUID.fromString(file.getName().substring(file.getName().length() - 5)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return uuids;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,14 +28,12 @@ import org.bukkit.configuration.file.YamlConfiguration;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.HashMap;
|
import java.util.*;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
public class YAMLImpl extends AbstractStorage {
|
public class YAMLImpl extends AbstractStorage implements LegacyDataStorageInterface {
|
||||||
|
|
||||||
|
@SuppressWarnings("ResultOfMethodCallIgnored")
|
||||||
public YAMLImpl(CustomFishingPlugin plugin) {
|
public YAMLImpl(CustomFishingPlugin plugin) {
|
||||||
super(plugin);
|
super(plugin);
|
||||||
File folder = new File(plugin.getDataFolder(), "data");
|
File folder = new File(plugin.getDataFolder(), "data");
|
||||||
@@ -52,7 +50,7 @@ public class YAMLImpl extends AbstractStorage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Optional<PlayerData>> getPlayerData(UUID uuid, boolean ignore) {
|
public CompletableFuture<Optional<PlayerData>> getPlayerData(UUID uuid, boolean lock) {
|
||||||
File dataFile = getPlayerDataFile(uuid);
|
File dataFile = getPlayerDataFile(uuid);
|
||||||
if (!dataFile.exists()) {
|
if (!dataFile.exists()) {
|
||||||
if (Bukkit.getPlayer(uuid) != null) {
|
if (Bukkit.getPlayer(uuid) != null) {
|
||||||
@@ -91,6 +89,26 @@ public class YAMLImpl extends AbstractStorage {
|
|||||||
return CompletableFuture.completedFuture(true);
|
return CompletableFuture.completedFuture(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<UUID> getUniqueUsers(boolean legacy) {
|
||||||
|
File folder;
|
||||||
|
if (legacy) {
|
||||||
|
folder = new File(plugin.getDataFolder(), "data/fishingbag");
|
||||||
|
} else {
|
||||||
|
folder = new File(plugin.getDataFolder(), "data");
|
||||||
|
}
|
||||||
|
Set<UUID> uuids = new HashSet<>();
|
||||||
|
if (folder.exists()) {
|
||||||
|
File[] files = folder.listFiles();
|
||||||
|
if (files != null) {
|
||||||
|
for (File file : files) {
|
||||||
|
uuids.add(UUID.fromString(file.getName().substring(0, file.getName().length() - 4)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return uuids;
|
||||||
|
}
|
||||||
|
|
||||||
public StatisticData getStatistics(ConfigurationSection section) {
|
public StatisticData getStatistics(ConfigurationSection section) {
|
||||||
if (section == null)
|
if (section == null)
|
||||||
return StatisticData.empty();
|
return StatisticData.empty();
|
||||||
@@ -102,4 +120,42 @@ public class YAMLImpl extends AbstractStorage {
|
|||||||
return new StatisticData(map);
|
return new StatisticData(map);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletableFuture<Optional<PlayerData>> getLegacyPlayerData(UUID uuid) {
|
||||||
|
var builder = new PlayerData.Builder().setName("");
|
||||||
|
File bagFile = new File(plugin.getDataFolder(), "data/fishingbag/" + uuid + ".yml");
|
||||||
|
if (bagFile.exists()) {
|
||||||
|
YamlConfiguration yaml = YamlConfiguration.loadConfiguration(bagFile);
|
||||||
|
String contents = yaml.getString("contents", "");
|
||||||
|
int size = yaml.getInt("size", 9);
|
||||||
|
builder.setBagData(new InventoryData(contents, size));
|
||||||
|
} else {
|
||||||
|
builder.setBagData(InventoryData.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
File statFile = new File(plugin.getDataFolder(), "data/statistics/" + uuid + ".yml");
|
||||||
|
if (statFile.exists()) {
|
||||||
|
YamlConfiguration yaml = YamlConfiguration.loadConfiguration(statFile);
|
||||||
|
HashMap<String, Integer> map = new HashMap<>();
|
||||||
|
for (Map.Entry<String, Object> entry : yaml.getValues(false).entrySet()) {
|
||||||
|
if (entry.getValue() instanceof Integer integer) {
|
||||||
|
map.put(entry.getKey(), integer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
builder.setStats(new StatisticData(map));
|
||||||
|
} else {
|
||||||
|
builder.setStats(StatisticData.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
File sellFile = new File(plugin.getDataFolder(), "data/sell/" + uuid + ".yml");
|
||||||
|
if (sellFile.exists()) {
|
||||||
|
YamlConfiguration yaml = YamlConfiguration.loadConfiguration(sellFile);
|
||||||
|
builder.setEarningData(new EarningData(yaml.getDouble("earnings"), yaml.getInt("date")));
|
||||||
|
} else {
|
||||||
|
builder.setEarningData(EarningData.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
return CompletableFuture.completedFuture(Optional.of(builder.build()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package net.momirealms.customfishing.util;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.stream.Collector;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public final class CompletableFutures {
|
||||||
|
private CompletableFutures() {}
|
||||||
|
|
||||||
|
public static <T extends CompletableFuture<?>> Collector<T, ImmutableList.Builder<T>, CompletableFuture<Void>> collector() {
|
||||||
|
return Collector.of(
|
||||||
|
ImmutableList.Builder::new,
|
||||||
|
ImmutableList.Builder::add,
|
||||||
|
(l, r) -> l.addAll(r.build()),
|
||||||
|
builder -> allOf(builder.build())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CompletableFuture<Void> allOf(Stream<? extends CompletableFuture<?>> futures) {
|
||||||
|
CompletableFuture<?>[] arr = futures.toArray(CompletableFuture[]::new);
|
||||||
|
return CompletableFuture.allOf(arr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CompletableFuture<Void> allOf(Collection<? extends CompletableFuture<?>> futures) {
|
||||||
|
CompletableFuture<?>[] arr = futures.toArray(new CompletableFuture[0]);
|
||||||
|
return CompletableFuture.allOf(arr);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -149,6 +149,10 @@ other-settings:
|
|||||||
# set to -1 to disable
|
# set to -1 to disable
|
||||||
data-saving-interval: 600
|
data-saving-interval: 600
|
||||||
|
|
||||||
|
# Lock player's data if a player is playing on a server that connected to database
|
||||||
|
# If you can ensure low database link latency and fast processing, you can consider disabling this option to save some performance
|
||||||
|
lock-data: true
|
||||||
|
|
||||||
# Requires PlaceholderAPI to work
|
# Requires PlaceholderAPI to work
|
||||||
placeholder-register:
|
placeholder-register:
|
||||||
'{date}': '%server_time_yyyy-MM-dd-HH:mm:ss%'
|
'{date}': '%server_time_yyyy-MM-dd-HH:mm:ss%'
|
||||||
|
|||||||
Reference in New Issue
Block a user