9
0
mirror of https://github.com/Xiao-MoMi/Custom-Fishing.git synced 2026-01-03 14:22:10 +00:00

added import command

This commit is contained in:
XiaoMoMi
2023-09-14 04:32:18 +08:00
parent efd31b7eb9
commit 9ed926364f
15 changed files with 227 additions and 31 deletions

View File

@@ -1,23 +1,25 @@
package net.momirealms.customfishing.command.sub;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
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.DataStorageInterface;
import net.momirealms.customfishing.api.data.LegacyDataStorageInterface;
import net.momirealms.customfishing.api.data.PlayerData;
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 org.bukkit.Bukkit;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.text.SimpleDateFormat;
@@ -27,6 +29,7 @@ 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.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
public class DataCommand {
@@ -36,10 +39,13 @@ public class DataCommand {
public CommandAPICommand getDataCommand() {
return new CommandAPICommand("data")
.withSubcommands(
getExportLegacyCommand()
getExportLegacyCommand(),
getExportCommand(),
getImportCommand()
);
}
@SuppressWarnings("DuplicatedCode")
public CommandAPICommand getExportLegacyCommand() {
return new CommandAPICommand("export-legacy")
.withArguments(new StringArgument("method")
@@ -49,6 +55,9 @@ public class DataCommand {
if (arg == null) return;
CustomFishingPlugin plugin = CustomFishingPlugin.get();
plugin.getScheduler().runTaskAsync(() -> {
AdventureManagerImpl.getInstance().sendMessageWithPrefix(sender, "Starting <aqua>export</aqua>.");
LegacyDataStorageInterface dataStorageInterface;
switch (arg) {
case "MySQL" -> dataStorageInterface = new MySQLImpl(plugin);
@@ -103,9 +112,143 @@ public class DataCommand {
e.printStackTrace();
}
plugin.getScheduler().runTaskAsyncLater(dataStorageInterface::disable, 1, TimeUnit.SECONDS);
dataStorageInterface.disable();
AdventureManagerImpl.getInstance().sendMessageWithPrefix(sender, "Finished.");
AdventureManagerImpl.getInstance().sendMessageWithPrefix(sender, "Completed.");
});
});
}
@SuppressWarnings("DuplicatedCode")
public CommandAPICommand getExportCommand() {
return new CommandAPICommand("export")
.executesConsole((sender, args) -> {
if (Bukkit.getOnlinePlayers().size() != 0) {
AdventureManagerImpl.getInstance().sendMessageWithPrefix(sender, "Please kick all the players before exporting. Otherwise the cache will be inconsistent with data, resulting in the backup file not being up to date.");
return;
}
CustomFishingPlugin plugin = CustomFishingPlugin.get();
plugin.getScheduler().runTaskAsync(() -> {
AdventureManagerImpl.getInstance().sendMessageWithPrefix(sender, "Starting <aqua>export</aqua>.");
DataStorageInterface dataStorageInterface = plugin.getStorageManager().getDataSource();
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<>());
int amount = uuids.size();
for (UUID uuid : uuids) {
futures.add(dataStorageInterface.getPlayerData(uuid, false).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() + "/" + amount);
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();
}
AdventureManagerImpl.getInstance().sendMessageWithPrefix(sender, "Completed.");
});
});
}
@SuppressWarnings("DuplicatedCode")
public CommandAPICommand getImportCommand() {
return new CommandAPICommand("import")
.withArguments(new StringArgument("file"))
.executesConsole((sender, args) -> {
if (Bukkit.getOnlinePlayers().size() != 0) {
AdventureManagerImpl.getInstance().sendMessageWithPrefix(sender, "Please kick all the players before importing. Otherwise the cache will be inconsistent with data.");
return;
}
String fileName = (String) args.get("file");
if (fileName == null) return;
CustomFishingPlugin plugin = CustomFishingPlugin.get();
File file = new File(plugin.getDataFolder(), fileName);
if (!file.exists()) {
AdventureManagerImpl.getInstance().sendMessageWithPrefix(sender, "File not exists.");
return;
}
if (!file.getName().endsWith(".json.gz")) {
AdventureManagerImpl.getInstance().sendMessageWithPrefix(sender, "Invalid file.");
return;
}
plugin.getScheduler().runTaskAsync(() -> {
AdventureManagerImpl.getInstance().sendMessageWithPrefix(sender, "Starting <aqua>import</aqua>.");
JsonObject data;
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new GZIPInputStream(Files.newInputStream(file.toPath())), StandardCharsets.UTF_8))) {
data = new GsonBuilder().disableHtmlEscaping().create().fromJson(reader, JsonObject.class);
} catch (IOException e) {
AdventureManagerImpl.getInstance().sendMessageWithPrefix(sender, "Error occurred when reading the backup file.");
e.printStackTrace();
return;
}
DataStorageInterface dataStorageInterface = plugin.getStorageManager().getDataSource();
var entrySet = data.entrySet();
int amount = entrySet.size();
AtomicInteger userCount = new AtomicInteger(0);
Set<CompletableFuture<Void>> futures = new HashSet<>();
for (Map.Entry<String, JsonElement> entry : entrySet) {
UUID uuid = UUID.fromString(entry.getKey());
if (entry.getValue() instanceof JsonPrimitive primitive) {
PlayerData playerData = plugin.getStorageManager().fromJson(primitive.getAsString());
futures.add(dataStorageInterface.updateOrInsertPlayerData(uuid, playerData, true).thenAccept(it -> 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() + "/" + amount);
continue;
}
break;
}
AdventureManagerImpl.getInstance().sendMessageWithPrefix(sender, "Completed.");
});
});
}

