Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/main/java/city/norain/slimefun4/utils/TaskUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@

@UtilityClass
public class TaskUtil {
@SneakyThrows
public void runSyncMethod(Runnable runnable) {
if (Bukkit.isPrimaryThread()) {
runnable.run();
} else {
Slimefun.runSync(runnable);
}
}

@SneakyThrows
public <T> T runSyncMethod(Callable<T> callable) {
if (Bukkit.isPrimaryThread()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ protected ADataController(DataType dataType) {
logger = Logger.getLogger("Slimefun-Data-Controller");
}

/**
* 初始化 {@link ADataController}
*/
@OverridingMethodsMustInvokeSuper
public void init(IDataSourceAdapter<?> dataAdapter, int maxReadThread, int maxWriteThread) {
this.dataAdapter = dataAdapter;
Expand All @@ -49,6 +52,9 @@ public void init(IDataSourceAdapter<?> dataAdapter, int maxReadThread, int maxWr
callbackExecutor = Executors.newCachedThreadPool(threadFactory);
}

/**
* 正常关闭 {@link ADataController}
*/
@OverridingMethodsMustInvokeSuper
public void shutdown() {
if (destroyed) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +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 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;
Expand Down Expand Up @@ -218,7 +219,7 @@ public void setDelayedSavingEnable(boolean isEnable) {
}

/**
* 在指定位置新建方块
* 在指定位置创建一个新的 Slimefun 方块数据
*
* @param l Slimefun 方块位置 {@link Location}
* @param sfId Slimefun 物品 ID {@link SlimefunItem#getId()}
Expand All @@ -240,6 +241,36 @@ public SlimefunBlockData createBlock(Location l, String sfId) {
return re;
}

/**
* 创建一个新的 Slimefun 通用数据
* 提供一个可供读写的 KV 存储 Map
*
* @param sfId Slimefun 物品 ID {@link SlimefunItem#getId()}
* @return 通用数据, {@link SlimefunUniversalData}
*/
@Nonnull
public SlimefunUniversalData createUniversalData(String sfId) {
checkDestroy();

var uuid = UUID.randomUUID();
var uniData = new SlimefunUniversalData(uuid, sfId);

uniData.setIsDataLoaded(true);

loadedUniversalData.put(uuid, uniData);

Slimefun.getDatabaseManager().getBlockDataController().saveUniversalData(uniData);

return uniData;
}

/**
* 在指定位置创建一个新的 Slimefun 通用方块数据
*
* @param l Slimefun 方块位置 {@link Location}
* @param sfId Slimefun 物品 ID {@link SlimefunItem#getId()}
* @return 通用方块数据, {@link SlimefunUniversalBlockData}
*/
@Nonnull
@ParametersAreNonnullByDefault
public SlimefunUniversalBlockData createUniversalBlock(Location l, String sfId) {
Expand All @@ -264,7 +295,7 @@ public SlimefunUniversalBlockData createUniversalBlock(Location l, String sfId)
Slimefun.getTickerTask().enableTicker(l, uuid);
}

Slimefun.getDatabaseManager().getBlockDataController().saveUniversalData(uuid, sfId, uniData.getTraits());
Slimefun.getDatabaseManager().getBlockDataController().saveUniversalData(uniData);

return uniData;
}
Expand All @@ -286,48 +317,45 @@ void saveNewBlock(Location l, String sfId) {
}

/**
* Save certain universal data
* 立即计划保存一个通用数据
*
* @param uuid universal data uuid
* @param sfId the item universal data represents
* @param universalData 欲写入数据库保存的通用数据
*/
void saveUniversalData(UUID uuid, String sfId, Set<UniversalDataTrait> traits) {
void saveUniversalData(SlimefunUniversalData universalData) {
var uuid = universalData.getKey();
var sfId = universalData.getSfId();
var traitsStr = String.join(
",", universalData.getTraits().stream().map(Enum::name).toList());

var key = new RecordKey(DataScope.UNIVERSAL_RECORD);

var data = new RecordSet();
data.put(FieldKey.UNIVERSAL_UUID, uuid.toString());
data.put(FieldKey.UNIVERSAL_UUID, uuid);
data.put(FieldKey.SLIMEFUN_ID, sfId);
data.put(
FieldKey.UNIVERSAL_TRAITS,
String.join(",", traits.stream().map(Enum::name).toList()));
data.put(FieldKey.UNIVERSAL_TRAITS, traitsStr);

var scopeKey = new UUIDKey(DataScope.NONE, uuid);
removeDelayedBlockDataUpdates(scopeKey); // Shouldn't have.. But for safe..
scheduleWriteTask(scopeKey, key, data, true);
}

/**
* Remove slimefun block data at specific location
* 移除指定位置上的 Slimefun 数据
*
* @param l slimefun block location {@link Location}
* @param l 位置 {@link Location}
*/
public void removeBlock(Location l) {
checkDestroy();

var removed = getChunkDataCache(l.getChunk(), true).removeBlockData(l);

if (removed == null) {
getUniversalBlockDataFromCache(l)
.ifPresentOrElse(data -> removeUniversalBlockData(data.getUUID(), l), () -> {
if (Bukkit.isPrimaryThread()) {
Slimefun.getBlockDataService()
.getUniversalDataUUID(l.getBlock())
.ifPresent(uuid -> removeUniversalBlockData(uuid, l));
} else {
Slimefun.runSync(() -> Slimefun.getBlockDataService()
.ifPresentOrElse(
data -> removeUniversalBlockData(data.getUUID()),
() -> TaskUtil.runSyncMethod(() -> Slimefun.getBlockDataService()
.getUniversalDataUUID(l.getBlock())
.ifPresent(uuid -> removeUniversalBlockData(uuid, l)));
}
});
.ifPresent(this::removeUniversalBlockData)));

return;
}
Expand All @@ -346,6 +374,11 @@ public void removeBlock(Location l) {
}
}

/**
* 移除指定位置上的 Slimefun 方块数据
*
* @param l 位置 {@link Location}
*/
public void removeBlockData(Location l) {
checkDestroy();

Expand All @@ -365,7 +398,12 @@ public void removeBlockData(Location l) {
}
}

public void removeUniversalBlockData(UUID uuid, Location lastPresent) {
/**
* 移除指定 UUID 对应的 Slimefun 通用方块数据
*
* @param uuid 通用方块数据识别符
*/
public void removeUniversalBlockData(UUID uuid) {
checkDestroy();

var toRemove = loadedUniversalData.get(uuid);
Expand All @@ -381,7 +419,7 @@ public void removeUniversalBlockData(UUID uuid, Location lastPresent) {
toRemove.setPendingRemove(true);

if (toRemove instanceof SlimefunUniversalBlockData ubd) {
toRemove.setPendingRemove(true);
ubd.setPendingRemove(true);
removeUniversalBlockDirectly(uuid);

var menu = ubd.getMenu();
Expand All @@ -390,7 +428,7 @@ public void removeUniversalBlockData(UUID uuid, Location lastPresent) {
}

if (Slimefun.getRegistry().getTickerBlocks().contains(toRemove.getSfId())) {
Slimefun.getTickerTask().disableTicker(lastPresent);
Slimefun.getTickerTask().disableTicker(ubd.getLastPresent().toLocation());
}
}

Expand Down Expand Up @@ -545,7 +583,7 @@ public Optional<SlimefunUniversalBlockData> getUniversalBlockDataFromCache(@Nonn

for (SlimefunUniversalData uniData : loadedUniversalData.values()) {
if (uniData instanceof SlimefunUniversalBlockData ubd) {
if (!ubd.isDataLoaded() || !ubd.hasTrait(UniversalDataTrait.BLOCK) || ubd.getLastPresent() == null) {
if (!ubd.isDataLoaded() || ubd.getLastPresent() == null) {
continue;
}

Expand Down Expand Up @@ -715,7 +753,9 @@ public void loadUniversalRecord() {
uniKey.addField(FieldKey.SLIMEFUN_ID);
uniKey.addField(FieldKey.UNIVERSAL_TRAITS);

getData(uniKey).forEach(data -> {
var uniRecord = getData(uniKey);

uniRecord.forEach(data -> {
var sfId = data.get(FieldKey.SLIMEFUN_ID);
var sfItem = SlimefunItem.getById(sfId);

Expand Down Expand Up @@ -853,6 +893,7 @@ public void loadUniversalData(SlimefunUniversalData uniData) {
return;
}

// 构建 通用数据 kv 存储 查询条件
var key = new RecordKey(DataScope.UNIVERSAL_DATA);
key.addCondition(FieldKey.UNIVERSAL_UUID, uniData.getKey());
key.addField(FieldKey.DATA_KEY);
Expand All @@ -875,45 +916,46 @@ public void loadUniversalData(SlimefunUniversalData uniData) {

uniData.setIsDataLoaded(true);

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);
if (uniData instanceof SlimefunUniversalBlockData ubd) {
if (uniData.hasTrait(UniversalDataTrait.BLOCK)) {
// 初始化 上次出现位置
var lStr = ubd.getData(UniversalDataTrait.BLOCK.getReservedKey());
ubd.setLastPresent(LocationUtils.toLocation(lStr));

var inv = new ItemStack[54];
var sfItem = SlimefunItem.getById(ubd.getSfId());

getData(menuKey)
.forEach(recordSet -> inv[recordSet.getInt(FieldKey.INVENTORY_SLOT)] =
recordSet.getItemStack(FieldKey.INVENTORY_ITEM));
if (sfItem != null && sfItem.isTicking()) {
Slimefun.getTickerTask()
.enableTicker(ubd.getLastPresent().toLocation(), uniData.getUUID());
}
}

var location = uniData.hasTrait(UniversalDataTrait.BLOCK)
? ((SlimefunUniversalBlockData) uniData)
.getLastPresent()
.toLocation()
: null;
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);

uniData.setMenu(new UniversalMenu(menuPreset, uniData.getUUID(), location, inv));
var inv = new ItemStack[54];

var content = uniData.getMenuContents();
if (content != null) {
invSnapshots.put(uniData.getKey(), InvStorageUtils.getInvSnapshot(content));
}
}
}
getData(menuKey)
.forEach(recordSet -> inv[recordSet.getInt(FieldKey.INVENTORY_SLOT)] =
recordSet.getItemStack(FieldKey.INVENTORY_ITEM));

var location = uniData.hasTrait(UniversalDataTrait.BLOCK)
? ubd.getLastPresent().toLocation()
: null;

if (uniData.hasTrait(UniversalDataTrait.BLOCK)) {
var sfItem = SlimefunItem.getById(uniData.getSfId());
uniData.setMenu(new UniversalMenu(menuPreset, uniData.getUUID(), location, inv));

if (sfItem != null && sfItem.isTicking()) {
Slimefun.getTickerTask()
.enableTicker(
((SlimefunUniversalBlockData) uniData)
.getLastPresent()
.toLocation(),
uniData.getUUID());
var content = uniData.getMenuContents();
if (content != null) {
invSnapshots.put(uniData.getKey(), InvStorageUtils.getInvSnapshot(content));
}
}
}
}
} finally {
Expand Down Expand Up @@ -1298,14 +1340,14 @@ private SlimefunChunkData getChunkDataCache(Chunk chunk, boolean createOnNotExis
})
: loadedChunk.get(LocationUtils.getChunkKey(chunk));
}
// fix issue 935: auto chunk load when using loc.getChunk(),if chunk data is already loaded into cache, we generate
// keyString using location,instead of loc.getChunk

// Fixed #935: use cache chunk data to generate chunkKey by location first.
private SlimefunChunkData getChunkDataCache(Location loc, boolean createOnNotExists) {
var re = loadedChunk.get(LocationUtils.getChunkKey(loc));
if (re != null) {
return re;
} else {
// jump to origin getChunkDataCache and call getChunk() to trigger chunkLoad
// If cache not exists, use `getChunkDataCache` and trigger chunk loading
return getChunkDataCache(loc.getChunk(), createOnNotExists);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,10 +200,14 @@ public void onPlayerPlace(BlockPlaceEvent e) {
"rotation", p.getFacing().getOppositeFace().toString());
universalData.setData("paused", String.valueOf(true));

if (b.getBlockData() instanceof Rotatable rotatable) {
rotatable.setRotation(p.getFacing());
b.setBlockData(rotatable);
}
b.setBlockData(Material.PLAYER_HEAD.createBlockData(data -> {
if (data instanceof Rotatable rotatable) {
rotatable.setRotation(p.getFacing());
}
}));

Slimefun.getBlockDataService().updateUniversalDataUUID(b, universalData.getKey());
PlayerHead.setSkin(b, PlayerSkin.fromBase64(texture), true);
}
};
}
Expand Down
Loading