diff --git a/modules/AcShop/pom.xml b/modules/AcShop/pom.xml
index b929296..1b86d4e 100644
--- a/modules/AcShop/pom.xml
+++ b/modules/AcShop/pom.xml
@@ -86,6 +86,18 @@
jar
1.0.0
+
+ junit
+ junit
+ 4.13.2
+ test
+
+
+ org.mockito
+ mockito-core
+ 5.11.0
+ test
+
diff --git a/modules/AcShop/src/main/java/com/mcatk/acshop/FileOperation.java b/modules/AcShop/src/main/java/com/mcatk/acshop/FileOperation.java
index 5bc8638..8bb3931 100644
--- a/modules/AcShop/src/main/java/com/mcatk/acshop/FileOperation.java
+++ b/modules/AcShop/src/main/java/com/mcatk/acshop/FileOperation.java
@@ -11,23 +11,35 @@
public class FileOperation {
+ private static final Gson gson = new GsonBuilder().setPrettyPrinting().create();
private final File shopsFile;
- private final Gson gson;
public FileOperation() {
- shopsFile = new File(AcShop.getPlugin().getDataFolder(), "shopsFile.json");
- gson = new GsonBuilder().setPrettyPrinting().create();
+ this(AcShop.getPlugin().getDataFolder());
+ }
+
+ public FileOperation(File dataFolder) {
+ this.shopsFile = new File(dataFolder, "shopsFile.json");
}
public void saveShops(Shops shops) {
- try {
- FileWriter writer = new FileWriter(shopsFile);
+ try (FileWriter writer = new FileWriter(shopsFile)) {
gson.toJson(shops, writer);
- writer.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
+
+ public void saveShopsAsync(Shops shops) {
+ final String json = gson.toJson(shops);
+ org.bukkit.Bukkit.getScheduler().runTaskAsynchronously(AcShop.getPlugin(), () -> {
+ try (FileWriter writer = new FileWriter(shopsFile)) {
+ writer.write(json);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ });
+ }
public Shops loadShops() {
Shops shops = null;
diff --git a/modules/AcShop/src/main/java/com/mcatk/acshop/command/AdminCommand.java b/modules/AcShop/src/main/java/com/mcatk/acshop/command/AdminCommand.java
index ee8c7e1..1b1d97d 100644
--- a/modules/AcShop/src/main/java/com/mcatk/acshop/command/AdminCommand.java
+++ b/modules/AcShop/src/main/java/com/mcatk/acshop/command/AdminCommand.java
@@ -47,7 +47,7 @@ public boolean onCommand(CommandSender sender, Command command, String label, St
break;
default:
}
- new FileOperation().saveShops(AcShop.getShops());
+ new FileOperation().saveShopsAsync(AcShop.getShops());
return true;
}
diff --git a/modules/AcShop/src/test/java/com/mcatk/acshop/BenchmarkTest.java b/modules/AcShop/src/test/java/com/mcatk/acshop/BenchmarkTest.java
new file mode 100644
index 0000000..3390eab
--- /dev/null
+++ b/modules/AcShop/src/test/java/com/mcatk/acshop/BenchmarkTest.java
@@ -0,0 +1,70 @@
+package com.mcatk.acshop;
+
+import com.mcatk.acshop.commodity.Item;
+import com.mcatk.acshop.commodity.ItemType;
+import com.mcatk.acshop.shop.Shop;
+import com.mcatk.acshop.shop.Shops;
+import org.bukkit.Bukkit;
+import org.bukkit.scheduler.BukkitScheduler;
+import org.bukkit.plugin.Plugin;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class BenchmarkTest {
+
+ @Test
+ public void benchmarkSaveShops() throws IOException {
+ // Setup data
+ Shops shops = new Shops();
+ for (int i = 0; i < 50; i++) {
+ Shop shop = new Shop("Shop" + i);
+ for (int j = 0; j < 50; j++) {
+ shop.getItemHashMap().put("Item" + j, new Item(ItemType.ITEM_STACK, "Item" + j, 100, "sort", "id"));
+ }
+ shops.getShopsHashMap().put(shop.getId(), shop);
+ }
+
+ // Mock AcShop
+ File tempDir = Files.createTempDirectory("acshop_test").toFile();
+ tempDir.deleteOnExit();
+
+ AcShop mockPlugin = mock(AcShop.class);
+ when(mockPlugin.getDataFolder()).thenReturn(tempDir);
+
+ BukkitScheduler mockScheduler = mock(BukkitScheduler.class);
+ when(mockScheduler.runTaskAsynchronously(any(Plugin.class), any(Runnable.class))).thenReturn(null);
+
+ try (MockedStatic mockedAcShop = Mockito.mockStatic(AcShop.class);
+ MockedStatic mockedBukkit = Mockito.mockStatic(Bukkit.class)) {
+
+ mockedAcShop.when(AcShop::getPlugin).thenReturn(mockPlugin);
+ mockedBukkit.when(Bukkit::getScheduler).thenReturn(mockScheduler);
+
+ // Warmup
+ new FileOperation().saveShopsAsync(shops);
+
+ // Benchmark
+ long startTime = System.nanoTime();
+ int iterations = 20;
+ for (int i = 0; i < iterations; i++) {
+ new FileOperation().saveShopsAsync(shops);
+ }
+ long endTime = System.nanoTime();
+ double avgTime = (endTime - startTime) / (double) iterations / 1_000_000.0;
+ System.out.println("Average save time (Async offload): " + avgTime + " ms");
+ }
+ }
+}