getData(RecordKey key) {
diff --git a/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/controller/ASlimefunDataContainer.java b/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/controller/ASlimefunDataContainer.java
index 2faba0b9de..2bfc75638d 100644
--- a/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/controller/ASlimefunDataContainer.java
+++ b/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/controller/ASlimefunDataContainer.java
@@ -3,6 +3,15 @@
import lombok.Getter;
import lombok.Setter;
+/**
+ * Slimefun 数据容器的抽象类.
+ *
+ * 该类用于存储 Slimefun 特有的数据容器, 包括 Slimefun ID 和是否待删除的标志.
+ *
+ * @author NoRainCity
+ *
+ * @see ADataController
+ */
public abstract class ASlimefunDataContainer extends ADataContainer {
@Getter
private final String sfId;
diff --git a/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/controller/BlockDataController.java b/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/controller/BlockDataController.java
index 06c21f91c8..2f3169d10b 100644
--- a/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/controller/BlockDataController.java
+++ b/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/controller/BlockDataController.java
@@ -3,7 +3,7 @@
import city.norain.slimefun4.api.menu.UniversalMenu;
import city.norain.slimefun4.api.menu.UniversalMenuPreset;
import city.norain.slimefun4.utils.InventoryUtil;
-import city.norain.slimefun4.utils.TaskUtil;
+import city.norain.slimefun4.utils.StringUtil;
import com.xzavier0722.mc.plugin.slimefun4.storage.adapter.IDataSourceAdapter;
import com.xzavier0722.mc.plugin.slimefun4.storage.callback.IAsyncReadCallback;
import com.xzavier0722.mc.plugin.slimefun4.storage.common.DataScope;
@@ -23,7 +23,6 @@
import io.github.bakedlibs.dough.collections.Pair;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
-import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -100,7 +99,7 @@ public class BlockDataController extends ADataController {
BlockDataController() {
super(DataType.BLOCK_STORAGE);
- delayedWriteTasks = new HashMap<>();
+ delayedWriteTasks = new ConcurrentHashMap<>();
loadedChunk = new ConcurrentHashMap<>();
loadedUniversalData = new ConcurrentHashMap<>();
invSnapshots = new ConcurrentHashMap<>();
@@ -195,17 +194,7 @@ public void initDelayedSaving(Plugin p, int delayedSecond, int forceSavePeriod)
.runTaskTimerAsynchronously(
p,
new DelayedSavingLooperTask(
- forceSavePeriod,
- () -> {
- synchronized (delayedWriteTasks) {
- return new HashMap<>(delayedWriteTasks);
- }
- },
- key -> {
- synchronized (delayedWriteTasks) {
- delayedWriteTasks.remove(key);
- }
- }),
+ forceSavePeriod, () -> new HashMap<>(delayedWriteTasks), delayedWriteTasks::remove),
20,
20);
}
@@ -243,6 +232,7 @@ public SlimefunBlockData createBlock(Location l, String sfId) {
/**
* 创建一个新的 Slimefun 通用数据
+ *
* 提供一个可供读写的 KV 存储 Map
*
* @param sfId Slimefun 物品 ID {@link SlimefunItem#getId()}
@@ -250,9 +240,25 @@ public SlimefunBlockData createBlock(Location l, String sfId) {
*/
@Nonnull
public SlimefunUniversalData createUniversalData(String sfId) {
+ return createUniversalData(UUID.randomUUID(), sfId);
+ }
+
+ /**
+ * 创建一个新的 Slimefun 通用数据
+ * 提供一个可供读写的 KV 存储 Map
+ *
+ * @param uuid 通用数据的识别 UUID
+ * @param sfId Slimefun 物品 ID {@link SlimefunItem#getId()}
+ * @return 通用数据, {@link SlimefunUniversalData}
+ */
+ @Nonnull
+ public SlimefunUniversalData createUniversalData(UUID uuid, String sfId) {
checkDestroy();
- var uuid = UUID.randomUUID();
+ if (getUniversalDataFromCache(uuid) != null || getUniversalData(uuid) != null) {
+ throw new IllegalArgumentException("A universal data with this UUID already exists: " + uuid);
+ }
+
var uniData = new SlimefunUniversalData(uuid, sfId);
uniData.setIsDataLoaded(true);
@@ -282,7 +288,6 @@ public SlimefunUniversalBlockData createUniversalBlock(Location l, String sfId)
uniData.setIsDataLoaded(true);
uniData.initTraits();
- uniData.initLastPresent();
loadedUniversalData.put(uuid, uniData);
@@ -301,6 +306,8 @@ public SlimefunUniversalBlockData createUniversalBlock(Location l, String sfId)
Slimefun.getBlockDataService().updateUniversalDataUUID(l.getBlock(), uniData.getKey());
}
+ uniData.initLastPresent();
+
return uniData;
}
@@ -328,8 +335,7 @@ void saveNewBlock(Location l, String sfId) {
void saveUniversalData(SlimefunUniversalData universalData) {
var uuid = universalData.getKey();
var sfId = universalData.getSfId();
- var traitsStr = String.join(
- ",", universalData.getTraits().stream().map(Enum::name).toList());
+ var traitsStr = StringUtil.getTraitsStr(universalData.getTraits());
var key = new RecordKey(DataScope.UNIVERSAL_RECORD);
@@ -354,12 +360,7 @@ public void removeBlock(Location l) {
var removed = getChunkDataCache(l.getChunk(), true).removeBlockData(l);
if (removed == null) {
- getUniversalBlockDataFromCache(l)
- .ifPresentOrElse(
- data -> removeUniversalBlockData(data.getUUID()),
- () -> TaskUtil.runSyncMethod(() -> Slimefun.getBlockDataService()
- .getUniversalDataUUID(l.getBlock())
- .ifPresent(this::removeUniversalBlockData)));
+ removeUniversalBlockData(l);
return;
}
@@ -368,14 +369,14 @@ public void removeBlock(Location l) {
return;
}
+ if (Slimefun.getRegistry().getTickerBlocks().contains(removed.getSfId())) {
+ Slimefun.getTickerTask().disableTicker(l);
+ }
+
var menu = removed.getBlockMenu();
if (menu != null) {
menu.lock();
}
-
- if (Slimefun.getRegistry().getTickerBlocks().contains(removed.getSfId())) {
- Slimefun.getTickerTask().disableTicker(l);
- }
}
/**
@@ -402,6 +403,23 @@ public void removeBlockData(Location l) {
}
}
+ /**
+ * 移除指定位置对应的可能存在的 Slimefun 通用方块数据
+ *
+ * @param l {@link Location} 位置
+ */
+ public void removeUniversalBlockData(Location l) {
+ checkDestroy();
+
+ var toRemove = getUniversalBlockDataFromCache(l);
+
+ if (toRemove.isEmpty()) {
+ return;
+ }
+
+ removeUniversalBlockData(toRemove.get().getUUID());
+ }
+
/**
* 移除指定 UUID 对应的 Slimefun 通用方块数据
*
@@ -424,13 +442,14 @@ public void removeUniversalBlockData(UUID uuid) {
if (toRemove instanceof SlimefunUniversalBlockData ubd) {
ubd.setPendingRemove(true);
- removeUniversalBlockDirectly(uuid);
var menu = ubd.getMenu();
if (menu != null) {
menu.lock();
}
+ removeUniversalBlockDirectly(uuid);
+
if (Slimefun.getRegistry().getTickerBlocks().contains(toRemove.getSfId())) {
Slimefun.getTickerTask().disableTicker(ubd.getLastPresent().toLocation());
}
@@ -520,16 +539,15 @@ public SlimefunBlockData getBlockDataFromCache(Location l) {
}
/**
- * Get slimefun universal data
- *
- * @param uuid universal data uuid {@link UUID}
+ * 从数据库中获取 {@link SlimefunUniversalData}
*/
- @Nullable public SlimefunUniversalBlockData getUniversalBlockData(@Nonnull UUID uuid) {
+ @Nullable public SlimefunUniversalData getUniversalData(@Nonnull UUID uuid) {
checkDestroy();
var key = new RecordKey(DataScope.UNIVERSAL_RECORD);
key.addCondition(FieldKey.UNIVERSAL_UUID, uuid.toString());
key.addField(FieldKey.SLIMEFUN_ID);
+ key.addField(FieldKey.UNIVERSAL_TRAITS);
var result = getData(key);
@@ -537,17 +555,30 @@ public SlimefunBlockData getBlockDataFromCache(Location l) {
return null;
}
- var newData = new SlimefunUniversalBlockData(uuid, result.get(0).get(FieldKey.SLIMEFUN_ID));
+ var traits = StringUtil.getTraitsFromStr(result.get(0).get(FieldKey.UNIVERSAL_TRAITS));
- Arrays.stream(result.get(0).get(FieldKey.UNIVERSAL_TRAITS).split(",")).forEach(tname -> {
- for (UniversalDataTrait trait : UniversalDataTrait.values()) {
- if (trait.name().equals(tname)) {
- newData.getTraits().add(trait);
- }
- }
- });
+ if (traits.contains(UniversalDataTrait.BLOCK)) {
+ var ubd = new SlimefunUniversalBlockData(uuid, result.get(0).get(FieldKey.SLIMEFUN_ID));
+ traits.forEach(ubd::addTrait);
+ return ubd;
+ } else {
+ return new SlimefunUniversalData(uuid, result.get(0).get(FieldKey.SLIMEFUN_ID), traits);
+ }
+ }
+
+ /**
+ * Get slimefun universal data
+ *
+ * @param uuid universal data uuid {@link UUID}
+ */
+ @Nullable public SlimefunUniversalBlockData getUniversalBlockData(@Nonnull UUID uuid) {
+ SlimefunUniversalData universalData = getUniversalData(uuid);
- return newData;
+ if (universalData instanceof SlimefunUniversalBlockData ubd) {
+ return ubd;
+ } else {
+ return null;
+ }
}
/**
@@ -560,15 +591,25 @@ public void getUniversalBlockData(@Nonnull UUID uuid, IAsyncReadCallback invokeCallback(callback, getUniversalBlockData(uuid)));
}
+ /**
+ * 从缓存中获取 {@link SlimefunUniversalData}
+ *
+ * @param uuid 通用数据 UUID
+ * @return {@link SlimefunUniversalData}
+ */
+ @Nullable public SlimefunUniversalData getUniversalDataFromCache(@Nonnull UUID uuid) {
+ checkDestroy();
+
+ return loadedUniversalData.get(uuid);
+ }
+
/**
* Get slimefun universal data from cache
*
* @param uuid universal data uuid {@link UUID}
*/
@Nullable public SlimefunUniversalBlockData getUniversalBlockDataFromCache(@Nonnull UUID uuid) {
- checkDestroy();
-
- var cache = loadedUniversalData.get(uuid);
+ var cache = getUniversalDataFromCache(uuid);
if (cache instanceof SlimefunUniversalBlockData ubd) {
return ubd;
@@ -776,7 +817,10 @@ public void loadUniversalRecord() {
for (String traitStr : traitsData.split(",")) {
try {
traits.add(UniversalDataTrait.valueOf(traitStr.toUpperCase()));
- } catch (IllegalArgumentException ignored) {
+ } catch (IllegalArgumentException e) {
+ logger.log(Level.WARNING, "Invalid trait '{0}' for universal data {1}.", new Object[] {
+ traitStr, uuid
+ });
}
}
}
@@ -916,10 +960,10 @@ public void loadUniversalData(SlimefunUniversalData uniData) {
DataUtils.blockDataDebase64(recordSet.get(FieldKey.DATA_VALUE)),
false));
- loadedUniversalData.putIfAbsent(uniData.getUUID(), uniData);
-
uniData.setIsDataLoaded(true);
+ loadedUniversalData.putIfAbsent(uniData.getUUID(), uniData);
+
if (uniData instanceof SlimefunUniversalBlockData ubd) {
if (ubd.hasTrait(UniversalDataTrait.BLOCK)) {
// 初始化 上次出现位置
@@ -931,40 +975,47 @@ public void loadUniversalData(SlimefunUniversalData uniData) {
var sfItem = SlimefunItem.getById(ubd.getSfId());
- if (sfItem != null && sfItem.isTicking()) {
+ if (sfItem != null && sfItem.isTicking() && ubd.getLastPresent() != null) {
Slimefun.getTickerTask()
.enableTicker(ubd.getLastPresent().toLocation(), ubd.getUUID());
}
}
+ }
- if (ubd.hasTrait(UniversalDataTrait.INVENTORY)) {
- // 加载菜单
- var menuPreset = UniversalMenuPreset.getPreset(ubd.getSfId());
- if (menuPreset != null) {
- var menuKey = new RecordKey(DataScope.UNIVERSAL_INVENTORY);
- menuKey.addCondition(FieldKey.UNIVERSAL_UUID, ubd.getKey());
- menuKey.addField(FieldKey.INVENTORY_SLOT);
- menuKey.addField(FieldKey.INVENTORY_ITEM);
-
- var inv = new ItemStack[54];
+ if (uniData.hasTrait(UniversalDataTrait.INVENTORY)) {
+ // 加载菜单
+ var menuPreset = UniversalMenuPreset.getPreset(uniData.getSfId());
+ if (menuPreset != null) {
+ var menuKey = new RecordKey(DataScope.UNIVERSAL_INVENTORY);
+ menuKey.addCondition(FieldKey.UNIVERSAL_UUID, uniData.getKey());
+ menuKey.addField(FieldKey.INVENTORY_SLOT);
+ menuKey.addField(FieldKey.INVENTORY_ITEM);
- getData(menuKey)
- .forEach(recordSet -> inv[recordSet.getInt(FieldKey.INVENTORY_SLOT)] =
- recordSet.getItemStack(FieldKey.INVENTORY_ITEM));
+ var inv = new ItemStack[54];
- var location = ubd.hasTrait(UniversalDataTrait.BLOCK)
- ? ubd.getLastPresent().toLocation()
- : null;
+ getData(menuKey)
+ .forEach(recordSet -> inv[recordSet.getInt(FieldKey.INVENTORY_SLOT)] =
+ recordSet.getItemStack(FieldKey.INVENTORY_ITEM));
- ubd.setMenu(new UniversalMenu(menuPreset, ubd.getUUID(), location, inv));
+ Location location = null;
- var content = ubd.getMenuContents();
- if (content != null) {
- invSnapshots.put(ubd.getKey(), InvStorageUtils.getInvSnapshot(content));
+ if (uniData instanceof SlimefunUniversalBlockData ubd && ubd.hasTrait(UniversalDataTrait.BLOCK)) {
+ if (ubd.getLastPresent() != null) {
+ location = ubd.getLastPresent().toLocation();
}
}
+
+ uniData.setMenu(new UniversalMenu(menuPreset, uniData.getUUID(), location, inv));
+
+ var content = uniData.getMenuContents();
+
+ if (content != null) {
+ invSnapshots.put(uniData.getKey(), InvStorageUtils.getInvSnapshot(content));
+ }
}
}
+ } catch (Exception e) {
+ logger.log(Level.SEVERE, "Failed to load universal data: " + uniData.getKey(), e);
} finally {
lock.unlock(key);
}
@@ -1091,26 +1142,26 @@ public void removeAllDataInWorldAsync(World world, Runnable onFinishedCallback)
}
public void saveUniversalInventory(@Nonnull SlimefunUniversalData universalData) {
- var menu = universalData.getMenu();
var universalID = universalData.getUUID();
- var newInv = universalData.getMenuContents();
+ var currentInv = universalData.getMenuContents();
List> lastSave;
- if (newInv == null) {
+
+ if (currentInv == null) {
lastSave = invSnapshots.remove(universalID.toString());
if (lastSave == null) {
return;
}
} else {
- lastSave = invSnapshots.put(universalID.toString(), InvStorageUtils.getInvSnapshot(newInv));
+ lastSave = invSnapshots.put(universalID.toString(), InvStorageUtils.getInvSnapshot(currentInv));
}
- var changed = InvStorageUtils.getChangedSlots(lastSave, newInv);
+ var changed = InvStorageUtils.getChangedSlots(lastSave, currentInv);
if (changed.isEmpty()) {
return;
}
- changed.forEach(slot -> scheduleDelayedUniversalInvUpdate(universalID, menu, slot));
+ changed.forEach(slot -> scheduleDelayedUniversalInvUpdate(universalData, slot));
}
public Set getAllLoadedChunkData(World world) {
@@ -1177,27 +1228,27 @@ private void scheduleBlockInvUpdate(ScopeKey scopeKey, RecordKey reqKey, String
/**
* Save universal inventory by async way
*
- * @param uuid Universal Inventory UUID
- * @param menu Universal menu
+ * @param ubd {@link SlimefunUniversalBlockData}
* @param slot updated item slot
*/
- private void scheduleDelayedUniversalInvUpdate(UUID uuid, UniversalMenu menu, int slot) {
- var scopeKey = new UUIDKey(DataScope.NONE, uuid);
+ private void scheduleDelayedUniversalInvUpdate(SlimefunUniversalData ubd, int slot) {
+ var scopeKey = new UUIDKey(DataScope.NONE, ubd.getKey());
var reqKey = new RecordKey(DataScope.UNIVERSAL_INVENTORY);
- reqKey.addCondition(FieldKey.UNIVERSAL_UUID, uuid.toString());
+ reqKey.addCondition(FieldKey.UNIVERSAL_UUID, ubd.getKey());
reqKey.addCondition(FieldKey.INVENTORY_SLOT, slot + "");
reqKey.addField(FieldKey.INVENTORY_ITEM);
if (enableDelayedSaving) {
scheduleDelayedUpdateTask(
new LinkedKey(scopeKey, reqKey),
- () -> scheduleUniversalInvUpdate(scopeKey, reqKey, uuid, menu.getContents(), slot));
+ () -> scheduleUniversalInvUpdate(scopeKey, reqKey, ubd.getKey(), ubd.getMenuContents(), slot));
} else {
- scheduleUniversalInvUpdate(scopeKey, reqKey, uuid, menu.getContents(), slot);
+ scheduleUniversalInvUpdate(scopeKey, reqKey, ubd.getKey(), ubd.getMenuContents(), slot);
}
}
- private void scheduleUniversalInvUpdate(ScopeKey scopeKey, RecordKey reqKey, UUID uuid, ItemStack[] inv, int slot) {
+ private void scheduleUniversalInvUpdate(
+ ScopeKey scopeKey, RecordKey reqKey, String uuid, ItemStack[] inv, int slot) {
var item = inv != null && slot < inv.length ? inv[slot] : null;
if (item == null) {
@@ -1205,7 +1256,7 @@ private void scheduleUniversalInvUpdate(ScopeKey scopeKey, RecordKey reqKey, UUI
} else {
try {
var data = new RecordSet();
- data.put(FieldKey.UNIVERSAL_UUID, uuid.toString());
+ data.put(FieldKey.UNIVERSAL_UUID, uuid);
data.put(FieldKey.INVENTORY_SLOT, slot + "");
data.put(FieldKey.INVENTORY_ITEM, item);
scheduleWriteTask(scopeKey, reqKey, data, true);
@@ -1245,6 +1296,7 @@ void scheduleDelayedUniversalDataUpdate(SlimefunUniversalData universalData, Str
var reqKey = new RecordKey(DataScope.UNIVERSAL_DATA);
reqKey.addCondition(FieldKey.UNIVERSAL_UUID, universalData.getKey());
reqKey.addCondition(FieldKey.DATA_KEY, key);
+
if (enableDelayedSaving) {
scheduleDelayedUpdateTask(
new LinkedKey(scopeKey, reqKey),
@@ -1307,6 +1359,7 @@ void scheduleDelayedChunkDataUpdate(SlimefunChunkData chunkData, String key) {
private void scheduleDelayedUpdateTask(LinkedKey key, Runnable run) {
synchronized (delayedWriteTasks) {
var task = delayedWriteTasks.get(key);
+
if (task != null && !task.isExecuted()) {
task.setRunAfter(delayedSecond, TimeUnit.SECONDS);
return;
diff --git a/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/controller/LinkedKey.java b/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/controller/LinkedKey.java
index a6ebd2a893..850efe4114 100644
--- a/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/controller/LinkedKey.java
+++ b/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/controller/LinkedKey.java
@@ -1,10 +1,15 @@
package com.xzavier0722.mc.plugin.slimefun4.storage.controller;
import com.xzavier0722.mc.plugin.slimefun4.storage.common.ScopeKey;
+import lombok.Getter;
+import lombok.Setter;
public class LinkedKey extends ScopeKey {
private final ScopeKey self;
private final int hash;
+
+ @Getter
+ @Setter
private ScopeKey parent;
public LinkedKey(ScopeKey self) {
@@ -18,14 +23,6 @@ public LinkedKey(ScopeKey parent, ScopeKey self) {
this.parent = parent;
}
- public void setParent(ScopeKey parent) {
- this.parent = parent;
- }
-
- public ScopeKey getParent() {
- return parent;
- }
-
@Override
public int hashCode() {
return hash;
@@ -35,4 +32,9 @@ public int hashCode() {
public boolean equals(Object obj) {
return self.equals(obj instanceof LinkedKey linked ? linked.self : obj);
}
+
+ @Override
+ public String toString() {
+ return getKeyStr() + " -> " + self.toString();
+ }
}
diff --git a/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/controller/ProfileDataController.java b/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/controller/ProfileDataController.java
index a373e9661d..42987adde2 100644
--- a/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/controller/ProfileDataController.java
+++ b/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/controller/ProfileDataController.java
@@ -1,5 +1,6 @@
package com.xzavier0722.mc.plugin.slimefun4.storage.controller;
+import city.norain.slimefun4.utils.PlayerUtil;
import com.xzavier0722.mc.plugin.slimefun4.storage.callback.IAsyncReadCallback;
import com.xzavier0722.mc.plugin.slimefun4.storage.common.DataScope;
import com.xzavier0722.mc.plugin.slimefun4.storage.common.DataType;
@@ -355,7 +356,7 @@ public void run() {
return;
}
- if (Bukkit.getOfflinePlayer(UUID.fromString(pUuid)).isConnected()) {
+ if (PlayerUtil.isConnected(Bukkit.getOfflinePlayer(UUID.fromString(pUuid)))) {
return;
}
diff --git a/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/controller/SlimefunBlockData.java b/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/controller/SlimefunBlockData.java
index 29138215a1..dcd6588b9c 100644
--- a/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/controller/SlimefunBlockData.java
+++ b/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/controller/SlimefunBlockData.java
@@ -11,6 +11,16 @@
import org.bukkit.Location;
import org.bukkit.inventory.ItemStack;
+/**
+ * {@link SlimefunBlockData} 是 Slimefun 中机器等方块类物品的数据存储容器。
+ *
+ * 它包含了方块对应的键值容器、位置信息和菜单,
+ * 是 Slimefun 中常用的方块数据存储类。
+ *
+ * @author Xzavier0722
+ *
+ * @see ASlimefunDataContainer
+ */
@ToString
public class SlimefunBlockData extends ASlimefunDataContainer {
private final Location location;
diff --git a/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/controller/SlimefunChunkData.java b/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/controller/SlimefunChunkData.java
index 174b150a8f..3be1aa4b2a 100644
--- a/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/controller/SlimefunChunkData.java
+++ b/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/controller/SlimefunChunkData.java
@@ -15,6 +15,9 @@
import org.bukkit.Chunk;
import org.bukkit.Location;
+/**
+ * {@link SlimefunChunkData} 是 Slimefun 中用于存储区块内所有方块数据的容器类。
+ */
public class SlimefunChunkData extends ADataContainer {
private static final SlimefunBlockData INVALID_BLOCK_DATA = new SlimefunBlockData(
new Location(Bukkit.getWorlds().get(0), Double.MAX_VALUE, Double.MAX_VALUE, Double.MAX_VALUE),
diff --git a/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/controller/SlimefunUniversalData.java b/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/controller/SlimefunUniversalData.java
index 677f032dd6..110a45fa7c 100644
--- a/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/controller/SlimefunUniversalData.java
+++ b/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/controller/SlimefunUniversalData.java
@@ -12,8 +12,10 @@
import javax.annotation.ParametersAreNonnullByDefault;
import lombok.Getter;
import lombok.Setter;
+import lombok.extern.slf4j.Slf4j;
import org.bukkit.inventory.ItemStack;
+@Slf4j
@Getter
public class SlimefunUniversalData extends ASlimefunDataContainer {
@Setter
@@ -29,6 +31,12 @@ public class SlimefunUniversalData extends ASlimefunDataContainer {
super(uuid.toString(), sfId);
}
+ @ParametersAreNonnullByDefault
+ SlimefunUniversalData(UUID uuid, String sfId, Set traits) {
+ super(uuid.toString(), sfId);
+ this.traits.addAll(traits);
+ }
+
@ParametersAreNonnullByDefault
public void setData(String key, String val) {
checkData();
@@ -48,6 +56,7 @@ protected void setTraitData(UniversalDataTrait trait, String val) {
if (!trait.getReservedKey().isEmpty()) {
setCacheInternal(trait.getReservedKey(), val, true);
+
Slimefun.getDatabaseManager()
.getBlockDataController()
.scheduleDelayedUniversalDataUpdate(this, trait.getReservedKey());
diff --git a/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/package-info.java b/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/package-info.java
new file mode 100644
index 0000000000..b19d8bd06d
--- /dev/null
+++ b/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Slimefun 的数据库存储系统实现与 API
+ */
+package com.xzavier0722.mc.plugin.slimefun4.storage;
diff --git a/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/task/DatabaseThreadFactory.java b/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/task/DatabaseThreadFactory.java
index 9c9ec07931..f9b3f67e70 100644
--- a/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/task/DatabaseThreadFactory.java
+++ b/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/task/DatabaseThreadFactory.java
@@ -20,7 +20,7 @@ public DatabaseThreadFactory(String prefix) {
public Thread newThread(@Nonnull Runnable r) {
Thread t = new Thread(r, prefix + threadCount.getAndIncrement());
t.setUncaughtExceptionHandler((et, e) ->
- Slimefun.logger().log(Level.SEVERE, "A error occurred in database thread " + t.getName(), e));
+ Slimefun.logger().log(Level.SEVERE, "A error occurred in database thread " + et.getName(), e));
return t;
}
diff --git a/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/task/DelayedSavingLooperTask.java b/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/task/DelayedSavingLooperTask.java
index 822aecc9b8..9deeacd1bf 100644
--- a/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/task/DelayedSavingLooperTask.java
+++ b/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/task/DelayedSavingLooperTask.java
@@ -1,21 +1,25 @@
package com.xzavier0722.mc.plugin.slimefun4.storage.task;
-import com.xzavier0722.mc.plugin.slimefun4.storage.common.ScopeKey;
+import com.xzavier0722.mc.plugin.slimefun4.storage.controller.LinkedKey;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Supplier;
+import lombok.extern.slf4j.Slf4j;
+@Slf4j
public class DelayedSavingLooperTask implements Runnable {
private final long forceSavePeriodInMillis;
- private final Supplier