View File

@@ -63,7 +63,7 @@ public class BagManagerImpl implements BagManager, Listener {
public void disable() {
unload();
plugin.getStorageManager().getDataSource().savePlayersData(tempEditMap.values(), true);
plugin.getStorageManager().getDataSource().updateManyPlayersData(tempEditMap.values(), true);
}
@Override

View File

@@ -293,7 +293,7 @@ public class MarketManagerImpl implements MarketManager, Listener {
if (current.getAmount() <= left) {
itemStack.setAmount(itemStack.getAmount() + current.getAmount());
current.setAmount(0);
return;
break;
} else {
current.setAmount(current.getAmount() - left);
itemStack.setAmount(itemStack.getType().getMaxStackSize());
@@ -302,7 +302,7 @@ public class MarketManagerImpl implements MarketManager, Listener {
} else {
gui.getInventory().setItem(slot, current.clone());
current.setAmount(0);
return;
break;
}
}
}

View File

@@ -17,6 +17,7 @@
package net.momirealms.customfishing.storage;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonSyntaxException;
import net.momirealms.customfishing.CustomFishingPluginImpl;
@@ -70,11 +71,13 @@ public class StorageManagerImpl implements StorageManager, Listener {
private RedisManager redisManager;
private String uniqueID;
private CancellableTask timerSaveTask;
private Gson gson;
public StorageManagerImpl(CustomFishingPluginImpl plugin) {
this.plugin = plugin;
this.locked = new HashSet<>();
this.onlineUserMap = new ConcurrentHashMap<>();
this.gson = new GsonBuilder().create();
Bukkit.getPluginManager().registerEvents(this, plugin);
}
@@ -113,7 +116,7 @@ public class StorageManagerImpl implements StorageManager, Listener {
this.timerSaveTask = this.plugin.getScheduler().runTaskAsyncTimer(
() -> {
long time1 = System.currentTimeMillis();
this.dataSource.savePlayersData(this.onlineUserMap.values(), !CFConfig.lockData);
this.dataSource.updateManyPlayersData(this.onlineUserMap.values(), !CFConfig.lockData);
LogUtils.info("Data Saved for online players. Took " + (System.currentTimeMillis() - time1) + "ms.");
},
CFConfig.dataSaveInterval,
@@ -124,7 +127,7 @@ public class StorageManagerImpl implements StorageManager, Listener {
public void disable() {
HandlerList.unregisterAll(this);
this.dataSource.savePlayersData(onlineUserMap.values(), true);
this.dataSource.updateManyPlayersData(onlineUserMap.values(), true);
this.onlineUserMap.clear();
if (this.dataSource != null)
this.dataSource.disable();
@@ -162,7 +165,7 @@ public class StorageManagerImpl implements StorageManager, Listener {
@Override
public CompletableFuture<Boolean> saveUserData(OfflineUser offlineUser, boolean unlock) {
return dataSource.savePlayerData(offlineUser.getUUID(), offlineUser.getPlayerData(), unlock);
return dataSource.updatePlayerData(offlineUser.getUUID(), offlineUser.getPlayerData(), unlock);
}
@Override
@@ -200,13 +203,13 @@ public class StorageManagerImpl implements StorageManager, Listener {
if (hasRedis) {
redisManager.setChangeServer(uuid).thenRun(
() -> redisManager.savePlayerData(uuid, data, true).thenRun(
() -> dataSource.savePlayerData(uuid, data, true).thenAccept(
() -> redisManager.updatePlayerData(uuid, data, true).thenRun(
() -> dataSource.updatePlayerData(uuid, data, true).thenAccept(
result -> {
if (result) locked.remove(uuid);
})));
} else {
dataSource.savePlayerData(uuid, data, true).thenAccept(
dataSource.updatePlayerData(uuid, data, true).thenAccept(
result -> {
if (result) locked.remove(uuid);
});
@@ -302,14 +305,19 @@ public class StorageManagerImpl implements StorageManager, Listener {
@Override
@NotNull
public String toJson(@NotNull PlayerData data) {
return new GsonBuilder().create().toJson(data);
return gson.toJson(data);
}
@Override
public PlayerData fromJson(String json) {
return gson.fromJson(json, PlayerData.class);
}
@Override
@NotNull
public PlayerData fromBytes(byte[] data) {
try {
return new GsonBuilder().create().fromJson(new String(data, StandardCharsets.UTF_8), PlayerData.class);
return gson.fromJson(new String(data, StandardCharsets.UTF_8), PlayerData.class);
} catch (JsonSyntaxException e) {
throw new DataSerializationException("Failed to get PlayerData from bytes", e);
}

View File

@@ -19,11 +19,13 @@ package net.momirealms.customfishing.storage.method;
import net.momirealms.customfishing.api.CustomFishingPlugin;
import net.momirealms.customfishing.api.data.DataStorageInterface;
import net.momirealms.customfishing.api.data.PlayerData;
import net.momirealms.customfishing.api.data.user.OfflineUser;
import java.time.Instant;
import java.util.Collection;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
public abstract class AbstractStorage implements DataStorageInterface {
@@ -48,13 +50,18 @@ public abstract class AbstractStorage implements DataStorageInterface {
}
@Override
public void savePlayersData(Collection<? extends OfflineUser> users, boolean unlock) {
public void updateManyPlayersData(Collection<? extends OfflineUser> users, boolean unlock) {
for (OfflineUser user : users) {
this.savePlayerData(user.getUUID(), user.getPlayerData(), unlock);
this.updatePlayerData(user.getUUID(), user.getPlayerData(), unlock);
}
}
public void lockPlayerData(UUID uuid, boolean lock) {
}
@Override
public CompletableFuture<Boolean> updateOrInsertPlayerData(UUID uuid, PlayerData playerData, boolean unlock) {
return updatePlayerData(uuid, playerData, unlock);
}
}

View File

@@ -130,7 +130,7 @@ public class MongoDBImpl extends AbstractStorage {
}
@Override
public CompletableFuture<Boolean> savePlayerData(UUID uuid, PlayerData playerData, boolean unlock) {
public CompletableFuture<Boolean> updatePlayerData(UUID uuid, PlayerData playerData, boolean unlock) {
var future = new CompletableFuture<Boolean>();
plugin.getScheduler().runTaskAsync(() -> {
MongoCollection<Document> collection = database.getCollection(getCollectionName("data"));
@@ -150,7 +150,7 @@ public class MongoDBImpl extends AbstractStorage {
}
@Override
public void savePlayersData(Collection<? extends OfflineUser> users, boolean unlock) {
public void updateManyPlayersData(Collection<? extends OfflineUser> users, boolean unlock) {
MongoCollection<Document> collection = database.getCollection(getCollectionName("data"));
try {
int lock = unlock ? 0 : getCurrentSeconds();

View File

@@ -251,7 +251,7 @@ public class RedisManager extends AbstractStorage {
}
@Override
public CompletableFuture<Boolean> savePlayerData(UUID uuid, PlayerData playerData, boolean ignore) {
public CompletableFuture<Boolean> updatePlayerData(UUID uuid, PlayerData playerData, boolean ignore) {
var future = new CompletableFuture<Boolean>();
plugin.getScheduler().runTaskAsync(() -> {
try (Jedis jedis = jedisPool.getResource()) {

View File

@@ -116,7 +116,7 @@ public abstract class AbstractSQLDatabase extends AbstractStorage {
}
@Override
public CompletableFuture<Boolean> savePlayerData(UUID uuid, PlayerData playerData, boolean unlock) {
public CompletableFuture<Boolean> updatePlayerData(UUID uuid, PlayerData playerData, boolean unlock) {
var future = new CompletableFuture<Boolean>();
plugin.getScheduler().runTaskAsync(() -> {
try (
@@ -138,7 +138,7 @@ public abstract class AbstractSQLDatabase extends AbstractStorage {
}
@Override
public void savePlayersData(Collection<? extends OfflineUser> users, boolean unlock) {
public void updateManyPlayersData(Collection<? extends OfflineUser> users, boolean unlock) {
String sql = String.format(SqlConstants.SQL_UPDATE_BY_UUID, getTableName("data"));
try (Connection connection = getConnection()) {
connection.setAutoCommit(false);
@@ -188,6 +188,29 @@ public abstract class AbstractSQLDatabase extends AbstractStorage {
}
}
@Override
public CompletableFuture<Boolean> updateOrInsertPlayerData(UUID uuid, PlayerData playerData, boolean unlock) {
var future = new CompletableFuture<Boolean>();
plugin.getScheduler().runTaskAsync(() -> {
try (
Connection connection = getConnection();
PreparedStatement statement = connection.prepareStatement(String.format(SqlConstants.SQL_SELECT_BY_UUID, getTableName("data")))
) {
statement.setString(1, uuid.toString());
ResultSet rs = statement.executeQuery();
if (rs.next()) {
updatePlayerData(uuid, playerData, unlock).thenRun(() -> future.complete(true));
} else {
insertPlayerData(uuid, playerData, !unlock);
future.complete(true);
}
} catch (SQLException e) {
LogUtils.warn("Failed to get " + uuid + "'s data.", e);
}
});
return future;
}
@Override
public Set<UUID> getUniqueUsers(boolean legacy) {
Set<UUID> uuids = new HashSet<>();

View File

@@ -112,7 +112,7 @@ public class SQLiteImpl extends AbstractSQLDatabase {
}
@Override
public CompletableFuture<Boolean> savePlayerData(UUID uuid, PlayerData playerData, boolean unlock) {
public CompletableFuture<Boolean> updatePlayerData(UUID uuid, PlayerData playerData, boolean unlock) {
var future = new CompletableFuture<Boolean>();
plugin.getScheduler().runTaskAsync(() -> {
try (
@@ -133,7 +133,7 @@ public class SQLiteImpl extends AbstractSQLDatabase {
}
@Override
public void savePlayersData(Collection<? extends OfflineUser> users, boolean unlock) {
public void updateManyPlayersData(Collection<? extends OfflineUser> users, boolean unlock) {
String sql = String.format(SqlConstants.SQL_UPDATE_BY_UUID, getTableName("data"));
try (Connection connection = getConnection()) {
connection.setAutoCommit(false);

View File

@@ -64,7 +64,7 @@ public class JsonImpl extends AbstractStorage {
}
@Override
public CompletableFuture<Boolean> savePlayerData(UUID uuid, PlayerData playerData, boolean ignore) {
public CompletableFuture<Boolean> updatePlayerData(UUID uuid, PlayerData playerData, boolean ignore) {
this.saveToJsonFile(playerData, getPlayerDataFile(uuid));
return CompletableFuture.completedFuture(true);
}

View File

@@ -70,7 +70,7 @@ public class YAMLImpl extends AbstractStorage implements LegacyDataStorageInterf
}
@Override
public CompletableFuture<Boolean> savePlayerData(UUID uuid, PlayerData playerData, boolean ignore) {
public CompletableFuture<Boolean> updatePlayerData(UUID uuid, PlayerData playerData, boolean ignore) {
YamlConfiguration data = new YamlConfiguration();
data.set("name", playerData.getName());
data.set("bag", playerData.getBagData().serialized);

View File

@@ -116,6 +116,16 @@ rubbish:
disable-game: true
instant-game: false
prevent-grabbing: false
rainbow_fish:
material: cod
nick: <Rainbow>Rainbow Fish</Rainbow>
display:
name: <Rainbow>Rainbow Fish</Rainbow>
lore:
- <gray>Bringing a good mood for the day
custom-model-data: 50100
price:
base: 100
# Enchantments
sharpness_book:
tag: false

View File

@@ -80,6 +80,7 @@ global-group:
- minecraft:warm_ocean
list:
- vanilla:+30
- rainbow_fish:+5
- stick:+15
- gold_fish:+15
- gold_fish_silver_star:+3