getDataKeys() {
- checkData();
- return data.keySet();
- }
-
- @Nullable public String getData(String key) {
- checkData();
- return getCacheInternal(key);
- }
-
- public abstract void setData(String key, String val);
}
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 99cb7305a6..3a772ba4d7 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
@@ -1,5 +1,8 @@
package com.xzavier0722.mc.plugin.slimefun4.storage.controller;
+import city.norain.slimefun4.api.menu.UniversalMenu;
+import city.norain.slimefun4.api.menu.UniversalMenuPreset;
+import city.norain.slimefun4.utils.InventoryUtil;
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;
@@ -8,6 +11,8 @@
import com.xzavier0722.mc.plugin.slimefun4.storage.common.RecordKey;
import com.xzavier0722.mc.plugin.slimefun4.storage.common.RecordSet;
import com.xzavier0722.mc.plugin.slimefun4.storage.common.ScopeKey;
+import com.xzavier0722.mc.plugin.slimefun4.storage.controller.attributes.UniversalBlock;
+import com.xzavier0722.mc.plugin.slimefun4.storage.controller.attributes.UniversalDataTrait;
import com.xzavier0722.mc.plugin.slimefun4.storage.event.SlimefunChunkDataLoadEvent;
import com.xzavier0722.mc.plugin.slimefun4.storage.task.DelayedSavingLooperTask;
import com.xzavier0722.mc.plugin.slimefun4.storage.task.DelayedTask;
@@ -18,11 +23,7 @@
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
@@ -38,25 +39,70 @@
import org.bukkit.plugin.Plugin;
import org.bukkit.scheduler.BukkitTask;
+/**
+ * 方块数据控制器
+ *
+ * 用于管理区块中的 Slimefun 方块数据
+ *
+ * {@link SlimefunBlockData}
+ * {@link SlimefunUniversalData}
+ *
+ * @author Xzavier0722
+ * @author NoRainCity
+ */
public class BlockDataController extends ADataController {
private final Map delayedWriteTasks;
+ /**
+ * 区块数据缓存
+ */
private final Map loadedChunk;
+ /**
+ * 通用数据缓存
+ */
+ private final Map loadedUniversalData;
+ /**
+ * 方块物品栏快照
+ */
private final Map>> invSnapshots;
+ /**
+ * 全局控制器加载数据锁
+ *
+ * {@link ScopedLock}
+ */
private final ScopedLock lock;
+ /**
+ * 延时加载模式标志
+ */
private boolean enableDelayedSaving = false;
+
private int delayedSecond = 0;
private BukkitTask looperTask;
+ /**
+ * 区块数据加载模式
+ * {@link ChunkDataLoadMode}
+ */
private ChunkDataLoadMode chunkDataLoadMode;
+ /**
+ * 初始化加载中标志
+ */
private boolean initLoading = false;
BlockDataController() {
super(DataType.BLOCK_STORAGE);
delayedWriteTasks = new HashMap<>();
loadedChunk = new ConcurrentHashMap<>();
+ loadedUniversalData = new ConcurrentHashMap<>();
invSnapshots = new ConcurrentHashMap<>();
lock = new ScopedLock();
}
+ /**
+ * 初始化数据控制器
+ *
+ * @param dataAdapter 使用的 {@link IDataSourceAdapter}
+ * @param maxReadThread 最大数据库读线程数
+ * @param maxWriteThread 最大数据库写线程数
+ */
@Override
public void init(IDataSourceAdapter> dataAdapter, int maxReadThread, int maxWriteThread) {
super.init(dataAdapter, maxReadThread, maxWriteThread);
@@ -64,13 +110,29 @@ public void init(IDataSourceAdapter> dataAdapter, int maxReadThread, int maxWr
initLoadData();
}
+ /**
+ * 初始化加载数据
+ */
private void initLoadData() {
switch (chunkDataLoadMode) {
case LOAD_WITH_CHUNK -> loadLoadedChunks();
case LOAD_ON_STARTUP -> loadLoadedWorlds();
}
+
+ Bukkit.getScheduler()
+ .runTaskLater(
+ Slimefun.instance(),
+ () -> {
+ initLoading = true;
+ loadUniversalRecord();
+ initLoading = false;
+ },
+ 1);
}
+ /**
+ * 加载所有服务器已加载的世界中的数据
+ */
private void loadLoadedWorlds() {
Bukkit.getScheduler()
.runTaskLater(
@@ -85,6 +147,9 @@ private void loadLoadedWorlds() {
1);
}
+ /**
+ * 加载所有服务器已加载的世界区块中的数据
+ */
private void loadLoadedChunks() {
Bukkit.getScheduler()
.runTaskLater(
@@ -101,10 +166,17 @@ private void loadLoadedChunks() {
1);
}
+ /**
+ * 初始化延时加载任务
+ *
+ * @param p 插件实例
+ * @param delayedSecond 首次执行延时
+ * @param forceSavePeriod 强制保存周期
+ */
public void initDelayedSaving(Plugin p, int delayedSecond, int forceSavePeriod) {
checkDestroy();
if (delayedSecond < 1 || forceSavePeriod < 1) {
- throw new IllegalArgumentException("Second must be greater than 0!");
+ throw new IllegalArgumentException("save period second must be greater than 0!");
}
enableDelayedSaving = true;
this.delayedSecond = delayedSecond;
@@ -136,24 +208,53 @@ public void setDelayedSavingEnable(boolean isEnable) {
}
/**
- * Creates a new slimefun block data at specific location
+ * 在指定位置新建方块
*
- * @param l slimefun block location {@link Location}
- * @param sfId slimefun block id {@link SlimefunItem#getId()}
- * @return {@link SlimefunBlockData}
+ * @param l Slimefun 方块位置 {@link Location}
+ * @param sfId Slimefun 物品 ID {@link SlimefunItem#getId()}
+ * @return 方块数据, 由于 {@link SlimefunItem} 的不同会返回两种数据中的一种
+ * {@link SlimefunBlockData}
+ * {@link SlimefunUniversalData}
*/
-
- public SlimefunBlockData createBlock(Location l, String sfId) {
+ public ASlimefunDataContainer createBlock(Location l, String sfId) {
checkDestroy();
- var re = getChunkDataCache(l.getChunk(), true).createBlockData(l, sfId);
- if (Slimefun.getRegistry().getTickerBlocks().contains(sfId)) {
- if (sfId.equalsIgnoreCase("CARGO_MANAGER")) {
- Slimefun.instance().getCargoTickerTask().enableTicker(l);
- } else {
+ var sfItem = SlimefunItem.getById(sfId);
+
+ if (sfItem instanceof UniversalBlock) {
+ SlimefunUniversalData re = createUniversalBlockData(l, sfId);
+ if (Slimefun.getRegistry().getTickerBlocks().contains(sfId)) {
+ Slimefun.getTickerTask().enableTicker(l, re.getUUID());
+ }
+ return re;
+ } else {
+ var re = getChunkDataCache(l.getChunk(), true).createBlockData(l, sfId);
+ if (Slimefun.getRegistry().getTickerBlocks().contains(sfId)) {
Slimefun.getTickerTask().enableTicker(l);
}
+ return re;
}
- return re;
+ }
+
+ public SlimefunUniversalBlockData createUniversalBlockData(Location l, String sfId) {
+ checkDestroy();
+
+ var uuid = UUID.randomUUID();
+ var uniData = new SlimefunUniversalBlockData(uuid, sfId, l);
+
+ uniData.setIsDataLoaded(true);
+
+ loadedUniversalData.put(uuid, uniData);
+
+ var preset = UniversalMenuPreset.getPreset(sfId);
+ if (preset != null) {
+ uniData.setMenu(new UniversalMenu(preset, uuid, l));
+ }
+
+ Slimefun.getDatabaseManager()
+ .getBlockDataController()
+ .saveUniversalData(uuid, sfId, Set.of(UniversalDataTrait.BLOCK, UniversalDataTrait.INVENTORY));
+
+ return uniData;
}
void saveNewBlock(Location l, String sfId) {
@@ -172,6 +273,27 @@ void saveNewBlock(Location l, String sfId) {
scheduleWriteTask(scopeKey, key, data, true);
}
+ /**
+ * Save certain universal data
+ *
+ * @param uuid universal data uuid
+ * @param sfId the item universal data represents
+ */
+ void saveUniversalData(UUID uuid, String sfId, Set traits) {
+ var key = new RecordKey(DataScope.UNIVERSAL_RECORD);
+
+ var data = new RecordSet();
+ data.put(FieldKey.UNIVERSAL_UUID, uuid.toString());
+ data.put(FieldKey.SLIMEFUN_ID, sfId);
+ data.put(
+ FieldKey.UNIVERSAL_TRAITS,
+ String.join(",", traits.stream().map(Enum::name).toList()));
+
+ 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
*
@@ -182,6 +304,15 @@ public void removeBlock(Location l) {
SlimefunBlockData 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));
+ }
+ });
+
return;
}
@@ -203,6 +334,55 @@ public void removeBlock(Location l) {
}
}
+ public void removeBlockData(Location l) {
+ checkDestroy();
+
+ var removed = getChunkDataCache(l.getChunk(), true).removeBlockData(l);
+
+ if (removed == null || !removed.isDataLoaded()) {
+ return;
+ }
+
+ var menu = removed.getBlockMenu();
+ if (menu != null) {
+ InventoryUtil.closeInventory(menu.toInventory());
+ }
+
+ if (Slimefun.getRegistry().getTickerBlocks().contains(removed.getSfId())) {
+ Slimefun.getTickerTask().disableTicker(l);
+ }
+ }
+
+ public void removeUniversalBlockData(UUID uuid, Location lastPresent) {
+ checkDestroy();
+
+ var toRemove = loadedUniversalData.get(uuid);
+
+ if (toRemove == null) {
+ return;
+ }
+
+ if (!toRemove.isDataLoaded()) {
+ return;
+ }
+
+ if (toRemove instanceof SlimefunUniversalBlockData ubd) {
+ toRemove.setPendingRemove(true);
+ removeUniversalBlockDirectly(uuid);
+
+ var menu = ubd.getMenu();
+ if (menu != null) {
+ menu.lock();
+ }
+
+ if (Slimefun.getRegistry().getTickerBlocks().contains(toRemove.getSfId())) {
+ Slimefun.getTickerTask().disableTicker(lastPresent);
+ }
+
+ loadedUniversalData.remove(uuid);
+ }
+ }
+
void removeBlockDirectly(Location l) {
checkDestroy();
var scopeKey = new LocationKey(DataScope.NONE, l);
@@ -213,6 +393,16 @@ void removeBlockDirectly(Location l) {
scheduleDeleteTask(scopeKey, key, true);
}
+ void removeUniversalBlockDirectly(UUID uuid) {
+ checkDestroy();
+ var scopeKey = new UUIDKey(DataScope.NONE, uuid);
+ removeDelayedBlockDataUpdates(scopeKey);
+
+ var key = new RecordKey(DataScope.UNIVERSAL_RECORD);
+ key.addCondition(FieldKey.UNIVERSAL_UUID, uuid.toString());
+ scheduleDeleteTask(scopeKey, key, true);
+ }
+
/**
* Get slimefun block data at specific location
*
@@ -252,7 +442,7 @@ public SlimefunBlockData getBlockData(Location l) {
}
/**
- * Get slimefun block data at specific location async
+ * Get slimefun block data at specific location asynchronous
*
* @param l slimefun block location {@link Location}
* @param callback operation when block data fetched {@link IAsyncReadCallback}
@@ -271,6 +461,79 @@ public SlimefunBlockData getBlockDataFromCache(Location l) {
return getBlockDataFromCache(LocationUtils.getChunkKey(l.getChunk()), LocationUtils.getLocKey(l));
}
+ /**
+ * Get slimefun universal data
+ *
+ * @param uuid universal data uuid {@link UUID}
+ */
+ @Nullable
+ public SlimefunUniversalBlockData getUniversalBlockData(UUID uuid) {
+ checkDestroy();
+
+ var key = new RecordKey(DataScope.UNIVERSAL_RECORD);
+ key.addCondition(FieldKey.UNIVERSAL_UUID, uuid.toString());
+ key.addField(FieldKey.SLIMEFUN_ID);
+
+ var result = getData(key);
+
+ if (result.isEmpty()) {
+ return null;
+ }
+
+ var newData = new SlimefunUniversalBlockData(uuid, result.get(0).get(FieldKey.SLIMEFUN_ID));
+
+ 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);
+ }
+ }
+ });
+
+ return newData;
+ }
+
+ /**
+ * Get slimefun universal data asynchronous
+ *
+ * @param uuid universal data uuid {@link UUID}
+ * @param callback operation when block data fetched {@link IAsyncReadCallback}
+ */
+ public void getUniversalBlockData(UUID uuid, IAsyncReadCallback callback) {
+ scheduleReadTask(() -> invokeCallback(callback, getUniversalBlockData(uuid)));
+ }
+
+ /**
+ * Get slimefun universal data from cache
+ *
+ * @param uuid universal data uuid {@link UUID}
+ */
+ @Nullable
+ public SlimefunUniversalBlockData getUniversalBlockDataFromCache(UUID uuid) {
+ checkDestroy();
+
+ var cache = loadedUniversalData.get(uuid);
+
+ return cache == null
+ ? getUniversalBlockData(uuid)
+ : (cache instanceof SlimefunUniversalBlockData ubd ? ubd : null);
+ }
+
+ /**
+ * Get slimefun universal data from cache by location
+ *
+ * @param l Slimefun block location {@link Location}
+ */
+ public Optional getUniversalBlockDataFromCache(Location l) {
+ checkDestroy();
+
+ return loadedUniversalData.values().stream()
+ .filter(uniData -> uniData instanceof SlimefunUniversalBlockData ubd
+ && ubd.getLastPresent().toLocation().equals(l))
+ .map(data -> (SlimefunUniversalBlockData) data)
+ .findFirst();
+ }
+
/**
* Move block data to specific location
*
@@ -378,6 +641,8 @@ public void loadChunk(Chunk chunk, boolean isNewChunk) {
loadChunkData(chunkData);
+ // 按区块加载方块数据
+
var key = new RecordKey(DataScope.BLOCK_RECORD);
key.addField(FieldKey.LOCATION);
key.addField(FieldKey.SLIMEFUN_ID);
@@ -399,6 +664,7 @@ public void loadChunk(Chunk chunk, boolean isNewChunk) {
scheduleReadTask(() -> loadBlockData(blockData));
}
});
+
Bukkit.getPluginManager().callEvent(new SlimefunChunkDataLoadEvent(chunkData));
}
@@ -422,6 +688,43 @@ public void loadWorld(World world) {
Level.INFO, "世界 {0} 数据加载完成, 耗时 {1}ms", new Object[]{worldName, (System.currentTimeMillis() - start)});
}
+ public void loadUniversalRecord() {
+ var uniKey = new RecordKey(DataScope.UNIVERSAL_RECORD);
+ uniKey.addField(FieldKey.UNIVERSAL_UUID);
+ uniKey.addField(FieldKey.SLIMEFUN_ID);
+ uniKey.addField(FieldKey.UNIVERSAL_TRAITS);
+
+ getData(uniKey).forEach(data -> {
+ var sfId = data.get(FieldKey.SLIMEFUN_ID);
+ var sfItem = SlimefunItem.getById(sfId);
+
+ if (sfItem == null) {
+ return;
+ }
+
+ var uuid = data.getUUID(FieldKey.UNIVERSAL_UUID);
+ var traitsData = data.get(FieldKey.UNIVERSAL_TRAITS);
+ var traits = new HashSet();
+
+ if (traitsData != null && !traitsData.isBlank()) {
+ for (String traitStr : traitsData.split(",")) {
+ try {
+ traits.add(UniversalDataTrait.valueOf(traitStr.toUpperCase()));
+ } catch (IllegalArgumentException ignored) {
+ }
+ }
+ }
+
+ var uniData = traits.contains(UniversalDataTrait.BLOCK)
+ ? new SlimefunUniversalBlockData(uuid, sfId)
+ : new SlimefunUniversalData(uuid, sfId);
+
+ traits.forEach(t -> uniData.getTraits().add(t));
+
+ scheduleReadTask(() -> loadUniversalData(uniData));
+ });
+ }
+
private void loadChunkData(SlimefunChunkData chunkData) {
if (chunkData.isDataLoaded()) {
return;
@@ -462,33 +765,45 @@ public void loadBlockData(SlimefunBlockData blockData) {
return;
}
- getData(key)
- .forEach(recordSet -> blockData.setCacheInternal(
- recordSet.get(FieldKey.DATA_KEY),
- DataUtils.blockDataDebase64(recordSet.get(FieldKey.DATA_VALUE)),
- false));
- blockData.setIsDataLoaded(true);
-
- var menuPreset = BlockMenuPreset.getPreset(blockData.getSfId());
- if (menuPreset != null) {
- var menuKey = new RecordKey(DataScope.BLOCK_INVENTORY);
- menuKey.addCondition(FieldKey.LOCATION, blockData.getKey());
- menuKey.addField(FieldKey.INVENTORY_SLOT);
- menuKey.addField(FieldKey.INVENTORY_ITEM);
-
- var inv = new ItemStack[54];
- getData(menuKey)
- .forEach(record -> inv[record.getInt(FieldKey.INVENTORY_SLOT)] =
- record.getItemStack(FieldKey.INVENTORY_ITEM));
- blockData.setBlockMenu(new BlockMenu(menuPreset, blockData.getLocation(), inv));
-
- var content = blockData.getMenuContents();
- if (content != null) {
- invSnapshots.put(blockData.getKey(), InvStorageUtils.getInvSnapshot(content));
+ var sfItem = SlimefunItem.getById(blockData.getSfId());
+ var universal = sfItem instanceof UniversalBlock;
+
+ var kvData = getData(key);
+
+ var menuKey = new RecordKey(DataScope.BLOCK_INVENTORY);
+ menuKey.addCondition(FieldKey.LOCATION, blockData.getKey());
+ menuKey.addField(FieldKey.INVENTORY_SLOT);
+ menuKey.addField(FieldKey.INVENTORY_ITEM);
+
+ var invData = getData(menuKey);
+
+ if (universal) {
+ migrateUniversalData(blockData.getLocation(), blockData.getSfId(), kvData, invData);
+ } else {
+ kvData.forEach(recordSet -> blockData.setCacheInternal(
+ recordSet.get(FieldKey.DATA_KEY),
+ DataUtils.blockDataDebase64(recordSet.get(FieldKey.DATA_VALUE)),
+ false));
+
+ blockData.setIsDataLoaded(true);
+
+ var menuPreset = BlockMenuPreset.getPreset(blockData.getSfId());
+
+ if (menuPreset != null) {
+ var inv = new ItemStack[54];
+
+ invData.forEach(record ->
+ inv[record.getInt(FieldKey.INVENTORY_SLOT)] = record.getItemStack(FieldKey.INVENTORY_ITEM));
+
+ blockData.setBlockMenu(new BlockMenu(menuPreset, blockData.getLocation(), inv));
+
+ var content = blockData.getMenuContents();
+ if (content != null) {
+ invSnapshots.put(blockData.getKey(), InvStorageUtils.getInvSnapshot(content));
+ }
}
}
- SlimefunItem sfItem = SlimefunItem.getById(blockData.getSfId());
if (sfItem != null && sfItem.isTicking()) {
sfItem.getTickerTask().enableTicker(blockData.getLocation());
}
@@ -510,6 +825,87 @@ public void loadBlockDataAsync(
invokeCallback(callback, blockDataList);
}
+ public void loadUniversalData(SlimefunUniversalData uniData) {
+ if (uniData.isDataLoaded()) {
+ return;
+ }
+
+ var key = new RecordKey(DataScope.UNIVERSAL_DATA);
+ key.addCondition(FieldKey.UNIVERSAL_UUID, uniData.getKey());
+ key.addField(FieldKey.DATA_KEY);
+ key.addField(FieldKey.DATA_VALUE);
+
+ lock.lock(key);
+
+ try {
+ if (uniData.isDataLoaded()) {
+ return;
+ }
+
+ getData(key)
+ .forEach(recordSet -> uniData.setCacheInternal(
+ recordSet.get(FieldKey.DATA_KEY),
+ DataUtils.blockDataDebase64(recordSet.get(FieldKey.DATA_VALUE)),
+ false));
+
+ uniData.setIsDataLoaded(true);
+
+ loadedUniversalData.putIfAbsent(uniData.getUUID(), uniData);
+
+ 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);
+
+ var inv = new ItemStack[54];
+
+ getData(menuKey)
+ .forEach(recordSet -> inv[recordSet.getInt(FieldKey.INVENTORY_SLOT)] =
+ recordSet.getItemStack(FieldKey.INVENTORY_ITEM));
+
+ var location = uniData.hasTrait(UniversalDataTrait.BLOCK)
+ ? ((SlimefunUniversalBlockData) uniData)
+ .getLastPresent()
+ .toLocation()
+ : null;
+
+ uniData.setMenu(new UniversalMenu(menuPreset, uniData.getUUID(), location, inv));
+
+ var content = uniData.getMenuContents();
+ if (content != null) {
+ invSnapshots.put(uniData.getKey(), InvStorageUtils.getInvSnapshot(content));
+ }
+ }
+ }
+
+ if (uniData.hasTrait(UniversalDataTrait.BLOCK)) {
+ SlimefunItem sfItem = SlimefunItem.getById(uniData.getSfId());
+
+ if (sfItem != null && sfItem.isTicking()) {
+ Slimefun.getTickerTask()
+ .enableTicker(
+ ((SlimefunUniversalBlockData) uniData)
+ .getLastPresent()
+ .toLocation(),
+ uniData.getUUID());
+ }
+ }
+ } finally {
+ lock.unlock(key);
+ }
+ }
+
+ public void loadUniversalDataAsync(
+ SlimefunUniversalData uniData, IAsyncReadCallback callback) {
+ scheduleReadTask(() -> {
+ loadUniversalData(uniData);
+ invokeCallback(callback, uniData);
+ });
+ }
+
public SlimefunChunkData getChunkData(Chunk chunk) {
checkDestroy();
loadChunk(chunk, false);
@@ -535,6 +931,21 @@ public void saveAllBlockInventories() {
}));
}
+ public void saveAllUniversalInventories() {
+ var uniData = new HashSet<>(loadedUniversalData.values());
+ uniData.forEach(data -> {
+ if (data.isPendingRemove() || !data.isDataLoaded()) {
+ return;
+ }
+ var menu = data.getMenu();
+ if (menu == null || !menu.isDirty()) {
+ return;
+ }
+
+ saveUniversalInventory(data);
+ });
+ }
+
public void saveBlockInventory(SlimefunBlockData blockData) {
var newInv = blockData.getMenuContents();
List> lastSave;
@@ -606,6 +1017,29 @@ public void removeAllDataInWorldAsync(World world, Runnable onFinishedCallback)
});
}
+ public void saveUniversalInventory(SlimefunUniversalData universalData) {
+ var menu = universalData.getMenu();
+ var universalID = universalData.getUUID();
+
+ var newInv = menu.getContents();
+ List> lastSave;
+ if (newInv == null) {
+ lastSave = invSnapshots.remove(universalID.toString());
+ if (lastSave == null) {
+ return;
+ }
+ } else {
+ lastSave = invSnapshots.put(universalID.toString(), InvStorageUtils.getInvSnapshot(newInv));
+ }
+
+ var changed = InvStorageUtils.getChangedSlots(lastSave, newInv);
+ if (changed.isEmpty()) {
+ return;
+ }
+
+ changed.forEach(slot -> scheduleDelayedUniversalInvUpdate(universalID, menu, slot));
+ }
+
public Set getAllLoadedChunkData(World world) {
var prefix = world.getName() + ";";
var re = new HashSet();
@@ -663,9 +1097,47 @@ private void scheduleBlockInvUpdate(ScopeKey scopeKey, RecordKey reqKey, String
}
}
+ /**
+ * Save universal inventory by async way
+ *
+ * @param uuid Universal Inventory UUID
+ * @param menu Universal menu
+ * @param slot updated item slot
+ */
+ private void scheduleDelayedUniversalInvUpdate(UUID uuid, UniversalMenu menu, int slot) {
+ var scopeKey = new UUIDKey(DataScope.NONE, uuid);
+ var reqKey = new RecordKey(DataScope.UNIVERSAL_INVENTORY);
+ reqKey.addCondition(FieldKey.UNIVERSAL_UUID, uuid.toString());
+ 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));
+ } else {
+ scheduleUniversalInvUpdate(scopeKey, reqKey, uuid, menu.getContents(), slot);
+ }
+ }
+
+ private void scheduleUniversalInvUpdate(ScopeKey scopeKey, RecordKey reqKey, UUID uuid, ItemStack[] inv, int slot) {
+ var item = inv != null && slot < inv.length ? inv[slot] : null;
+
+ if (item == null) {
+ scheduleDeleteTask(scopeKey, reqKey, true);
+ } else {
+ var data = new RecordSet();
+ data.put(FieldKey.UNIVERSAL_UUID, uuid.toString());
+ data.put(FieldKey.INVENTORY_SLOT, slot + "");
+ data.put(FieldKey.INVENTORY_ITEM, item);
+ scheduleWriteTask(scopeKey, reqKey, data, true);
+ }
+ }
+
@Override
public void shutdown() {
saveAllBlockInventories();
+ saveAllUniversalInventories();
if (enableDelayedSaving) {
looperTask.cancel();
executeAllDelayedTasks();
@@ -687,6 +1159,21 @@ void scheduleDelayedBlockDataUpdate(SlimefunBlockData blockData, String key) {
}
}
+ void scheduleDelayedUniversalDataUpdate(SlimefunUniversalData universalData, String key) {
+ var scopeKey = new UUIDKey(DataScope.NONE, universalData.getKey());
+ 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),
+ () -> scheduleUniversalDataUpdate(
+ scopeKey, reqKey, universalData.getKey(), key, universalData.getData(key)));
+ } else {
+ scheduleUniversalDataUpdate(scopeKey, reqKey, universalData.getKey(), key, universalData.getData(key));
+ }
+ }
+
private void removeDelayedBlockDataUpdates(ScopeKey scopeKey) {
synchronized (delayedWriteTasks) {
delayedWriteTasks
@@ -708,6 +1195,19 @@ private void scheduleBlockDataUpdate(ScopeKey scopeKey, RecordKey reqKey, String
}
}
+ private void scheduleUniversalDataUpdate(ScopeKey scopeKey, RecordKey reqKey, String uuid, String key, String val) {
+ if (val == null) {
+ scheduleDeleteTask(scopeKey, reqKey, false);
+ } else {
+ var data = new RecordSet();
+ reqKey.addField(FieldKey.DATA_VALUE);
+ data.put(FieldKey.UNIVERSAL_UUID, uuid);
+ data.put(FieldKey.DATA_KEY, key);
+ data.put(FieldKey.DATA_VALUE, DataUtils.blockDataBase64(val));
+ scheduleWriteTask(scopeKey, reqKey, data, true);
+ }
+ }
+
void scheduleDelayedChunkDataUpdate(SlimefunChunkData chunkData, String key) {
var scopeKey = new ChunkKey(DataScope.NONE, chunkData.getChunk());
var reqKey = new RecordKey(DataScope.CHUNK_DATA);
@@ -792,4 +1292,53 @@ private void clearBlockCacheAndTasks(SlimefunBlockData blockData) {
removeDelayedBlockDataUpdates(scopeKey);
abortScopeTask(scopeKey);
}
+
+ /**
+ * 迁移旧 Slimefun 机器数据至通用数据
+ */
+ private void migrateUniversalData(
+ Location l,
+ String sfId,
+ List kvData,
+ List invData) {
+ try {
+ if (l == null || sfId == null) {
+ return;
+ }
+
+ var universalData = createUniversalBlockData(l, sfId);
+
+ Slimefun.runSync(
+ () -> Slimefun.getBlockDataService()
+ .updateUniversalDataUUID(l.getBlock(), String.valueOf(universalData.getUUID())),
+ 10L);
+
+ kvData.forEach(recordSet -> universalData.setData(
+ recordSet.get(FieldKey.DATA_KEY), DataUtils.blockDataDebase64(recordSet.get(FieldKey.DATA_VALUE))));
+
+ UniversalMenuPreset preset = UniversalMenuPreset.getPreset(sfId);
+ if (preset != null) {
+ ItemStack[] inv = new ItemStack[54];
+
+ invData.forEach(record ->
+ inv[record.getInt(FieldKey.INVENTORY_SLOT)] = record.getItemStack(FieldKey.INVENTORY_ITEM));
+
+ universalData.setMenu(new UniversalMenu(preset, universalData.getUUID(), l, inv));
+
+ ItemStack[] content = universalData.getMenuContents();
+ if (content != null) {
+ invSnapshots.put(universalData.getKey(), InvStorageUtils.getInvSnapshot(content));
+ }
+ }
+
+ removeBlockData(l);
+
+ if (Slimefun.getRegistry().getTickerBlocks().contains(universalData.getSfId())) {
+ Slimefun.getTickerTask()
+ .enableTicker(universalData.getLastPresent().toLocation(), universalData.getUUID());
+ }
+ } catch (Exception e) {
+ Slimefun.logger().log(Level.WARNING, "迁移机器人数据时出现错误", e);
+ }
+ }
}
diff --git a/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/controller/ControllerHolder.java b/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/controller/ControllerHolder.java
index 9c69a62a56..ff31481589 100644
--- a/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/controller/ControllerHolder.java
+++ b/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/controller/ControllerHolder.java
@@ -9,8 +9,9 @@ public class ControllerHolder {
private final Map controllers;
public static CT getController(Class clazz, StorageType type) {
+ final ControllerHolder> holder = holders.get(clazz);
//noinspection unchecked
- return ((ControllerHolder) holders.get(clazz)).get(type);
+ return holder == null ? null : ((ControllerHolder) holder).get(type);
}
public static void clearControllers() {
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 dbea4888a5..64877aab68 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
@@ -2,10 +2,10 @@
import com.xzavier0722.mc.plugin.slimefun4.storage.util.LocationUtils;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
+
import javax.annotation.Nullable;
import lombok.Getter;
-import lombok.Setter;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
import org.bukkit.Location;
import org.bukkit.inventory.ItemStack;
@@ -13,23 +13,21 @@
public class SlimefunBlockData extends ASlimefunDataContainer {
@Getter
private final Location location;
- @Getter
- private final String sfId;
+
private volatile BlockMenu menu;
- @Setter
- @Getter
- private volatile boolean pendingRemove = false;
SlimefunBlockData(Location location, String sfId) {
- super(LocationUtils.getLocKey(location));
+ super(LocationUtils.getLocKey(location), sfId);
this.location = location;
- this.sfId = sfId;
}
SlimefunBlockData(Location location, SlimefunBlockData other) {
- super(LocationUtils.getLocKey(location), other);
+ super(LocationUtils.getLocKey(location), other, other.getSfId());
this.location = location;
- this.sfId = other.sfId;
+ }
+
+ public String getSfId() {
+ return super.getSfId();
}
public void setData(String key, String val) {
@@ -48,11 +46,13 @@ void setBlockMenu(BlockMenu blockMenu) {
menu = blockMenu;
}
- @Nullable public BlockMenu getBlockMenu() {
+ @Nullable
+ public BlockMenu getBlockMenu() {
return menu;
}
- @Nullable public ItemStack[] getMenuContents() {
+ @Nullable
+ public ItemStack[] getMenuContents() {
if (menu == null) {
return null;
}
@@ -72,11 +72,11 @@ void setBlockMenu(BlockMenu blockMenu) {
@Override
public String toString() {
return "SlimefunBlockData [sfId="
- + sfId
- + ", location="
- + location
- + ", isPendingRemove="
- + pendingRemove
- + "]";
+ + getSfId()
+ + ", location="
+ + location
+ + ", isPendingRemove="
+ + isPendingRemove()
+ + "]";
}
}
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 d6e2d1bcec..bc70cf5166 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
@@ -16,7 +16,7 @@
import org.bukkit.Chunk;
import org.bukkit.Location;
-public class SlimefunChunkData extends ASlimefunDataContainer {
+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),
"INVALID_BLOCK_DATA_SF_KEY");
@@ -31,15 +31,12 @@ public class SlimefunChunkData extends ASlimefunDataContainer {
}
public SlimefunBlockData createBlockData(Location l, String sfId) {
- var lKey = LocationUtils.getLocKey(l);
- if (getBlockCacheInternal(lKey) != null) {
- throw new IllegalStateException("There already a block in this location: " + lKey);
- }
- var re = new SlimefunBlockData(l, sfId);
+ String lKey = LocationUtils.getLocKey(l);
+ SlimefunBlockData re = new SlimefunBlockData(l, sfId);
re.setIsDataLoaded(true);
sfBlocks.put(lKey, re);
- var preset = BlockMenuPreset.getPreset(sfId);
+ BlockMenuPreset preset = BlockMenuPreset.getPreset(sfId);
if (preset != null) {
re.setBlockMenu(new BlockMenu(preset, l));
}
@@ -56,8 +53,8 @@ public SlimefunBlockData getBlockData(Location l) {
@Nullable
public SlimefunBlockData removeBlockData(Location l) {
- var lKey = LocationUtils.getLocKey(l);
- var re = removeBlockDataCacheInternal(lKey);
+ String lKey = LocationUtils.getLocKey(l);
+ SlimefunBlockData re = removeBlockDataCacheInternal(lKey);
if (re == null) {
if (isDataLoaded()) {
return null;
@@ -77,12 +74,12 @@ void addBlockCacheInternal(SlimefunBlockData data, boolean override) {
}
SlimefunBlockData getBlockCacheInternal(String lKey) {
- var re = sfBlocks.get(lKey);
+ SlimefunBlockData re = sfBlocks.get(lKey);
return re == INVALID_BLOCK_DATA ? null : re;
}
Set getAllCacheInternal() {
- var re = new HashSet<>(sfBlocks.values());
+ Set re = new HashSet<>(sfBlocks.values());
re.removeIf(v -> v == INVALID_BLOCK_DATA);
return re;
}
diff --git a/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/controller/SlimefunUniversalBlockData.java b/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/controller/SlimefunUniversalBlockData.java
new file mode 100644
index 0000000000..6fe51ec6fb
--- /dev/null
+++ b/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/controller/SlimefunUniversalBlockData.java
@@ -0,0 +1,48 @@
+package com.xzavier0722.mc.plugin.slimefun4.storage.controller;
+
+import com.xzavier0722.mc.plugin.slimefun4.storage.controller.attributes.UniversalDataTrait;
+import com.xzavier0722.mc.plugin.slimefun4.storage.util.LocationUtils;
+import io.github.bakedlibs.dough.blocks.BlockPosition;
+
+import java.util.UUID;
+
+import org.bukkit.Location;
+
+public class SlimefunUniversalBlockData extends SlimefunUniversalData {
+ private volatile BlockPosition lastPresent;
+
+ public SlimefunUniversalBlockData(UUID uuid, String sfId) {
+ super(uuid, sfId);
+ }
+
+ public SlimefunUniversalBlockData(UUID uuid, String sfId, BlockPosition present) {
+ super(uuid, sfId);
+
+ this.lastPresent = present;
+ }
+
+ public SlimefunUniversalBlockData(UUID uuid, String sfId, Location present) {
+ this(uuid, sfId, new BlockPosition(present));
+ }
+
+ public void setLastPresent(BlockPosition lastPresent) {
+ setTraitData(UniversalDataTrait.BLOCK, LocationUtils.locationToString(lastPresent.toLocation()));
+ this.lastPresent = lastPresent;
+ }
+
+ public BlockPosition getLastPresent() {
+ if (lastPresent != null) {
+ return lastPresent;
+ }
+
+ var data = getData("location");
+
+ if (data == null) {
+ throw new IllegalArgumentException("UniversalBlockData missing location data");
+ }
+
+ lastPresent = new BlockPosition(LocationUtils.toLocation(data));
+
+ return lastPresent;
+ }
+}
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
new file mode 100644
index 0000000000..a71770d665
--- /dev/null
+++ b/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/controller/SlimefunUniversalData.java
@@ -0,0 +1,91 @@
+package com.xzavier0722.mc.plugin.slimefun4.storage.controller;
+
+import city.norain.slimefun4.api.menu.UniversalMenu;
+import com.xzavier0722.mc.plugin.slimefun4.storage.controller.attributes.UniversalDataTrait;
+import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.UUID;
+import java.util.logging.Level;
+import javax.annotation.Nullable;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.bukkit.inventory.ItemStack;
+
+@Getter
+public class SlimefunUniversalData extends ASlimefunDataContainer {
+ @Setter
+ private volatile UniversalMenu menu;
+
+ @Setter
+ private volatile boolean pendingRemove = false;
+
+ private final Set traits = new HashSet<>();
+
+ SlimefunUniversalData(UUID uuid, String sfId) {
+ super(uuid.toString(), sfId);
+ }
+
+ public void setData(String key, String val) {
+ checkData();
+
+ if (UniversalDataTrait.isReservedKey(key)) {
+ Slimefun.logger().log(Level.WARNING, "警告: 有附属正在尝试修改受保护的方块数据, 已取消更改");
+ return;
+ }
+
+ setCacheInternal(key, val, true);
+ Slimefun.getDatabaseManager().getBlockDataController().scheduleDelayedUniversalDataUpdate(this, key);
+ }
+
+ protected void setTraitData(UniversalDataTrait trait, String val) {
+ checkData();
+
+ if (!trait.getReservedKey().isBlank()) {
+ setCacheInternal(trait.getReservedKey(), val, true);
+ Slimefun.getDatabaseManager()
+ .getBlockDataController()
+ .scheduleDelayedUniversalDataUpdate(this, trait.getReservedKey());
+ }
+ }
+
+ public void removeData(String key) {
+ if (removeCacheInternal(key) != null || !isDataLoaded()) {
+ Slimefun.getDatabaseManager().getBlockDataController().scheduleDelayedUniversalDataUpdate(this, key);
+ }
+ }
+
+ @Nullable
+ public ItemStack[] getMenuContents() {
+ if (menu == null) {
+ return null;
+ }
+ var re = new ItemStack[54];
+ var presetSlots = menu.getPreset().getPresetSlots();
+ var inv = menu.toInventory().getContents();
+ for (var i = 0; i < inv.length; i++) {
+ if (presetSlots.contains(i)) {
+ continue;
+ }
+ re[i] = inv[i];
+ }
+
+ return re;
+ }
+
+ public UUID getUUID() {
+ return UUID.fromString(getKey());
+ }
+
+ public boolean hasTrait(UniversalDataTrait trait) {
+ return traits.contains(trait);
+ }
+
+ @Override
+ public String toString() {
+ return "SlimefunUniversalData [uuid= " + getUUID() + ", sfId=" + getSfId() + ", isPendingRemove="
+ + pendingRemove + "]";
+ }
+}
diff --git a/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/controller/attributes/UniversalBlock.java b/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/controller/attributes/UniversalBlock.java
new file mode 100644
index 0000000000..6b47577c93
--- /dev/null
+++ b/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/controller/attributes/UniversalBlock.java
@@ -0,0 +1,22 @@
+package com.xzavier0722.mc.plugin.slimefun4.storage.controller.attributes;
+
+import com.xzavier0722.mc.plugin.slimefun4.storage.controller.SlimefunUniversalBlockData;
+import com.xzavier0722.mc.plugin.slimefun4.storage.controller.SlimefunUniversalData;
+import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
+
+/**
+ * 这个属性用于声明 {@link SlimefunItem} 使用了 {@link SlimefunUniversalData}
+ *
+ * 当这个 {@link SlimefunItem} 作为机器时, 对应材质需要支持
+ * 使用 PDC 存储容器 (用于识别 UUID).
+ * 否则无法将这个物品/机器绑定到一个通用数据上.
+ *
+ * 查看此处了解支持 PDC 的物品材质:
+ * Paper Doc
+ *
+ * @author NoRainCity
+ * @see SlimefunUniversalData
+ * @see SlimefunUniversalBlockData
+ */
+public interface UniversalBlock {
+}
diff --git a/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/controller/attributes/UniversalDataTrait.java b/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/controller/attributes/UniversalDataTrait.java
new file mode 100644
index 0000000000..4d402a4118
--- /dev/null
+++ b/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/controller/attributes/UniversalDataTrait.java
@@ -0,0 +1,44 @@
+package com.xzavier0722.mc.plugin.slimefun4.storage.controller.attributes;
+
+import city.norain.slimefun4.api.menu.UniversalMenu;
+import com.xzavier0722.mc.plugin.slimefun4.storage.controller.SlimefunUniversalBlockData;
+import com.xzavier0722.mc.plugin.slimefun4.storage.controller.SlimefunUniversalData;
+import lombok.Getter;
+
+/**
+ * 这个枚举类用于声明 {@link SlimefunUniversalData} 的特征.
+ * 一个通用数据可以有单个或多个特征.
+ *
+ * 对于一个通用数据, 它默认拥有作为 k-v 容器的特征.
+ *
+ * @see SlimefunUniversalData
+ * @see SlimefunUniversalBlockData
+ */
+@Getter
+public enum UniversalDataTrait {
+ /**
+ * BLOCK 特征标明该通用数据属于 {@link SlimefunUniversalBlockData}
+ */
+ BLOCK("location"),
+
+ /**
+ * INVENTORY 特征标明该通用数据拥有一个 {@link UniversalMenu}
+ */
+ INVENTORY("");
+
+ private final String reservedKey;
+
+ UniversalDataTrait(String reservedKey) {
+ this.reservedKey = reservedKey;
+ }
+
+ public static boolean isReservedKey(String key) {
+ for (UniversalDataTrait trait : UniversalDataTrait.values()) {
+ if (trait.getReservedKey().equals(key)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/migrator/IMigrator.java b/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/migrator/IMigrator.java
index a594789b2a..fdffbd8587 100644
--- a/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/migrator/IMigrator.java
+++ b/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/migrator/IMigrator.java
@@ -6,5 +6,7 @@ public interface IMigrator {
MigrateStatus migrateData();
- String getName();
+ default String getName() {
+ return this.getClass().getSimpleName();
+ }
}
diff --git a/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/util/LocationUtils.java b/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/util/LocationUtils.java
index 272da92628..8ca9e9803c 100644
--- a/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/util/LocationUtils.java
+++ b/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/util/LocationUtils.java
@@ -15,6 +15,10 @@ public static String getChunkKey(Chunk chunk) {
}
public static Location toLocation(String lKey) {
+ if (lKey == null || lKey.isEmpty()) {
+ return null;
+ }
+
String[] strArr = lKey.split(";");
String[] loc = strArr[1].split(":");
return new Location(
diff --git a/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/util/StorageCacheUtils.java b/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/util/StorageCacheUtils.java
index 3217a9c8be..4ba0995788 100644
--- a/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/util/StorageCacheUtils.java
+++ b/src/main/java/com/xzavier0722/mc/plugin/slimefun4/storage/util/StorageCacheUtils.java
@@ -1,31 +1,44 @@
package com.xzavier0722.mc.plugin.slimefun4.storage.util;
+import city.norain.slimefun4.api.menu.UniversalMenu;
+import com.google.common.base.Preconditions;
import com.xzavier0722.mc.plugin.slimefun4.storage.callback.IAsyncReadCallback;
+import com.xzavier0722.mc.plugin.slimefun4.storage.controller.ADataContainer;
+import com.xzavier0722.mc.plugin.slimefun4.storage.controller.ASlimefunDataContainer;
import com.xzavier0722.mc.plugin.slimefun4.storage.controller.SlimefunBlockData;
+import com.xzavier0722.mc.plugin.slimefun4.storage.controller.SlimefunUniversalBlockData;
+import com.xzavier0722.mc.plugin.slimefun4.storage.controller.SlimefunUniversalData;
+import io.github.bakedlibs.dough.blocks.BlockPosition;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
import java.util.HashSet;
import java.util.Set;
-import javax.annotation.Nullable;
+import java.util.UUID;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
import org.bukkit.Location;
+import org.bukkit.block.Block;
/**
* Utils to access the cached block data.
- * It is safe to use when the target block is in a loaded chunk (such as in block events).
+ * It is safe to use when the target block is in a loaded chunk(such as in block events).
* By default, please use
* {@link com.xzavier0722.mc.plugin.slimefun4.storage.controller.BlockDataController#getBlockData}
*/
public class StorageCacheUtils {
- private static final Set loadingData = new HashSet<>();
+ private static final Set loadingData = new HashSet<>();
public static boolean hasBlock(Location l) {
return getBlock(l) != null;
}
- @Nullable
+
+ public static boolean hasUniversalBlock(Location l) {
+ return Slimefun.getBlockDataService().getUniversalDataUUID(l.getBlock()).isPresent();
+ }
+
+
public static SlimefunBlockData getBlock(Location l) {
return Slimefun.getDatabaseManager().getBlockDataController().getBlockDataFromCache(l);
}
@@ -35,31 +48,60 @@ public static boolean isBlock(Location l, String id) {
return blockData != null && id.equals(blockData.getSfId());
}
- @Nullable
public static SlimefunItem getSfItem(Location l) {
SlimefunBlockData blockData = getBlock(l);
- return blockData == null ? null : SlimefunItem.getById(blockData.getSfId());
+
+ if (blockData != null) {
+ return SlimefunItem.getById(blockData.getSfId());
+ } else {
+ SlimefunUniversalData universalData = getUniversalBlock(l.getBlock());
+ return universalData == null ? null : SlimefunItem.getById(universalData.getSfId());
+ }
}
- @Nullable
public static String getData(Location loc, String key) {
SlimefunBlockData blockData = getBlock(loc);
- return blockData == null ? null : blockData.getData(key);
+
+ if (blockData != null) {
+ return blockData.getData(key);
+ } else {
+ SlimefunUniversalData uniData = getUniversalBlock(loc.getBlock());
+
+ if (uniData == null) {
+ return null;
+ }
+
+ return uniData.getData(key);
+ }
+ }
+
+ public static String getUniversalBlock(UUID uuid, Location loc, String key) {
+ SlimefunUniversalBlockData universalData = getUniversalBlock(uuid, loc);
+ return universalData == null ? null : universalData.getData(key);
}
public static void setData(Location loc, String key, String val) {
SlimefunBlockData block = getBlock(loc);
- if (block == null) {
- return;
+ if (block != null) {
+ block.setData(key, val);
+ } else {
+ var uni = getUniversalBlock(loc.getBlock());
+ Preconditions.checkNotNull(uni);
+ uni.setData(key, val);
}
- block.setData(key, val);
}
public static void removeData(Location loc, String key) {
- getBlock(loc).removeData(key);
+ var block = getBlock(loc);
+ if (block != null) {
+ block.removeData(key);
+ } else {
+ var uni = getUniversalBlock(loc.getBlock());
+ Preconditions.checkNotNull(uni);
+ uni.removeData(key);
+ }
}
- @Nullable
public static BlockMenu getMenu(Location loc) {
SlimefunBlockData blockData = getBlock(loc);
if (blockData == null) {
@@ -74,30 +116,135 @@ public static BlockMenu getMenu(Location loc) {
return blockData.getBlockMenu();
}
- public static void requestLoad(SlimefunBlockData blockData) {
- if (blockData.isDataLoaded()) {
+ public static SlimefunUniversalBlockData getUniversalBlock(UUID uuid) {
+ var uniData = Slimefun.getDatabaseManager().getBlockDataController().getUniversalBlockDataFromCache(uuid);
+
+ if (uniData == null) {
+ return null;
+ }
+
+ if (!uniData.isDataLoaded()) {
+ requestLoad(uniData);
+ return null;
+ }
+
+ return uniData;
+ }
+
+ public static SlimefunUniversalBlockData getUniversalBlock(UUID uuid, Location l) {
+ var uniData = getUniversalBlock(uuid);
+
+ if (uniData != null) {
+ uniData.setLastPresent(new BlockPosition(l));
+ }
+
+ return uniData;
+ }
+
+ /**
+ * Get universal data from block
+ *
+ * You **must** call this method from sync!
+ *
+ * @param block {@link Block}
+ * @return {@link SlimefunUniversalBlockData}
+ */
+ public static SlimefunUniversalBlockData getUniversalBlock(Block block) {
+ var uuid = Slimefun.getBlockDataService().getUniversalDataUUID(block);
+
+ return uuid.map(id -> getUniversalBlock(id, block.getLocation())).orElse(null);
+ }
+
+ /**
+ * Get universal menu from block
+ *
+ * You **must** call this method from sync!
+ *
+ * @param block {@link Block}
+ * @return {@link SlimefunUniversalData}
+ */
+ public static UniversalMenu getUniversalMenu(Block block) {
+ var uniData = getUniversalBlock(block);
+
+ if (uniData == null) {
+ return null;
+ }
+
+ return uniData.getMenu();
+ }
+
+ public static UniversalMenu getUniversalMenu(UUID uuid, Location l) {
+ var uniData = Slimefun.getDatabaseManager().getBlockDataController().getUniversalBlockDataFromCache(uuid);
+
+ if (uniData == null) {
+ return null;
+ }
+
+ if (!uniData.isDataLoaded()) {
+ requestLoad(uniData);
+ return null;
+ }
+
+ uniData.setLastPresent(new BlockPosition(l));
+
+ return uniData.getMenu();
+ }
+
+ public static boolean isBlockPendingRemove(Block block) {
+ if (hasBlock(block.getLocation())) {
+ return getBlock(block.getLocation()).isPendingRemove();
+ }
+
+ if (hasUniversalBlock(block.getLocation())) {
+ return getUniversalBlock(block).isPendingRemove();
+ }
+
+ return false;
+ }
+
+ public static void requestLoad(ADataContainer data) {
+ if (data.isDataLoaded()) {
return;
}
- if (loadingData.contains(blockData)) {
+ if (loadingData.contains(data)) {
return;
}
synchronized (loadingData) {
- if (loadingData.contains(blockData)) {
+ if (loadingData.contains(data)) {
return;
}
- loadingData.add(blockData);
+ loadingData.add(data);
}
- Slimefun.getDatabaseManager()
- .getBlockDataController()
- .loadBlockDataAsync(blockData, new IAsyncReadCallback<>() {
- @Override
- public void onResult(SlimefunBlockData result) {
- loadingData.remove(blockData);
- }
- });
+ if (data instanceof SlimefunBlockData blockData) {
+ Slimefun.getDatabaseManager()
+ .getBlockDataController()
+ .loadBlockDataAsync(blockData, new IAsyncReadCallback<>() {
+ @Override
+ public void onResult(SlimefunBlockData result) {
+ loadingData.remove(data);
+ }
+ });
+ } else if (data instanceof SlimefunUniversalData uniData) {
+ Slimefun.getDatabaseManager()
+ .getBlockDataController()
+ .loadUniversalDataAsync(uniData, new IAsyncReadCallback<>() {
+ @Override
+ public void onResult(SlimefunUniversalData result) {
+ loadingData.remove(data);
+ }
+ });
+ }
+ }
+
+ public static void executeAfterLoad(ASlimefunDataContainer data, Runnable execute, boolean runOnMainThread) {
+ if (data instanceof SlimefunBlockData blockData) {
+ executeAfterLoad(blockData, execute, runOnMainThread);
+ } else if (data instanceof SlimefunUniversalData universalData) {
+ executeAfterLoad(universalData, execute, runOnMainThread);
+ }
}
public static void executeAfterLoad(SlimefunBlockData data, Runnable execute, boolean runOnMainThread) {
@@ -118,4 +265,23 @@ public void onResult(SlimefunBlockData result) {
}
});
}
+
+ public static void executeAfterLoad(SlimefunUniversalData data, Runnable execute, boolean runOnMainThread) {
+ if (data.isDataLoaded()) {
+ execute.run();
+ return;
+ }
+
+ Slimefun.getDatabaseManager().getBlockDataController().loadUniversalDataAsync(data, new IAsyncReadCallback<>() {
+ @Override
+ public boolean runOnMainThread() {
+ return runOnMainThread;
+ }
+
+ @Override
+ public void onResult(SlimefunUniversalData result) {
+ execute.run();
+ }
+ });
+ }
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/api/ErrorReport.java b/src/main/java/io/github/thebusybiscuit/slimefun4/api/ErrorReport.java
index cff43c1323..5d9938462d 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/api/ErrorReport.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/api/ErrorReport.java
@@ -79,39 +79,57 @@ public ErrorReport(T throwable, SlimefunAddon addon, Consumer print
*/
public ErrorReport(T throwable, Location l, SlimefunItem item) {
this(throwable, item.getAddon(), stream -> {
- stream.println("Block Info:");
- stream.println(" World: " + l.getWorld().getName());
+ stream.println("方块信息:");
+ stream.println(" 世界: " + l.getWorld().getName());
stream.println(" X: " + l.getBlockX());
stream.println(" Y: " + l.getBlockY());
stream.println(" Z: " + l.getBlockZ());
- stream.println(" Material: " + l.getBlock().getType());
- stream.println(
- " Block Data: " + l.getBlock().getBlockData().getClass().getName());
- stream.println(" State: " + l.getBlock().getState().getClass().getName());
+ stream.println(" 方块类型: " + l.getBlock().getType());
+ stream.println(" 方块数据: " + l.getBlock().getBlockData().getClass().getName());
+ stream.println(" 状态: " + l.getBlock().getState().getClass().getName());
stream.println();
if (item.getBlockTicker() != null) {
- stream.println("Ticker-Info:");
- stream.println(" Type: " + (item.getBlockTicker().isSynchronized() ? "Synchronized" : "Asynchronous"));
+ stream.println("Ticker 信息:");
+ stream.println(" 类型: " + (item.getBlockTicker().isSynchronized() ? "同步" : "异步"));
stream.println();
}
if (item instanceof EnergyNetProvider) {
- stream.println("Ticker-Info:");
- stream.println(" Type: Indirect (Energy Network)");
+ stream.println("Ticker 信息:");
+ stream.println(" 类型: 间接 (由能源网络管理)");
stream.println();
}
- stream.println("Slimefun Data:");
+ stream.println("Slimefun 数据:");
stream.println(" ID: " + item.getId());
var blockData =
Slimefun.getDatabaseManager().getBlockDataController().getBlockData(l);
+
if (blockData == null) {
- stream.println("Block data is not presented.");
+ Slimefun.getBlockDataService()
+ .getUniversalDataUUID(l.getBlock())
+ .ifPresentOrElse(
+ uuid -> {
+ var universalData = Slimefun.getDatabaseManager()
+ .getBlockDataController()
+ .getUniversalBlockDataFromCache(uuid);
+ if (universalData != null) {
+ stream.println(" 数据加载状态: " + universalData.isDataLoaded());
+ stream.println(" 物品栏: " + (universalData.getMenu() != null));
+ stream.println(" 数据: ");
+ universalData
+ .getAllData()
+ .forEach((k, v) -> stream.println(" " + k + ": " + v));
+ } else {
+ stream.println("该方块没有任何数据.");
+ }
+ },
+ () -> stream.println("该方块没有任何数据."));
} else {
- stream.println(" Is data loaded: " + blockData.isDataLoaded());
- stream.println(" Inventory: " + (blockData.getBlockMenu() != null));
- stream.println(" Data: ");
+ stream.println(" 数据加载状态: " + blockData.isDataLoaded());
+ stream.println(" 物品栏: " + (blockData.getBlockMenu() != null));
+ stream.println(" 数据: ");
blockData.getAllData().forEach((k, v) -> stream.println(" " + k + ": " + v));
}
stream.println();
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/api/items/SlimefunItem.java b/src/main/java/io/github/thebusybiscuit/slimefun4/api/items/SlimefunItem.java
index fb3a8dbcc8..69dc448ff4 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/api/items/SlimefunItem.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/api/items/SlimefunItem.java
@@ -5,7 +5,6 @@
import io.github.bakedlibs.dough.items.ItemUtils;
import io.github.thebusybiscuit.slimefun4.api.SlimefunAddon;
import io.github.thebusybiscuit.slimefun4.api.exceptions.IdConflictException;
-import io.github.thebusybiscuit.slimefun4.api.exceptions.IncompatibleItemHandlerException;
import io.github.thebusybiscuit.slimefun4.api.exceptions.MissingDependencyException;
import io.github.thebusybiscuit.slimefun4.api.exceptions.UnregisteredItemException;
import io.github.thebusybiscuit.slimefun4.api.exceptions.WrongItemStackException;
@@ -188,7 +187,7 @@ public SlimefunItem(
this.recipeType = recipeType;
this.recipe = recipe;
this.recipeOutput = recipeOutput;
- normalItemName = TextUtils.toPlainText(itemStackTemplate.getItemMeta().getDisplayName()).replaceAll(" ","_");
+ normalItemName = TextUtils.toPlainText(itemStackTemplate.getItemMeta().getDisplayName()).replaceAll(" ", "_");
}
// Previously deprecated constructor, now only for internal purposes
@@ -198,7 +197,7 @@ protected SlimefunItem(ItemGroup itemGroup, ItemStack item, String id, RecipeTyp
this.id = id;
this.recipeType = recipeType;
this.recipe = recipe;
- normalItemName = TextUtils.toPlainText(itemStackTemplate.getItemMeta().getDisplayName()).replaceAll(" ","_");
+ normalItemName = TextUtils.toPlainText(itemStackTemplate.getItemMeta().getDisplayName()).replaceAll(" ", "_");
}
/**
@@ -505,13 +504,6 @@ private void onEnable() {
private void loadItemHandlers() {
for (ItemHandler handler : itemHandlers.values()) {
- Optional exception = handler.validate(this);
-
- // Check if the validation caused an exception.
- if (exception.isPresent()) {
- throw exception.get();
- }
-
/*
* If this ItemHandler is "global" (not bound to this SlimefunItem),
* we add it to the list of global Item handlers
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/NotCardinallyRotatable.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/rotations/NotCardinallyRotatable.java
similarity index 85%
rename from src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/NotCardinallyRotatable.java
rename to src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/rotations/NotCardinallyRotatable.java
index a4ebd320c8..6dcc9acffe 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/NotCardinallyRotatable.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/rotations/NotCardinallyRotatable.java
@@ -1,6 +1,7 @@
-package io.github.thebusybiscuit.slimefun4.core.attributes;
+package io.github.thebusybiscuit.slimefun4.core.attributes.rotations;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
+import io.github.thebusybiscuit.slimefun4.core.attributes.ItemAttribute;
import org.bukkit.block.BlockFace;
/**
@@ -12,7 +13,6 @@
* {@link BlockFace}.WEST
*
* @author Ddggdd135
- *
*/
public interface NotCardinallyRotatable extends ItemAttribute {
default BlockFace getRotation(double angle) {
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/NotDiagonallyRotatable.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/rotations/NotDiagonallyRotatable.java
similarity index 86%
rename from src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/NotDiagonallyRotatable.java
rename to src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/rotations/NotDiagonallyRotatable.java
index 6dcbb87926..f992533df7 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/NotDiagonallyRotatable.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/rotations/NotDiagonallyRotatable.java
@@ -1,6 +1,7 @@
-package io.github.thebusybiscuit.slimefun4.core.attributes;
+package io.github.thebusybiscuit.slimefun4.core.attributes.rotations;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
+import io.github.thebusybiscuit.slimefun4.core.attributes.ItemAttribute;
import org.bukkit.block.BlockFace;
/**
@@ -12,7 +13,6 @@
* {@link BlockFace}.SOUTH_WEST
*
* @author Ddggdd135
- *
*/
public interface NotDiagonallyRotatable extends ItemAttribute {
default BlockFace getRotation(double angle) {
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/NotRotatable.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/rotations/NotRotatable.java
similarity index 72%
rename from src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/NotRotatable.java
rename to src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/rotations/NotRotatable.java
index b8b9f26f89..92d236cbdd 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/NotRotatable.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/attributes/rotations/NotRotatable.java
@@ -1,6 +1,7 @@
-package io.github.thebusybiscuit.slimefun4.core.attributes;
+package io.github.thebusybiscuit.slimefun4.core.attributes.rotations;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
+import io.github.thebusybiscuit.slimefun4.core.attributes.ItemAttribute;
import org.bukkit.block.BlockFace;
/**
@@ -8,7 +9,6 @@
* that {@link SlimefunItem} from being rotated.
*
* @author Ddggdd135
- *
*/
public interface NotRotatable extends ItemAttribute {
default BlockFace getRotation() {
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/config/SlimefunDatabaseManager.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/config/SlimefunDatabaseManager.java
index b501a0536a..39bd177e83 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/config/SlimefunDatabaseManager.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/config/SlimefunDatabaseManager.java
@@ -53,9 +53,6 @@ public SlimefunDatabaseManager(Slimefun plugin) {
public void init() {
initDefaultVal();
- // Minimise hikari log
- System.setProperty("org.slf4j.simpleLogger.log.com.zaxxer.hikari", "error");
-
try {
blockDataStorageType = StorageType.valueOf(blockStorageConfig.getString("storageType"));
var readExecutorThread = blockStorageConfig.getInt("readExecutorThread");
@@ -153,7 +150,8 @@ private void initAdapter(StorageType storageType, DataType dataType, Config data
}
}
- @Nullable public ProfileDataController getProfileDataController() {
+ @Nullable
+ public ProfileDataController getProfileDataController() {
return ControllerHolder.getController(ProfileDataController.class, profileStorageType);
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/AutoSavingService.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/AutoSavingService.java
index 4aab97df04..a30bea02d0 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/AutoSavingService.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/AutoSavingService.java
@@ -2,8 +2,10 @@
import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
+
import java.util.Iterator;
import java.util.logging.Level;
+
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
@@ -12,16 +14,13 @@
* data.
*
* @author TheBusyBiscuit
- *
*/
public class AutoSavingService {
/**
* This method starts the {@link AutoSavingService} with the given interval.
*
- * @param plugin
- * The current instance of Slimefun
- * @param interval
- * The interval in which to run this task
+ * @param plugin The current instance of Slimefun
+ * @param interval The interval in which to run this task
*/
public void start(Slimefun plugin, int interval) {
plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, this::saveAllPlayers, 2000L, interval * 60L * 20L);
@@ -29,9 +28,15 @@ public void start(Slimefun plugin, int interval) {
.getScheduler()
.runTaskTimerAsynchronously(
plugin,
- () -> Slimefun.getDatabaseManager()
- .getBlockDataController()
- .saveAllBlockInventories(),
+ () -> {
+ Slimefun.getDatabaseManager()
+ .getBlockDataController()
+ .saveAllBlockInventories();
+
+ Slimefun.getDatabaseManager()
+ .getBlockDataController()
+ .saveAllUniversalInventories();
+ },
2000L,
interval * 60L * 20L);
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/BlockDataService.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/BlockDataService.java
index 2354acf2be..b216f68bc5 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/BlockDataService.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/BlockDataService.java
@@ -2,9 +2,12 @@
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
import io.github.thebusybiscuit.slimefun4.utils.tags.SlimefunTag;
+
import java.util.Optional;
+import java.util.UUID;
import java.util.logging.Level;
import javax.annotation.Nullable;
+
import org.bukkit.Bukkit;
import org.bukkit.Keyed;
import org.bukkit.Material;
@@ -24,23 +27,22 @@
* This is used to speed up performance and prevent
*
* @author TheBusyBiscuit
- *
*/
public class BlockDataService implements Keyed {
private final NamespacedKey namespacedKey;
+ private final NamespacedKey universalDataKey;
/**
* This creates a new {@link BlockDataService} for the given {@link Plugin}.
* The {@link Plugin} and key will together form a {@link NamespacedKey} used to store
* data on a {@link TileState}.
*
- * @param plugin
- * The {@link Plugin} responsible for this service
- * @param key
- * The key under which to store data
+ * @param plugin The {@link Plugin} responsible for this service
+ * @param key The key under which to store data
*/
public BlockDataService(Plugin plugin, String key) {
namespacedKey = new NamespacedKey(plugin, key);
+ universalDataKey = new NamespacedKey(plugin, "slimefun_unidata_uuid");
}
@Override
@@ -51,33 +53,44 @@ public NamespacedKey getKey() {
/**
* This will store the given {@link String} inside the NBT data of the given {@link Block}
*
- * @param b
- * The {@link Block} in which to store the given value
- * @param value
- * The value to store
+ * @param b The {@link Block} in which to store the given value
+ * @param value The value to store
*/
public void setBlockData(Block b, String value) {
+ setBlockData(b, namespacedKey, value);
+ }
+
+ /**
+ * This will store the universal data {@link UUID} inside the NBT data of the given {@link Block}
+ *
+ * @param b The {@link Block} in which to store the given value
+ * @param uuid The uuid linked to certain slimefun item
+ */
+ public void updateUniversalDataUUID(Block b, String uuid) {
+ setBlockData(b, universalDataKey, uuid);
+ }
+
+ /**
+ * This will store the given {@link String} inside the NBT data of the given {@link Block}
+ *
+ * @param b The {@link Block} in which to store the given value
+ * @param value The value to store
+ */
+ public void setBlockData(Block b, NamespacedKey key, String value) {
BlockState state = b.getState();
if (state instanceof TileState tileState) {
try {
PersistentDataContainer container = tileState.getPersistentDataContainer();
- container.set(namespacedKey, PersistentDataType.STRING, value);
+ container.set(key, PersistentDataType.STRING, value);
state.update();
} catch (RuntimeException x) {
Slimefun.logger().log(Level.SEVERE, "Please check if your Server Software is up to date!");
String serverSoftware = Bukkit.getName();
- Slimefun.logger()
- .log(
- Level.SEVERE,
- () -> serverSoftware + " | " + Bukkit.getVersion() + " | " + Bukkit.getBukkitVersion());
-
- Slimefun.logger()
- .log(
- Level.SEVERE,
- "An Exception was thrown while trying to set Persistent Data for a Block",
- x);
+ Slimefun.logger().log(Level.SEVERE, () -> serverSoftware + " | " + Bukkit.getVersion() + " | " + Bukkit.getBukkitVersion());
+
+ Slimefun.logger().log(Level.SEVERE, "An Exception was thrown while trying to set Persistent Data for a Block", x);
}
}
}
@@ -85,23 +98,38 @@ public void setBlockData(Block b, String value) {
/**
* This method returns the NBT data previously stored inside this {@link Block}.
*
- * @param b
- * The {@link Block} to retrieve data from
- *
+ * @param b The {@link Block} to retrieve data from
* @return The stored value
*/
public Optional getBlockData(Block b) {
+ return getBlockData(b, namespacedKey);
+ }
+
+ public Optional getUniversalDataUUID(Block b) {
+ var uuid = getBlockData(b, universalDataKey);
+
+ return uuid.map(data -> {
+ try {
+ return UUID.fromString(data);
+ } catch (IllegalArgumentException e) {
+ return null;
+ }
+ });
+ }
+
+ public Optional getBlockData(Block b, NamespacedKey key) {
BlockState state = b.getState(false);
PersistentDataContainer container = getPersistentDataContainer(state);
if (container != null) {
- return Optional.ofNullable(container.get(namespacedKey, PersistentDataType.STRING));
+ return Optional.ofNullable(container.get(key, PersistentDataType.STRING));
} else {
return Optional.empty();
}
}
- @Nullable private PersistentDataContainer getPersistentDataContainer(BlockState state) {
+ @Nullable
+ private PersistentDataContainer getPersistentDataContainer(BlockState state) {
if (state instanceof TileState tileState) {
return tileState.getPersistentDataContainer();
} else {
@@ -117,9 +145,7 @@ public Optional getBlockData(Block b) {
* Due to {@link Block#getState()} being a very expensive call performance-wise though,
* this simple lookup method is used instead.
*
- * @param type
- * The {@link Material} to check for
- *
+ * @param type The {@link Material} to check for
* @return Whether the given {@link Material} is considered a Tile Entity
*/
public boolean isTileEntity(@Nullable Material type) {
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/MinecraftRecipeService.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/MinecraftRecipeService.java
index ad1e706791..7cdfef791e 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/MinecraftRecipeService.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/MinecraftRecipeService.java
@@ -129,7 +129,7 @@ public RecipeChoice[] getRecipeShape(Recipe recipe) {
List choices = new LinkedList<>();
for (String row : shapedRecipe.getShape()) {
- int columns = row.toCharArray().length;
+ int columns = row.length();
for (char key : row.toCharArray()) {
choices.add(shapedRecipe.getChoiceMap().get(key));
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/ticker/TickLocation.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/ticker/TickLocation.java
new file mode 100644
index 0000000000..c7d5ef9693
--- /dev/null
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/ticker/TickLocation.java
@@ -0,0 +1,32 @@
+package io.github.thebusybiscuit.slimefun4.core.ticker;
+
+import io.github.bakedlibs.dough.blocks.BlockPosition;
+
+import java.util.UUID;
+
+import lombok.Getter;
+import org.bukkit.Location;
+
+@Getter
+public class TickLocation {
+ private final BlockPosition position;
+ private final UUID uuid;
+
+ public TickLocation(BlockPosition position) {
+ this.position = position;
+ uuid = null;
+ }
+
+ public TickLocation(BlockPosition position, UUID uuid) {
+ this.position = position;
+ this.uuid = uuid;
+ }
+
+ public boolean isUniversal() {
+ return uuid != null;
+ }
+
+ public Location getLocation() {
+ return position.toLocation();
+ }
+}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/Slimefun.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/Slimefun.java
index 7301e7b778..7e697bdb08 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/Slimefun.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/Slimefun.java
@@ -45,7 +45,6 @@
import io.github.thebusybiscuit.slimefun4.utils.NumberUtils;
import io.github.thebusybiscuit.slimefun4.utils.tags.SlimefunTag;
import lombok.Getter;
-import lombok.NonNull;
import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.MenuListener;
import me.qscbm.slimefun4.helper.ItemHelper;
import me.qscbm.slimefun4.services.LanguageService;
@@ -596,7 +595,7 @@ private void loadResearches() {
*
* @return The {@link Slimefun} instance
*/
- public static @NonNull Slimefun instance() {
+ public static Slimefun instance() {
return instance;
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/AndroidAction.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/AndroidAction.java
index 06a6e5f135..43ce01c23d 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/AndroidAction.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/AndroidAction.java
@@ -1,10 +1,10 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.androids;
-import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
+import city.norain.slimefun4.api.menu.UniversalMenu;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
@FunctionalInterface
interface AndroidAction {
- void perform(ProgrammableAndroid android, Block b, BlockMenu inventory, BlockFace face);
+ void perform(ProgrammableAndroid android, Block b, UniversalMenu inventory, BlockFace face);
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/FarmerAndroid.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/FarmerAndroid.java
index 35146c1778..3654a96a9e 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/FarmerAndroid.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/FarmerAndroid.java
@@ -1,5 +1,6 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.androids;
+import city.norain.slimefun4.api.menu.UniversalMenu;
import com.xzavier0722.mc.plugin.slimefun4.storage.util.StorageCacheUtils;
import io.github.bakedlibs.dough.protection.Interaction;
import io.github.thebusybiscuit.slimefun4.api.events.AndroidFarmEvent;
@@ -7,11 +8,11 @@
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
+
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
-import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
import org.bukkit.Bukkit;
import org.bukkit.Effect;
import org.bukkit.Material;
@@ -33,9 +34,9 @@ public AndroidType getAndroidType() {
}
@Override
- protected void farm(Block b, BlockMenu menu, Block block, boolean isAdvanced) {
- OfflinePlayer owner =
- Bukkit.getOfflinePlayer(UUID.fromString(StorageCacheUtils.getData(b.getLocation(), "owner")));
+ protected void farm(Block b, UniversalMenu menu, Block block, boolean isAdvanced) {
+ OfflinePlayer owner = Bukkit.getOfflinePlayer(
+ UUID.fromString(StorageCacheUtils.getUniversalBlock(menu.getUuid(), b.getLocation(), "owner")));
if (!Slimefun.getProtectionManager().hasPermission(owner, block, Interaction.BREAK_BLOCK)) {
return;
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/FishermanAndroid.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/FishermanAndroid.java
index 3d7e186f8d..fc75bdc537 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/FishermanAndroid.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/FishermanAndroid.java
@@ -1,13 +1,14 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.androids;
+import city.norain.slimefun4.api.menu.UniversalMenu;
import io.github.bakedlibs.dough.collections.RandomizedSet;
import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
import io.github.thebusybiscuit.slimefun4.core.services.sounds.SoundEffect;
+
import java.util.concurrent.ThreadLocalRandom;
-import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
import org.bukkit.Material;
import org.bukkit.Tag;
import org.bukkit.block.Block;
@@ -48,7 +49,7 @@ public AndroidType getAndroidType() {
}
@Override
- protected void fish(Block b, BlockMenu menu) {
+ protected void fish(Block b, UniversalMenu menu) {
Block water = b.getRelative(BlockFace.DOWN);
if (water.getType() == Material.WATER) {
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/Instruction.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/Instruction.java
index d804dca242..4577b81c83 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/Instruction.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/Instruction.java
@@ -1,14 +1,15 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.androids;
+import city.norain.slimefun4.api.menu.UniversalMenu;
import io.github.thebusybiscuit.slimefun4.utils.HeadTexture;
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
+
import java.util.HashMap;
import java.util.Map;
import java.util.function.Predicate;
-import javax.annotation.Nullable;
import lombok.Getter;
-import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
+
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Ageable;
@@ -22,7 +23,6 @@
* added by Slimefun itself.
*
* @author TheBusyBiscuit
- *
*/
public enum Instruction {
/**
@@ -248,7 +248,7 @@ public enum Instruction {
private final AndroidType type;
private final AndroidAction method;
- Instruction(AndroidType type, HeadTexture head, @Nullable AndroidAction method) {
+ Instruction(AndroidType type, HeadTexture head, AndroidAction method) {
this.type = type;
this.item = SlimefunUtils.getCustomHead(head.getTexture());
this.method = method;
@@ -262,8 +262,8 @@ public AndroidType getRequiredType() {
return type;
}
- public void execute(ProgrammableAndroid android, Block b, BlockMenu inventory, BlockFace face) {
- method.perform(android, b, inventory, face);
+ public void execute(ProgrammableAndroid android, Block b, UniversalMenu inventory, BlockFace face) {
+ method.perform(android, b, inventory, face);
}
/**
@@ -272,12 +272,10 @@ public void execute(ProgrammableAndroid android, Block b, BlockMenu inventory, B
* your Java version. It also means that you can avoid an IllegalArgumentException which let's
* face it is always good.
*
- * @param value
- * The value which you would like to look up.
- *
+ * @param value The value which you would like to look up.
* @return The {@link Instruction} or null if it does not exist.
*/
- @Nullable public static Instruction getInstruction(String value) {
+ public static Instruction getInstruction(String value) {
return nameLookup.get(value);
}
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/MinerAndroid.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/MinerAndroid.java
index b5354a86f9..056046845c 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/MinerAndroid.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/MinerAndroid.java
@@ -1,5 +1,6 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.androids;
+import city.norain.slimefun4.api.menu.UniversalMenu;
import com.xzavier0722.mc.plugin.slimefun4.storage.util.StorageCacheUtils;
import io.github.bakedlibs.dough.protection.Interaction;
import io.github.thebusybiscuit.slimefun4.api.events.AndroidMineEvent;
@@ -12,10 +13,10 @@
import io.github.thebusybiscuit.slimefun4.utils.InfiniteBlockGenerator;
import io.github.thebusybiscuit.slimefun4.utils.compatibility.VersionedParticle;
import io.github.thebusybiscuit.slimefun4.utils.tags.SlimefunTag;
+
import java.util.Collection;
import java.util.UUID;
-import me.mrCookieSlime.Slimefun.api.BlockStorage;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
import org.bukkit.Bukkit;
import org.bukkit.Effect;
@@ -29,8 +30,6 @@
/**
* The {@link MinerAndroid} is a variant of the {@link ProgrammableAndroid} which
* is able to break blocks.
- * The core functionalities boil down to {@link #dig(Block, BlockMenu, Block)} and
- * {@link #moveAndDig(Block, BlockMenu, BlockFace, Block)}.
* Otherwise the functionality is similar to a regular android.
*
* The {@link MinerAndroid} will also fire an {@link AndroidMineEvent} when breaking a {@link Block}.
@@ -42,9 +41,7 @@
* @author CyberPatriot
* @author Redemption198
* @author Poslovitch
- *
* @see AndroidMineEvent
- *
*/
public class MinerAndroid extends ProgrammableAndroid {
// Determines the drops a miner android will get
@@ -67,12 +64,12 @@ public AndroidType getAndroidType() {
}
@Override
- protected void dig(Block b, BlockMenu menu, Block block) {
+ protected void dig(Block b, UniversalMenu menu, Block block) {
Collection drops = block.getDrops(effectivePickaxe);
if (!SlimefunTag.UNBREAKABLE_MATERIALS.isTagged(block.getType()) && !drops.isEmpty()) {
- OfflinePlayer owner =
- Bukkit.getOfflinePlayer(UUID.fromString(BlockStorage.getLocationInfo(b.getLocation(), "owner")));
+ OfflinePlayer owner = Bukkit.getOfflinePlayer(
+ UUID.fromString(StorageCacheUtils.getUniversalBlock(menu.getUuid(), b.getLocation(), "owner")));
if (Slimefun.getProtectionManager().hasPermission(owner, block.getLocation(), Interaction.BREAK_BLOCK)) {
AndroidMineEvent event = new AndroidMineEvent(block, new AndroidInstance(this, b));
@@ -83,7 +80,8 @@ protected void dig(Block b, BlockMenu menu, Block block) {
}
// We only want to break non-Slimefun blocks
- if (!StorageCacheUtils.hasBlock(block.getLocation())) {
+ if (!StorageCacheUtils.hasBlock(block.getLocation())
+ && !StorageCacheUtils.hasUniversalBlock(block.getLocation())) {
breakBlock(menu, drops, block);
}
}
@@ -91,12 +89,12 @@ protected void dig(Block b, BlockMenu menu, Block block) {
}
@Override
- protected void moveAndDig(Block b, BlockMenu menu, BlockFace face, Block block) {
+ protected void moveAndDig(Block b, UniversalMenu menu, BlockFace face, Block block) {
Collection drops = block.getDrops(effectivePickaxe);
if (!SlimefunTag.UNBREAKABLE_MATERIALS.isTagged(block.getType()) && !drops.isEmpty()) {
- OfflinePlayer owner =
- Bukkit.getOfflinePlayer(UUID.fromString(BlockStorage.getLocationInfo(b.getLocation(), "owner")));
+ OfflinePlayer owner = Bukkit.getOfflinePlayer(
+ UUID.fromString(StorageCacheUtils.getUniversalBlock(menu.getUuid(), b.getLocation(), "owner")));
if (Slimefun.getProtectionManager().hasPermission(owner, block.getLocation(), Interaction.BREAK_BLOCK)) {
AndroidMineEvent event = new AndroidMineEvent(block, new AndroidInstance(this, b));
@@ -107,7 +105,8 @@ protected void moveAndDig(Block b, BlockMenu menu, BlockFace face, Block block)
}
// We only want to break non-Slimefun blocks
- if (!StorageCacheUtils.hasBlock(block.getLocation())) {
+ if (!StorageCacheUtils.hasBlock(block.getLocation())
+ && !StorageCacheUtils.hasUniversalBlock(block.getLocation())) {
breakBlock(menu, drops, block);
move(b, face, block);
}
@@ -119,7 +118,7 @@ protected void moveAndDig(Block b, BlockMenu menu, BlockFace face, Block block)
}
}
- private void breakBlock(BlockMenu menu, Collection drops, Block block) {
+ private void breakBlock(UniversalMenu menu, Collection drops, Block block) {
if (!block.getWorld().getWorldBorder().isInside(block.getLocation())) {
return;
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/ProgrammableAndroid.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/ProgrammableAndroid.java
index 3020eaa378..047da3384c 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/ProgrammableAndroid.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/ProgrammableAndroid.java
@@ -1,7 +1,12 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.androids;
-import com.xzavier0722.mc.plugin.slimefun4.storage.controller.SlimefunBlockData;
+import city.norain.slimefun4.api.menu.UniversalMenu;
+import city.norain.slimefun4.api.menu.UniversalMenuPreset;
+import com.xzavier0722.mc.plugin.slimefun4.storage.controller.SlimefunUniversalBlockData;
+import com.xzavier0722.mc.plugin.slimefun4.storage.controller.SlimefunUniversalData;
+import com.xzavier0722.mc.plugin.slimefun4.storage.controller.attributes.UniversalBlock;
import com.xzavier0722.mc.plugin.slimefun4.storage.util.StorageCacheUtils;
+import io.github.bakedlibs.dough.blocks.BlockPosition;
import io.github.bakedlibs.dough.chat.ChatInput;
import io.github.bakedlibs.dough.common.CommonPatterns;
import io.github.bakedlibs.dough.items.CustomItemStack;
@@ -13,8 +18,8 @@
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
-import io.github.thebusybiscuit.slimefun4.core.attributes.NotDiagonallyRotatable;
import io.github.thebusybiscuit.slimefun4.core.attributes.RecipeDisplayItem;
+import io.github.thebusybiscuit.slimefun4.core.attributes.rotations.NotDiagonallyRotatable;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockPlaceHandler;
import io.github.thebusybiscuit.slimefun4.core.services.sounds.SoundEffect;
@@ -41,12 +46,9 @@
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.MachineFuel;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.interfaces.InventoryBlock;
import me.mrCookieSlime.Slimefun.Objects.handlers.BlockTicker;
-import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
-import me.mrCookieSlime.Slimefun.api.inventory.BlockMenuPreset;
import me.mrCookieSlime.Slimefun.api.item_transport.ItemTransportFlow;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
-import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
import org.bukkit.Tag;
@@ -65,7 +67,8 @@
import org.bukkit.inventory.meta.ItemMeta;
public class ProgrammableAndroid extends SlimefunItem
- implements InventoryBlock, RecipeDisplayItem, NotDiagonallyRotatable {
+ implements InventoryBlock, RecipeDisplayItem, NotDiagonallyRotatable, UniversalBlock {
+
private static final List POSSIBLE_ROTATIONS =
Arrays.asList(BlockFace.NORTH, BlockFace.EAST, BlockFace.SOUTH, BlockFace.WEST);
private static final int[] BORDER = {
@@ -88,7 +91,8 @@ public ProgrammableAndroid(
texture = item.getSkullTexture().orElse(null);
registerDefaultFuelTypes();
- new BlockMenuPreset(getId(), "可编程式机器人") {
+ new UniversalMenuPreset(getId(), "可编程式机器人") {
+
@Override
public void init() {
constructMenu(this);
@@ -96,8 +100,11 @@ public void init() {
@Override
public boolean canOpen(Block b, Player p) {
- boolean isOwner = p.getUniqueId().toString().equals(StorageCacheUtils.getData(b.getLocation(), "owner"))
- || p.hasPermission("slimefun.android.bypass");
+ var uniData = StorageCacheUtils.getUniversalBlock(b);
+
+ UUID owner = UUID.fromString(uniData.getData("owner"));
+
+ boolean isOwner = p.getUniqueId().equals(owner) || p.hasPermission("slimefun.android.bypass");
if (isOwner || AndroidShareMenu.isTrustedUser(b, p.getUniqueId())) {
return true;
@@ -108,19 +115,21 @@ public boolean canOpen(Block b, Player p) {
}
@Override
- public void newInstance(BlockMenu menu, Block b) {
+ public void newInstance(UniversalMenu menu, Block b) {
+ var uniData = StorageCacheUtils.getUniversalBlock(menu.getUuid());
+
menu.replaceExistingItem(
15, new CustomItemStack(HeadTexture.SCRIPT_START.getAsItemStack(), "&a启动/继续运行"));
menu.addMenuClickHandler(15, (p, slot, item, action) -> {
Slimefun.getLocalization().sendMessage(p, "android.started", true);
- StorageCacheUtils.setData(b.getLocation(), "paused", "false");
+ uniData.setData("paused", "false");
p.closeInventory();
return false;
});
menu.replaceExistingItem(17, new CustomItemStack(HeadTexture.SCRIPT_PAUSE.getAsItemStack(), "§4暂停运行"));
menu.addMenuClickHandler(17, (p, slot, item, action) -> {
- StorageCacheUtils.setData(b.getLocation(), "paused", "true");
+ uniData.setData("paused", "true");
Slimefun.getLocalization().sendMessage(p, "android.stopped", true);
return false;
});
@@ -130,9 +139,9 @@ public void newInstance(BlockMenu menu, Block b) {
new CustomItemStack(
HeadTexture.ENERGY_REGULATOR.getAsItemStack(), "&b内存核心", "", "§8\u21E8 &7单击打开脚本编辑器"));
menu.addMenuClickHandler(16, (p, slot, item, action) -> {
- StorageCacheUtils.setData(b.getLocation(), "paused", "true");
+ uniData.setData("paused", "true");
Slimefun.getLocalization().sendMessage(p, "android.stopped", true);
- openScriptEditor(p, b);
+ openScriptEditor(p, uniData);
return false;
});
@@ -144,7 +153,7 @@ public void newInstance(BlockMenu menu, Block b) {
"",
Slimefun.getLocalization().getMessage("android.access-manager.subtitle")));
menu.addMenuClickHandler(25, (p, slot, item, action) -> {
- StorageCacheUtils.setData(b.getLocation(), "paused", "true");
+ uniData.setData("paused", "true");
Slimefun.getLocalization().sendMessage(p, "android.stopped", true);
AndroidShareMenu.openShareMenu(p, b);
return false;
@@ -167,13 +176,15 @@ public void onPlayerPlace(BlockPlaceEvent e) {
Player p = e.getPlayer();
Block b = e.getBlock();
- var blockData = StorageCacheUtils.getBlock(b.getLocation());
- blockData.setData("owner", p.getUniqueId().toString());
- blockData.setData("script", DEFAULT_SCRIPT);
- blockData.setData("index", "0");
- blockData.setData("fuel", "0");
- blockData.setData("rotation", p.getFacing().getOppositeFace().toString());
- blockData.setData("paused", "true");
+ var universalData = StorageCacheUtils.getUniversalBlock(b);
+
+ universalData.setData("owner", p.getUniqueId().toString());
+ universalData.setData("script", DEFAULT_SCRIPT);
+ universalData.setData("index", String.valueOf(0));
+ universalData.setData("fuel", String.valueOf(0));
+ universalData.setData(
+ "rotation", p.getFacing().getOppositeFace().toString());
+ universalData.setData("paused", String.valueOf(true));
b.setBlockData(Material.PLAYER_HEAD.createBlockData(data -> {
if (data instanceof Rotatable rotatable) {
@@ -189,21 +200,19 @@ private BlockBreakHandler onBreak() {
@Override
public void onPlayerBreak(BlockBreakEvent e, ItemStack item, List drops) {
Block b = e.getBlock();
- var blockData = StorageCacheUtils.getBlock(b.getLocation());
- String owner = blockData.getData("owner");
+ var uniData = StorageCacheUtils.getUniversalBlock(b);
if (!e.getPlayer().hasPermission("slimefun.android.bypass")
- && !e.getPlayer().getUniqueId().toString().equals(owner)) {
+ && !e.getPlayer().getUniqueId().equals(uniData.getData("owner"))) {
// The Player is not allowed to break this android
e.setCancelled(true);
return;
}
- BlockMenu inv = blockData.getBlockMenu();
-
- if (inv != null) {
- inv.dropItems(b.getLocation(), 43);
- inv.dropItems(b.getLocation(), getOutputSlots());
+ var menu = uniData.getMenu();
+ if (menu != null) {
+ menu.dropItems(b.getLocation(), 43);
+ menu.dropItems(b.getLocation(), getOutputSlots());
}
}
};
@@ -238,9 +247,10 @@ public AndroidFuelSource getFuelSource() {
public void preRegister() {
super.preRegister();
- addItemHandler(new BlockTicker() {
+ addItemHandler(new BlockTicker(true) {
+
@Override
- public void tick(Block b, SlimefunItem item, SlimefunBlockData data) {
+ public void tick(Block b, SlimefunItem item, SlimefunUniversalData data) {
if (b != null && data != null) {
ProgrammableAndroid.this.tick(b, data);
}
@@ -253,7 +263,8 @@ public boolean isSynchronized() {
});
}
- public void openScript(Player p, Block b, String sourceCode) {
+
+ public void openScript(Player p, SlimefunUniversalBlockData uniData, String sourceCode) {
ChestMenu menu =
new ChestMenu(ChatColor.DARK_AQUA + Slimefun.getLocalization().getMessage(p, "android.scripts.editor"));
menu.setEmptySlotsClickable(false);
@@ -266,7 +277,7 @@ public void openScript(Player p, Block b, String sourceCode) {
"",
"&7\u21E8 &e左键 &7返回机器人的控制面板"));
menu.addMenuClickHandler(0, (pl, slot, item, action) -> {
- BlockMenu inv = StorageCacheUtils.getMenu(b.getLocation());
+ UniversalMenu inv = uniData.getMenu();
// Fixes #2937
if (inv != null) {
inv.open(pl);
@@ -287,7 +298,7 @@ public void openScript(Player p, Block b, String sourceCode) {
if (hasFreeSlot) {
menu.addItem(i, new CustomItemStack(HeadTexture.SCRIPT_NEW.getAsItemStack(), "&7> 添加新命令"));
menu.addMenuClickHandler(i, (pl, slot, item, action) -> {
- editInstruction(pl, b, script, index);
+ editInstruction(pl, uniData, script, index);
return false;
});
}
@@ -301,7 +312,7 @@ public void openScript(Player p, Block b, String sourceCode) {
"",
"&7\u21E8 &e左键 &7返回机器人的控制面板"));
menu.addMenuClickHandler(slot, (pl, s, item, action) -> {
- BlockMenu inv = StorageCacheUtils.getMenu(b.getLocation());
+ UniversalMenu inv = uniData.getMenu();
// Fixes #2937
if (inv != null) {
inv.open(pl);
@@ -313,16 +324,6 @@ public void openScript(Player p, Block b, String sourceCode) {
} else {
Instruction instruction = Instruction.getInstruction(script[i]);
- if (instruction == null) {
- Slimefun.instance()
- .getLogger()
- .log(
- Level.WARNING,
- "Failed to parse Android instruction: {0}, maybe your server is out of date?",
- script[i]);
- return;
- }
-
ItemStack stack = instruction.getItem();
menu.addItem(
i,
@@ -345,14 +346,14 @@ public void openScript(Player p, Block b, String sourceCode) {
}
String code = duplicateInstruction(script, index);
- setScript(b.getLocation(), code);
- openScript(pl, b, code);
+ setScript(uniData, code);
+ openScript(pl, uniData, code);
} else if (action.isRightClicked()) {
String code = deleteInstruction(script, index);
- setScript(b.getLocation(), code);
- openScript(pl, b, code);
+ setScript(uniData, code);
+ openScript(pl, uniData, code);
} else {
- editInstruction(pl, b, script, index);
+ editInstruction(pl, uniData, script, index);
}
return false;
@@ -417,7 +418,7 @@ private String deleteInstruction(String[] script, int index) {
return builder.toString();
}
- protected void openScriptDownloader(Player p, Block b, int page) {
+ protected void openScriptDownloader(Player p, SlimefunUniversalBlockData uniData, int page) {
ChestMenu menu = new ChestMenu("机器人脚本");
menu.setEmptySlotsClickable(false);
@@ -438,7 +439,7 @@ protected void openScriptDownloader(Player p, Block b, int page) {
next = pages;
}
if (next != page) {
- openScriptDownloader(pl, b, next);
+ openScriptDownloader(pl, uniData, next);
}
return false;
});
@@ -448,7 +449,7 @@ protected void openScriptDownloader(Player p, Block b, int page) {
new CustomItemStack(
HeadTexture.SCRIPT_UP.getAsItemStack(), "&e上传脚本", "", "&6单击 &7将你正在用的脚本", "&7上传到服务器"));
menu.addMenuClickHandler(48, (pl, slot, item, action) -> {
- uploadScript(pl, b, page);
+ uploadScript(pl, uniData, page);
return false;
});
@@ -459,14 +460,14 @@ protected void openScriptDownloader(Player p, Block b, int page) {
next = 1;
}
if (next != page) {
- openScriptDownloader(pl, b, next);
+ openScriptDownloader(pl, uniData, next);
}
return false;
});
menu.addItem(53, new CustomItemStack(HeadTexture.SCRIPT_LEFT.getAsItemStack(), "&6> 返回", "", "&7返回机器人控制面板"));
menu.addMenuClickHandler(53, (pl, slot, item, action) -> {
- openScriptEditor(pl, b);
+ openScriptEditor(pl, uniData);
return false;
});
@@ -487,14 +488,14 @@ protected void openScriptDownloader(Player p, Block b, int page) {
Slimefun.getLocalization().sendMessage(player, "android.scripts.rating.own", true);
} else if (script.canRate(player)) {
script.rate(player, !action.isRightClicked());
- openScriptDownloader(player, b, page);
+ openScriptDownloader(player, uniData, page);
} else {
Slimefun.getLocalization().sendMessage(player, "android.scripts.rating.already", true);
}
} else if (!action.isRightClicked()) {
script.download();
- setScript(b.getLocation(), script.getSourceCode());
- openScriptEditor(player, b);
+ setScript(uniData, script.getSourceCode());
+ openScriptEditor(player, uniData);
}
} catch (RuntimeException x) {
Slimefun.logger()
@@ -514,8 +515,8 @@ protected void openScriptDownloader(Player p, Block b, int page) {
menu.open(p);
}
- private void uploadScript(Player p, Block b, int page) {
- String code = getScript(b.getLocation());
+ private void uploadScript(Player p, SlimefunUniversalBlockData uniData, int page) {
+ String code = getScript(uniData);
int nextId = 1;
for (Script script : Script.getUploadedScripts(getAndroidType())) {
@@ -536,28 +537,23 @@ private void uploadScript(Player p, Block b, int page) {
ChatInput.waitForPlayer(Slimefun.instance(), p, msg -> {
Script.upload(p, getAndroidType(), id, msg, code);
Slimefun.getLocalization().sendMessages(p, "android.scripts.uploaded");
- openScriptDownloader(p, b, page);
+ openScriptDownloader(p, uniData, page);
});
}
- public void openScriptEditor(Player p, Block b) {
+ public void openScriptEditor(Player p, SlimefunUniversalBlockData uniData) {
ChestMenu menu =
new ChestMenu(ChatColor.DARK_AQUA + Slimefun.getLocalization().getMessage(p, "android.scripts.editor"));
menu.setEmptySlotsClickable(false);
menu.addItem(1, new CustomItemStack(HeadTexture.SCRIPT_FORWARD.getAsItemStack(), "&2> 编辑脚本", "", "&a修改你现有的脚本"));
menu.addMenuClickHandler(1, (pl, slot, item, action) -> {
- String script = StorageCacheUtils.getData(b.getLocation(), "script");
- // Fixes #2937
- if (script != null) {
- if (CommonPatterns.DASH.split(script).length <= MAX_SCRIPT_LENGTH) {
- openScript(pl, b, getScript(b.getLocation()));
- } else {
- pl.closeInventory();
- Slimefun.getLocalization().sendMessage(pl, "android.scripts.too-long");
- }
+ String script = getScript(uniData);
+ if (CommonPatterns.DASH.split(script).length <= MAX_SCRIPT_LENGTH) {
+ openScript(pl, uniData, script);
} else {
pl.closeInventory();
+ Slimefun.getLocalization().sendMessage(pl, "android.scripts.too-long");
}
return false;
});
@@ -567,7 +563,7 @@ public void openScriptEditor(Player p, Block b) {
new CustomItemStack(
HeadTexture.SCRIPT_NEW.getAsItemStack(), "§4> 创建新脚本", "", "&c删除你正在使用的脚本", "&c并创建一个全新的空白脚本"));
menu.addMenuClickHandler(3, (pl, slot, item, action) -> {
- openScript(pl, b, DEFAULT_SCRIPT);
+ openScript(pl, uniData, DEFAULT_SCRIPT);
return false;
});
@@ -580,13 +576,13 @@ public void openScriptEditor(Player p, Block b) {
"&e从服务器中下载其他玩家上传的脚本",
"&e可以即下即用, 或者修改之后再使用"));
menu.addMenuClickHandler(5, (pl, slot, item, action) -> {
- openScriptDownloader(pl, b, 1);
+ openScriptDownloader(pl, uniData, 1);
return false;
});
menu.addItem(8, new CustomItemStack(HeadTexture.SCRIPT_LEFT.getAsItemStack(), "&6> 返回", "", "&7返回机器人控制面板"));
menu.addMenuClickHandler(8, (pl, slot, item, action) -> {
- BlockMenu inv = StorageCacheUtils.getMenu(b.getLocation());
+ UniversalMenu inv = uniData.getMenu();
// Fixes #2937
if (inv != null) {
inv.open(pl);
@@ -615,7 +611,7 @@ protected List getValidScriptInstructions() {
return list;
}
- protected void editInstruction(Player p, Block b, String[] script, int index) {
+ protected void editInstruction(Player p, SlimefunUniversalBlockData uniData, String[] script, int index) {
ChestMenu menu =
new ChestMenu(ChatColor.DARK_AQUA + Slimefun.getLocalization().getMessage(p, "android.scripts.editor"));
ChestMenuUtils.drawBackground(menu, 0, 1, 2, 3, 4, 5, 6, 7, 8);
@@ -626,8 +622,8 @@ protected void editInstruction(Player p, Block b, String[] script, int index) {
new CustomItemStack(HeadTexture.SCRIPT_PAUSE.getAsItemStack(), "&f什么也不做"),
(pl, slot, item, action) -> {
String code = deleteInstruction(script, index);
- setScript(b.getLocation(), code);
- openScript(p, b, code);
+ setScript(uniData, code);
+ openScript(p, uniData, code);
return false;
});
@@ -641,8 +637,8 @@ protected void editInstruction(Player p, Block b, String[] script, int index) {
.getMessage(p, "android.scripts.instructions." + instruction.name())),
(pl, slot, item, action) -> {
String code = addInstruction(script, index, instruction);
- setScript(b.getLocation(), code);
- openScript(p, b, code);
+ setScript(uniData, code);
+ openScript(p, uniData, code);
return false;
});
@@ -652,13 +648,13 @@ protected void editInstruction(Player p, Block b, String[] script, int index) {
menu.open(p);
}
- public String getScript(Location l) {
- String script = StorageCacheUtils.getData(l, "script");
+ public String getScript(SlimefunUniversalBlockData ubd) {
+ String script = ubd.getData("script");
return script != null ? script : DEFAULT_SCRIPT;
}
- public void setScript(Location l, String script) {
- StorageCacheUtils.setData(l, "script", script);
+ public void setScript(SlimefunUniversalBlockData ubd, String script) {
+ ubd.setData("script", script);
}
private void registerDefaultFuelTypes() {
@@ -733,14 +729,14 @@ public int[] getOutputSlots() {
return new int[]{20, 21, 22, 29, 30, 31};
}
- protected void tick(Block b, SlimefunBlockData data) {
+ protected void tick(Block b, SlimefunUniversalData data) {
if (b.getType() != Material.PLAYER_HEAD) {
// The Android was destroyed or moved.
return;
}
if ("false".equals(data.getData("paused"))) {
- BlockMenu menu = data.getBlockMenu();
+ UniversalMenu menu = data.getMenu();
String fuelData = data.getData("fuel");
float fuel = fuelData == null ? 0 : Float.parseFloat(fuelData);
@@ -760,16 +756,6 @@ protected void tick(Block b, SlimefunBlockData data) {
Instruction instruction = Instruction.getInstruction(script[index]);
- if (instruction == null) {
- Slimefun.instance()
- .getLogger()
- .log(
- Level.WARNING,
- "Failed to parse Android instruction: {0}, maybe your server is out of date?",
- script[index]);
- return;
- }
-
if ("false".equals(data.getData("paused"))) {
executeInstruction(instruction, b, menu, data, index);
@@ -780,7 +766,7 @@ protected void tick(Block b, SlimefunBlockData data) {
}
private void executeInstruction(
- Instruction instruction, Block b, BlockMenu inv, SlimefunBlockData data, int index) {
+ Instruction instruction, Block b, UniversalMenu inv, SlimefunUniversalData data, int index) {
if ("true".equals(data.getData("paused"))) {
return;
}
@@ -833,7 +819,7 @@ protected void rotate(Block b, BlockFace current, int mod) {
StorageCacheUtils.setData(b.getLocation(), "rotation", rotation.name());
}
- protected void depositItems(BlockMenu menu, Block facedBlock) {
+ protected void depositItems(UniversalMenu menu, Block facedBlock) {
if (facedBlock.getType() == Material.DISPENSER
&& StorageCacheUtils.isBlock(facedBlock.getLocation(), "ANDROID_INTERFACE_ITEMS")) {
BlockState state = facedBlock.getState(false);
@@ -857,7 +843,7 @@ protected void depositItems(BlockMenu menu, Block facedBlock) {
}
}
- protected void refuel(BlockMenu menu, Block facedBlock) {
+ protected void refuel(UniversalMenu menu, Block facedBlock) {
if (facedBlock.getType() == Material.DISPENSER
&& StorageCacheUtils.isBlock(facedBlock.getLocation(), "ANDROID_INTERFACE_FUEL")) {
BlockState state = facedBlock.getState(false);
@@ -875,7 +861,7 @@ protected void refuel(BlockMenu menu, Block facedBlock) {
}
private boolean insertFuel(
- BlockMenu menu, Inventory dispenser, int slot, ItemStack currentFuel, ItemStack newFuel) {
+ UniversalMenu menu, Inventory dispenser, int slot, ItemStack currentFuel, ItemStack newFuel) {
if (currentFuel == null) {
menu.replaceExistingItem(43, newFuel);
dispenser.setItem(slot, null);
@@ -895,7 +881,7 @@ private boolean insertFuel(
return false;
}
- private void consumeFuel(Block b, BlockMenu menu) {
+ private void consumeFuel(Block b, UniversalMenu menu) {
ItemStack item = menu.getItemInSlot(43);
if (item != null && item.getType() != Material.AIR) {
@@ -915,7 +901,7 @@ private void consumeFuel(Block b, BlockMenu menu) {
}
}
- private void constructMenu(BlockMenuPreset preset) {
+ private void constructMenu(UniversalMenuPreset preset) {
preset.drawBackground(BORDER);
preset.drawBackground(ChestMenuUtils.getOutputSlotTexture(), OUTPUT_BORDER);
@@ -938,7 +924,13 @@ public boolean onClick(
}
public void addItems(Block b, ItemStack... items) {
- BlockMenu inv = StorageCacheUtils.getMenu(b.getLocation());
+ Optional uuid = Slimefun.getBlockDataService().getUniversalDataUUID(b);
+
+ if (uuid.isEmpty()) {
+ throw new IllegalStateException("Android missing uuid");
+ }
+
+ UniversalMenu inv = StorageCacheUtils.getUniversalMenu(uuid.get(), b.getLocation());
if (inv != null) {
for (ItemStack item : items) {
@@ -947,48 +939,57 @@ public void addItems(Block b, ItemStack... items) {
}
}
- protected void move(Block b, BlockFace face, Block block) {
- var blockData = StorageCacheUtils.getBlock(b.getLocation());
- OfflinePlayer owner = Bukkit.getOfflinePlayer(UUID.fromString(blockData.getData("owner")));
+ protected void move(Block from, BlockFace face, Block to) {
+ var uniData = StorageCacheUtils.getUniversalBlock(from);
+
+ OfflinePlayer owner = Bukkit.getOfflinePlayer(UUID.fromString(uniData.getData("owner")));
- if (!Slimefun.getProtectionManager().hasPermission(owner, block.getLocation(), Interaction.PLACE_BLOCK)) {
+ if (!Slimefun.getProtectionManager().hasPermission(owner, to.getLocation(), Interaction.PLACE_BLOCK)) {
return;
}
+ if (to.getY() > to.getWorld().getMinHeight()
+ && to.getY() < to.getWorld().getMaxHeight()
+ && to.isEmpty()) {
- if (block.getY() > block.getWorld().getMinHeight()
- && block.getY() < block.getWorld().getMaxHeight()
- && block.isEmpty()) {
- if (!block.getWorld().getWorldBorder().isInside(block.getLocation())) {
+ if (!to.getWorld().getWorldBorder().isInside(to.getLocation())) {
return;
}
+ Slimefun.getTickerTask().disableTicker(from.getLocation());
+
// Bro encountered a ghost 💀
- if (StorageCacheUtils.hasBlock(block.getLocation())) {
- var data = StorageCacheUtils.getBlock(block.getLocation());
+ if (StorageCacheUtils.hasBlock(to.getLocation())) {
+ var data = StorageCacheUtils.getBlock(to.getLocation());
if (data != null && !data.isPendingRemove()) {
// Since it's a ghost, we just hunt it.
- Slimefun.getDatabaseManager().getBlockDataController().removeBlock(block.getLocation());
+ Slimefun.getDatabaseManager().getBlockDataController().removeBlock(to.getLocation());
}
return;
}
- block.setBlockData(Material.PLAYER_HEAD.createBlockData(data -> {
+ to.setBlockData(Material.PLAYER_HEAD.createBlockData(data -> {
if (data instanceof Rotatable rotatable) {
rotatable.setRotation(face.getOppositeFace());
}
}));
+ Slimefun.getBlockDataService()
+ .updateUniversalDataUUID(to, uniData.getUUID().toString());
+
Slimefun.runSync(() -> {
PlayerSkin skin = PlayerSkin.fromBase64(texture);
- Material type = block.getType();
+ Material type = to.getType();
// Ensure that this Block is still a Player Head
if (type == Material.PLAYER_HEAD || type == Material.PLAYER_WALL_HEAD) {
- PlayerHead.setSkin(block, skin, true);
+ PlayerHead.setSkin(to, skin, true);
}
});
- b.setType(Material.AIR);
- Slimefun.getDatabaseManager().getBlockDataController().setBlockDataLocation(blockData, block.getLocation());
+ from.setType(Material.AIR);
+ uniData.setLastPresent(new BlockPosition(to.getLocation()));
+ uniData.getMenu().update(to.getLocation());
+
+ Slimefun.getTickerTask().enableTicker(to.getLocation(), uniData.getUUID());
}
}
@@ -996,23 +997,23 @@ protected void attack(Block b, BlockFace face, Predicate predicate
throw new UnsupportedOperationException("Non-butcher Android tried to butcher!");
}
- protected void fish(Block b, BlockMenu menu) {
+ protected void fish(Block b, UniversalMenu menu) {
throw new UnsupportedOperationException("Non-fishing Android tried to fish!");
}
- protected void dig(Block b, BlockMenu menu, Block block) {
+ protected void dig(Block b, UniversalMenu menu, Block block) {
throw new UnsupportedOperationException("Non-mining Android tried to mine!");
}
- protected void moveAndDig(Block b, BlockMenu menu, BlockFace face, Block block) {
+ protected void moveAndDig(Block b, UniversalMenu menu, BlockFace face, Block block) {
throw new UnsupportedOperationException("Non-mining Android tried to mine!");
}
- protected boolean chopTree(Block b, BlockMenu menu, BlockFace face) {
+ protected boolean chopTree(Block b, UniversalMenu menu, BlockFace face) {
throw new UnsupportedOperationException("Non-woodcutter Android tried to chop a Tree!");
}
- protected void farm(Block b, BlockMenu menu, Block block, boolean isAdvanced) {
+ protected void farm(Block b, UniversalMenu menu, Block block, boolean isAdvanced) {
throw new UnsupportedOperationException("Non-farming Android tried to farm!");
}
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/WoodcutterAndroid.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/WoodcutterAndroid.java
index f12afa964b..83a997032f 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/WoodcutterAndroid.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/WoodcutterAndroid.java
@@ -1,5 +1,6 @@
package io.github.thebusybiscuit.slimefun4.implementation.items.androids;
+import city.norain.slimefun4.api.menu.UniversalMenu;
import com.xzavier0722.mc.plugin.slimefun4.storage.util.StorageCacheUtils;
import io.github.bakedlibs.dough.blocks.Vein;
import io.github.bakedlibs.dough.protection.Interaction;
@@ -9,11 +10,11 @@
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
import io.github.thebusybiscuit.slimefun4.utils.tags.SlimefunTag;
+
import java.util.List;
import java.util.UUID;
import java.util.function.Predicate;
-import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
import org.bukkit.Bukkit;
import org.bukkit.Effect;
import org.bukkit.Material;
@@ -37,7 +38,7 @@ public AndroidType getAndroidType() {
}
@Override
- protected boolean chopTree(Block b, BlockMenu menu, BlockFace face) {
+ protected boolean chopTree(Block b, UniversalMenu menu, BlockFace face) {
Block target = b.getRelative(face);
if (!target.getWorld().getWorldBorder().isInside(target.getLocation())) {
@@ -51,8 +52,8 @@ protected boolean chopTree(Block b, BlockMenu menu, BlockFace face) {
Block log = list.get(list.size() - 1);
log.getWorld().playEffect(log.getLocation(), Effect.STEP_SOUND, log.getType());
- OfflinePlayer owner =
- Bukkit.getOfflinePlayer(UUID.fromString(StorageCacheUtils.getData(b.getLocation(), "owner")));
+ OfflinePlayer owner = Bukkit.getOfflinePlayer(
+ UUID.fromString(StorageCacheUtils.getUniversalBlock(menu.getUuid(), b.getLocation(), "owner")));
if (Slimefun.getProtectionManager().hasPermission(owner, log.getLocation(), Interaction.BREAK_BLOCK)) {
breakLog(log, b, menu, face);
}
@@ -64,7 +65,7 @@ protected boolean chopTree(Block b, BlockMenu menu, BlockFace face) {
return true;
}
- private void breakLog(Block log, Block android, BlockMenu menu, BlockFace face) {
+ private void breakLog(Block log, Block android, UniversalMenu menu, BlockFace face) {
ItemStack drop = new ItemStack(log.getType());
// We try to push the log into the android's inventory, but nothing happens if it does not fit
@@ -118,7 +119,8 @@ private void replant(Block block) {
saplingType = Material.WARPED_FUNGUS;
soilRequirement = SlimefunTag.FUNGUS_SOIL::isTagged;
}
- default -> {}
+ default -> {
+ }
}
if (Slimefun.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_19)) {
@@ -127,7 +129,8 @@ private void replant(Block block) {
saplingType = Material.MANGROVE_PROPAGULE;
soilRequirement = SlimefunTag.MANGROVE_BASE_BLOCKS::isTagged;
}
- default -> {}
+ default -> {
+ }
}
}
@@ -137,7 +140,8 @@ private void replant(Block block) {
saplingType = Material.CHERRY_SAPLING;
soilRequirement = SlimefunTag.DIRT_VARIANTS::isTagged;
}
- default -> {}
+ default -> {
+ }
}
}
@@ -147,7 +151,8 @@ private void replant(Block block) {
saplingType = Material.CHERRY_SAPLING;
soilRequirement = SlimefunTag.DIRT_VARIANTS::isTagged;
}
- default -> {}
+ default -> {
+ }
}
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/menu/AndroidShareMenu.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/menu/AndroidShareMenu.java
index 0e3a9d37c5..2d1c0d44a2 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/menu/AndroidShareMenu.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/androids/menu/AndroidShareMenu.java
@@ -34,7 +34,8 @@ public final class AndroidShareMenu {
private static final NamespacedKey BLOCK_INFO_KEY = new NamespacedKey(Slimefun.instance(), "share-users");
private static final int SHARED_USERS_LIMIT = 15;
- private AndroidShareMenu() {}
+ private AndroidShareMenu() {
+ }
/**
* Open a share menu for player.
@@ -195,7 +196,7 @@ public static List getTrustedUsers(Block b) {
/**
* Checks user is in trusted users list.
*
- * @param b the block of Android
+ * @param b the block of Android
* @param uuid user's UUID
* @return user trusted status
*/
@@ -214,15 +215,7 @@ private static void setSharedUserData(BlockState state, String value) {
PersistentDataContainer container = ((TileState) state).getPersistentDataContainer();
container.set(BLOCK_INFO_KEY, PersistentDataType.STRING, value);
state.update();
- } catch (RuntimeException x) {
- Slimefun.logger().log(Level.SEVERE, "Please check if your Server Software is up to date!");
-
- String serverSoftware = Bukkit.getName();
- Slimefun.logger()
- .log(
- Level.SEVERE,
- () -> serverSoftware + " | " + Bukkit.getVersion() + " | " + Bukkit.getBukkitVersion());
-
+ } catch (Exception x) {
Slimefun.logger()
.log(Level.SEVERE, "An Exception was thrown while trying to set Persistent Data for a Android", x);
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/autocrafters/ArmorAutoCrafter.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/autocrafters/ArmorAutoCrafter.java
index ae4de80016..ab9ce1f9fe 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/autocrafters/ArmorAutoCrafter.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/autocrafters/ArmorAutoCrafter.java
@@ -3,7 +3,7 @@
import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
-import io.github.thebusybiscuit.slimefun4.core.attributes.NotDiagonallyRotatable;
+import io.github.thebusybiscuit.slimefun4.core.attributes.rotations.NotDiagonallyRotatable;
import io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks.ArmorForge;
import org.bukkit.inventory.ItemStack;
@@ -12,12 +12,10 @@
* It can craft items that are crafted using the {@link ArmorForge}.
*
* @author TheBusyBiscuit
- *
* @see ArmorForge
* @see AbstractAutoCrafter
* @see SlimefunAutoCrafter
* @see SlimefunItemRecipe
- *
*/
public class ArmorAutoCrafter extends SlimefunAutoCrafter implements NotDiagonallyRotatable {
public ArmorAutoCrafter(ItemGroup itemGroup, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/autocrafters/EnhancedAutoCrafter.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/autocrafters/EnhancedAutoCrafter.java
index 80703f8b7f..694ba27130 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/autocrafters/EnhancedAutoCrafter.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/autocrafters/EnhancedAutoCrafter.java
@@ -3,7 +3,7 @@
import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
-import io.github.thebusybiscuit.slimefun4.core.attributes.NotDiagonallyRotatable;
+import io.github.thebusybiscuit.slimefun4.core.attributes.rotations.NotDiagonallyRotatable;
import io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks.EnhancedCraftingTable;
import io.github.thebusybiscuit.slimefun4.implementation.listeners.AutoCrafterListener;
import org.bukkit.inventory.ItemStack;
@@ -13,12 +13,10 @@
* It can craft items that are crafted using the {@link EnhancedCraftingTable}.
*
* @author TheBusyBiscuit
- *
* @see AbstractAutoCrafter
* @see VanillaAutoCrafter
* @see SlimefunItemRecipe
* @see AutoCrafterListener
- *
*/
public class EnhancedAutoCrafter extends SlimefunAutoCrafter implements NotDiagonallyRotatable {
public EnhancedAutoCrafter(ItemGroup itemGroup, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/autocrafters/VanillaAutoCrafter.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/autocrafters/VanillaAutoCrafter.java
index 1abcf1690c..1fa50137c6 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/autocrafters/VanillaAutoCrafter.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/autocrafters/VanillaAutoCrafter.java
@@ -6,7 +6,7 @@
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
-import io.github.thebusybiscuit.slimefun4.core.attributes.NotDiagonallyRotatable;
+import io.github.thebusybiscuit.slimefun4.core.attributes.rotations.NotDiagonallyRotatable;
import io.github.thebusybiscuit.slimefun4.core.services.MinecraftRecipeService;
import io.github.thebusybiscuit.slimefun4.core.services.sounds.SoundEffect;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
@@ -40,11 +40,9 @@
* Only {@link ShapedRecipe} and {@link ShapelessRecipe} are therefore supported.
*
* @author TheBusyBiscuit
- *
* @see AbstractAutoCrafter
* @see EnhancedAutoCrafter
* @see VanillaRecipe
- *
*/
public class VanillaAutoCrafter extends AbstractAutoCrafter implements NotDiagonallyRotatable {
public VanillaAutoCrafter(ItemGroup itemGroup, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/CargoConnectorNode.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/CargoConnectorNode.java
index c807bb8aac..8c68a0e653 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/CargoConnectorNode.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/CargoConnectorNode.java
@@ -3,7 +3,7 @@
import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
-import io.github.thebusybiscuit.slimefun4.core.attributes.NotRotatable;
+import io.github.thebusybiscuit.slimefun4.core.attributes.rotations.NotRotatable;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockUseHandler;
import io.github.thebusybiscuit.slimefun4.core.networks.cargo.CargoNet;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
@@ -17,10 +17,8 @@
* It has no further functionality.
*
* @author TheBusyBiscuit
- *
* @see CargoNode
* @see CargoNet
- *
*/
public class CargoConnectorNode extends SimpleSlimefunItem implements NotRotatable {
public CargoConnectorNode(
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/CargoManager.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/CargoManager.java
index e1f99a364e..0cfa4df246 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/CargoManager.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/CargoManager.java
@@ -7,7 +7,7 @@
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
import io.github.thebusybiscuit.slimefun4.core.attributes.HologramOwner;
-import io.github.thebusybiscuit.slimefun4.core.attributes.NotRotatable;
+import io.github.thebusybiscuit.slimefun4.core.attributes.rotations.NotRotatable;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockUseHandler;
import io.github.thebusybiscuit.slimefun4.core.networks.cargo.CargoNet;
@@ -80,6 +80,7 @@ public boolean isSynchronized() {
}
});
}
+
@Override
public BaseTickerTask getTickerTask() {
return Slimefun.instance().getCargoTickerTask();
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/TrashCan.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/TrashCan.java
index eed409040a..155f7ff15d 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/TrashCan.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/cargo/TrashCan.java
@@ -6,7 +6,7 @@
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
-import io.github.thebusybiscuit.slimefun4.core.attributes.NotRotatable;
+import io.github.thebusybiscuit.slimefun4.core.attributes.rotations.NotRotatable;
import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.interfaces.InventoryBlock;
import me.mrCookieSlime.Slimefun.Objects.handlers.BlockTicker;
@@ -21,7 +21,6 @@
* items that enter it.
*
* @author TheBusyBiscuit
- *
*/
public class TrashCan extends SlimefunItem implements InventoryBlock, NotRotatable {
private final int[] border = {0, 1, 2, 3, 5, 4, 6, 7, 8, 9, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26};
@@ -41,7 +40,7 @@ private void constructMenu(BlockMenuPreset preset) {
@Override
public int[] getInputSlots() {
- return new int[] {10, 11, 12, 13, 14, 15, 16};
+ return new int[]{10, 11, 12, 13, 14, 15, 16};
}
@Override
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/EnergyConnector.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/EnergyConnector.java
index 3f95172adc..d425e4316c 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/EnergyConnector.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/EnergyConnector.java
@@ -4,7 +4,7 @@
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
import io.github.thebusybiscuit.slimefun4.core.attributes.EnergyNetComponent;
-import io.github.thebusybiscuit.slimefun4.core.attributes.NotRotatable;
+import io.github.thebusybiscuit.slimefun4.core.attributes.rotations.NotRotatable;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockUseHandler;
import io.github.thebusybiscuit.slimefun4.core.networks.energy.EnergyNet;
import io.github.thebusybiscuit.slimefun4.core.networks.energy.EnergyNetComponentType;
@@ -18,10 +18,8 @@
* They work similar to {@link Capacitor capacitors}.
*
* @author Linox
- *
* @see EnergyNet
* @see EnergyNetComponent
- *
*/
public class EnergyConnector extends SimpleSlimefunItem implements EnergyNetComponent, NotRotatable {
public EnergyConnector(
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/EnergyRegulator.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/EnergyRegulator.java
index 6787a96ee1..7816741046 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/EnergyRegulator.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/EnergyRegulator.java
@@ -7,7 +7,7 @@
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
import io.github.thebusybiscuit.slimefun4.core.attributes.EnergyNetComponent;
import io.github.thebusybiscuit.slimefun4.core.attributes.HologramOwner;
-import io.github.thebusybiscuit.slimefun4.core.attributes.NotRotatable;
+import io.github.thebusybiscuit.slimefun4.core.attributes.rotations.NotRotatable;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockPlaceHandler;
import io.github.thebusybiscuit.slimefun4.core.networks.energy.EnergyNet;
@@ -22,10 +22,8 @@
* {@link EnergyNet}.
*
* @author TheBusyBiscuit
- *
* @see EnergyNet
* @see EnergyNetComponent
- *
*/
public class EnergyRegulator extends SlimefunItem implements HologramOwner, NotRotatable {
public EnergyRegulator(ItemGroup itemGroup, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/generators/CoalGenerator.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/generators/CoalGenerator.java
index 65494b09a9..9885199c9c 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/generators/CoalGenerator.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/generators/CoalGenerator.java
@@ -3,7 +3,7 @@
import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
-import io.github.thebusybiscuit.slimefun4.core.attributes.NotDiagonallyRotatable;
+import io.github.thebusybiscuit.slimefun4.core.attributes.rotations.NotDiagonallyRotatable;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.AGenerator;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.MachineFuel;
import org.bukkit.Material;
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/generators/CombustionGenerator.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/generators/CombustionGenerator.java
index 6b70d378af..235ecd2495 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/generators/CombustionGenerator.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/generators/CombustionGenerator.java
@@ -3,7 +3,7 @@
import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
-import io.github.thebusybiscuit.slimefun4.core.attributes.NotDiagonallyRotatable;
+import io.github.thebusybiscuit.slimefun4.core.attributes.rotations.NotDiagonallyRotatable;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.AGenerator;
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/generators/LavaGenerator.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/generators/LavaGenerator.java
index ddcc630e6b..ef2be7f995 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/generators/LavaGenerator.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/generators/LavaGenerator.java
@@ -3,7 +3,7 @@
import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
-import io.github.thebusybiscuit.slimefun4.core.attributes.NotDiagonallyRotatable;
+import io.github.thebusybiscuit.slimefun4.core.attributes.rotations.NotDiagonallyRotatable;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.AGenerator;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.MachineFuel;
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/generators/MagnesiumGenerator.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/generators/MagnesiumGenerator.java
index 9922664b1a..b77942ab99 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/generators/MagnesiumGenerator.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/generators/MagnesiumGenerator.java
@@ -3,7 +3,7 @@
import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
-import io.github.thebusybiscuit.slimefun4.core.attributes.NotDiagonallyRotatable;
+import io.github.thebusybiscuit.slimefun4.core.attributes.rotations.NotDiagonallyRotatable;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.AGenerator;
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/ElectricPress.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/ElectricPress.java
index 4b54dbeb17..99a3ae7fb2 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/ElectricPress.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/ElectricPress.java
@@ -4,10 +4,9 @@
import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
-import io.github.thebusybiscuit.slimefun4.core.attributes.NotDiagonallyRotatable;
import io.github.thebusybiscuit.slimefun4.core.attributes.RecipeDisplayItem;
+import io.github.thebusybiscuit.slimefun4.core.attributes.rotations.NotDiagonallyRotatable;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
-
import me.qscbm.slimefun4.items.machines.ASpeedableContainer;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
@@ -17,7 +16,6 @@
* It allows you to compact items into their block variant, e.g. 9 diamonds into a diamond block.
*
* @author TheBusyBiscuit
- *
*/
public class ElectricPress extends ASpeedableContainer implements RecipeDisplayItem, NotDiagonallyRotatable {
public ElectricPress(ItemGroup itemGroup, SlimefunItemStack item, RecipeType recipeType, ItemStack[] recipe) {
@@ -80,7 +78,7 @@ protected void registerDefaultRecipes() {
}
private void addRecipe(int seconds, ItemStack input, ItemStack output) {
- registerRecipe(seconds, new ItemStack[] {input}, new ItemStack[] {output});
+ registerRecipe(seconds, new ItemStack[]{input}, new ItemStack[]{output});
}
@Override
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/entities/ExpCollector.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/entities/ExpCollector.java
index 29816ffa38..e9b705f375 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/entities/ExpCollector.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/electric/machines/entities/ExpCollector.java
@@ -9,12 +9,13 @@
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
import io.github.thebusybiscuit.slimefun4.core.attributes.EnergyNetComponent;
-import io.github.thebusybiscuit.slimefun4.core.attributes.NotDiagonallyRotatable;
+import io.github.thebusybiscuit.slimefun4.core.attributes.rotations.NotDiagonallyRotatable;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockPlaceHandler;
import io.github.thebusybiscuit.slimefun4.core.networks.energy.EnergyNetComponentType;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
import io.github.thebusybiscuit.slimefun4.implementation.handlers.SimpleBlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.implementation.items.magical.KnowledgeFlask;
+
import java.util.Iterator;
import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.interfaces.InventoryBlock;
@@ -34,7 +35,6 @@
* and produces a {@link KnowledgeFlask}.
*
* @author TheBusyBiscuit
- *
*/
public class ExpCollector extends SlimefunItem implements InventoryBlock, EnergyNetComponent, NotDiagonallyRotatable {
private final int[] border = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26};
@@ -82,7 +82,7 @@ public int[] getInputSlots() {
@Override
public int[] getOutputSlots() {
- return new int[] {12, 13, 14};
+ return new int[]{12, 13, 14};
}
@Override
@@ -143,10 +143,8 @@ protected void tick(Block block) {
* Produces Flasks of Knowledge for the given block until it either uses all stored
* experience or runs out of room.
*
- * @param location
- * The {@link Location} of the {@link ExpCollector} to produce flasks in.
- * @param experiencePoints
- * The number of experience points to use during production.
+ * @param location The {@link Location} of the {@link ExpCollector} to produce flasks in.
+ * @param experiencePoints The number of experience points to use during production.
*/
private void produceFlasks(Location location, int experiencePoints) {
int withdrawn = 0;
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/geo/GEOMiner.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/geo/GEOMiner.java
index d3ee4e0103..39083f139e 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/geo/GEOMiner.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/geo/GEOMiner.java
@@ -13,6 +13,7 @@
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
import io.github.thebusybiscuit.slimefun4.core.attributes.*;
+import io.github.thebusybiscuit.slimefun4.core.attributes.rotations.NotDiagonallyRotatable;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockPlaceHandler;
import io.github.thebusybiscuit.slimefun4.core.machines.MachineProcessor;
@@ -21,6 +22,7 @@
import io.github.thebusybiscuit.slimefun4.implementation.handlers.SimpleBlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.implementation.operations.GEOMiningOperation;
import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
+
import java.util.LinkedList;
import java.util.List;
import java.util.OptionalInt;
@@ -43,18 +45,17 @@
* The {@link GEOMiner} is an electrical machine that allows you to obtain a {@link GEOResource}.
*
* @author TheBusyBiscuit
- *
* @see GEOResource
*/
public class GEOMiner extends SlimefunItem
implements RecipeDisplayItem,
- EnergyNetComponent,
- InventoryBlock,
- HologramOwner,
- MachineProcessHolder,
- NotDiagonallyRotatable {
+ EnergyNetComponent,
+ InventoryBlock,
+ HologramOwner,
+ MachineProcessHolder,
+ NotDiagonallyRotatable {
private static final int[] BORDER = {
- 0, 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 26, 27, 35, 36, 44, 45, 53
+ 0, 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 26, 27, 35, 36, 44, 45, 53
};
private static final int[] OUTPUT_BORDER = {19, 20, 21, 22, 23, 24, 25, 28, 34, 37, 43, 46, 47, 48, 49, 50, 51, 52};
private static final int[] OUTPUT_SLOTS = {29, 30, 31, 32, 33, 38, 39, 40, 41, 42};
@@ -115,9 +116,7 @@ public int getSpeed() {
* This method must be called before registering the item
* and only before registering.
*
- * @param capacity
- * The amount of energy this machine can store
- *
+ * @param capacity The amount of energy this machine can store
* @return This method will return the current instance of {@link GEOMiner}, so that can be chained.
*/
public final GEOMiner setCapacity(int capacity) {
@@ -132,9 +131,7 @@ public final GEOMiner setCapacity(int capacity) {
/**
* This sets the speed of this machine.
*
- * @param speed
- * The speed multiplier for this machine, must be above zero
- *
+ * @param speed The speed multiplier for this machine, must be above zero
* @return This method will return the current instance of {@link GEOMiner}, so that can be chained.
*/
public final GEOMiner setProcessingSpeed(int speed) {
@@ -145,9 +142,7 @@ public final GEOMiner setProcessingSpeed(int speed) {
/**
* This method sets the energy consumed by this machine per tick.
*
- * @param energyConsumption
- * The energy consumed per tick
- *
+ * @param energyConsumption The energy consumed per tick
* @return This method will return the current instance of {@link GEOMiner}, so that can be chained.
*/
public final GEOMiner setEnergyConsumption(int energyConsumption) {
@@ -167,8 +162,8 @@ public void register(SlimefunAddon addon) {
if (getEnergyConsumption() <= 0) {
warn("The energy consumption has not been configured correctly. The Item was disabled.");
warn("Make sure to call '"
- + getClass().getSimpleName()
- + "#setEnergyConsumption(...)' before registering!");
+ + getClass().getSimpleName()
+ + "#setEnergyConsumption(...)' before registering!");
}
if (getSpeed() <= 0) {
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/geo/GEOScanner.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/geo/GEOScanner.java
index 07d472b98f..2e087372fe 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/geo/GEOScanner.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/geo/GEOScanner.java
@@ -4,10 +4,11 @@
import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
-import io.github.thebusybiscuit.slimefun4.core.attributes.NotDiagonallyRotatable;
+import io.github.thebusybiscuit.slimefun4.core.attributes.rotations.NotDiagonallyRotatable;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockUseHandler;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
+
import java.util.Optional;
import org.bukkit.Location;
@@ -42,6 +43,6 @@ public BlockUseHandler getItemHandler() {
private boolean hasAccess(Player p, Location l) {
return p.hasPermission("slimefun.gps.bypass")
- || (Slimefun.getProtectionManager().hasPermission(p, l, Interaction.INTERACT_BLOCK));
+ || (Slimefun.getProtectionManager().hasPermission(p, l, Interaction.INTERACT_BLOCK));
}
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/geo/OilPump.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/geo/OilPump.java
index f8d51008e6..a212daaf6f 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/geo/OilPump.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/geo/OilPump.java
@@ -5,11 +5,12 @@
import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
-import io.github.thebusybiscuit.slimefun4.core.attributes.NotDiagonallyRotatable;
import io.github.thebusybiscuit.slimefun4.core.attributes.RecipeDisplayItem;
+import io.github.thebusybiscuit.slimefun4.core.attributes.rotations.NotDiagonallyRotatable;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
import io.github.thebusybiscuit.slimefun4.implementation.SlimefunItems;
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
+
import java.util.Arrays;
import java.util.List;
import java.util.OptionalInt;
@@ -47,8 +48,8 @@ public void init() {
@Override
public boolean canOpen(Block b, Player p) {
if (!(p.hasPermission("slimefun.inventory.bypass")
- || Slimefun.getProtectionManager()
- .hasPermission(p, b.getLocation(), Interaction.INTERACT_BLOCK))) {
+ || Slimefun.getProtectionManager()
+ .hasPermission(p, b.getLocation(), Interaction.INTERACT_BLOCK))) {
return false;
}
@@ -102,7 +103,7 @@ protected MachineRecipe findNextRecipe(BlockMenu inv) {
if (supplies.isPresent() && supplies.getAsInt() > 0) {
MachineRecipe recipe = new MachineRecipe(
- 26, new ItemStack[] {emptyBucket}, new ItemStack[] {SlimefunItems.OIL_BUCKET});
+ 26, new ItemStack[]{emptyBucket}, new ItemStack[]{SlimefunItems.OIL_BUCKET});
inv.consumeItem(slot);
Slimefun.getGPSNetwork()
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/gps/GPSControlPanel.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/gps/GPSControlPanel.java
index 4a9b7d54fa..78d2bcf52a 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/gps/GPSControlPanel.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/gps/GPSControlPanel.java
@@ -4,10 +4,11 @@
import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
-import io.github.thebusybiscuit.slimefun4.core.attributes.NotDiagonallyRotatable;
+import io.github.thebusybiscuit.slimefun4.core.attributes.rotations.NotDiagonallyRotatable;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockUseHandler;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
+
import java.util.Optional;
import org.bukkit.Location;
@@ -40,6 +41,6 @@ public BlockUseHandler getItemHandler() {
private boolean hasAccess(Player p, Location l) {
return p.hasPermission("slimefun.gps.bypass")
- || (Slimefun.getProtectionManager().hasPermission(p, l, Interaction.INTERACT_BLOCK));
+ || (Slimefun.getProtectionManager().hasPermission(p, l, Interaction.INTERACT_BLOCK));
}
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/gps/GPSTransmitter.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/gps/GPSTransmitter.java
index 9fe4deff8e..5e281e270d 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/gps/GPSTransmitter.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/gps/GPSTransmitter.java
@@ -7,12 +7,13 @@
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
import io.github.thebusybiscuit.slimefun4.api.recipes.RecipeType;
import io.github.thebusybiscuit.slimefun4.core.attributes.EnergyNetComponent;
-import io.github.thebusybiscuit.slimefun4.core.attributes.NotDiagonallyRotatable;
+import io.github.thebusybiscuit.slimefun4.core.attributes.rotations.NotDiagonallyRotatable;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockPlaceHandler;
import io.github.thebusybiscuit.slimefun4.core.networks.energy.EnergyNetComponentType;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
import io.github.thebusybiscuit.slimefun4.implementation.items.SimpleSlimefunItem;
+
import java.util.List;
import java.util.UUID;
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BlockListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BlockListener.java
index 776c1d0b27..6d597bb352 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BlockListener.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BlockListener.java
@@ -2,15 +2,16 @@
import com.xzavier0722.mc.plugin.slimefun4.storage.callback.IAsyncReadCallback;
import com.xzavier0722.mc.plugin.slimefun4.storage.controller.SlimefunBlockData;
+import com.xzavier0722.mc.plugin.slimefun4.storage.controller.SlimefunUniversalBlockData;
import com.xzavier0722.mc.plugin.slimefun4.storage.util.StorageCacheUtils;
import io.github.thebusybiscuit.slimefun4.api.events.ExplosiveToolBreakBlocksEvent;
import io.github.thebusybiscuit.slimefun4.api.events.SlimefunBlockBreakEvent;
import io.github.thebusybiscuit.slimefun4.api.events.SlimefunBlockPlaceEvent;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
-import io.github.thebusybiscuit.slimefun4.core.attributes.NotCardinallyRotatable;
-import io.github.thebusybiscuit.slimefun4.core.attributes.NotDiagonallyRotatable;
import io.github.thebusybiscuit.slimefun4.core.attributes.NotPlaceable;
-import io.github.thebusybiscuit.slimefun4.core.attributes.NotRotatable;
+import io.github.thebusybiscuit.slimefun4.core.attributes.rotations.NotCardinallyRotatable;
+import io.github.thebusybiscuit.slimefun4.core.attributes.rotations.NotDiagonallyRotatable;
+import io.github.thebusybiscuit.slimefun4.core.attributes.rotations.NotRotatable;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler;
import io.github.thebusybiscuit.slimefun4.core.handlers.BlockPlaceHandler;
import io.github.thebusybiscuit.slimefun4.core.handlers.ToolUseHandler;
@@ -58,7 +59,7 @@ public BlockListener(Slimefun plugin) {
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
public void onBlockPlaceExisting(BlockPlaceEvent e) {
Block block = e.getBlock();
- var loc = block.getLocation();
+ Location loc = block.getLocation();
// Fixes #2636 - This will solve the "ghost blocks" issue
if (e.getBlockReplacedState().getType().isAir()) {
@@ -106,7 +107,8 @@ public void onBlockPlace(BlockPlaceEvent e) {
if (!sfItem.canUse(e.getPlayer(), true)) {
e.setCancelled(true);
} else {
- if (e.getBlock().getBlockData() instanceof Rotatable rotatable
+ Block block = e.getBlock();
+ if (block.getBlockData() instanceof Rotatable rotatable
&& !(rotatable.getRotation() == BlockFace.UP || rotatable.getRotation() == BlockFace.DOWN)) {
BlockFace rotation = null;
@@ -124,22 +126,32 @@ public void onBlockPlace(BlockPlaceEvent e) {
if (rotation != null) {
rotatable.setRotation(rotation);
- e.getBlock().setBlockData(rotatable);
+ block.setBlockData(rotatable);
}
}
- var placeEvent = new SlimefunBlockPlaceEvent(e.getPlayer(), item, e.getBlock(), sfItem);
+ var placeEvent = new SlimefunBlockPlaceEvent(e.getPlayer(), item, block, sfItem);
Bukkit.getPluginManager().callEvent(placeEvent);
if (placeEvent.isCancelled()) {
e.setCancelled(true);
} else {
- if (Slimefun.getBlockDataService().isTileEntity(e.getBlock().getType())) {
- Slimefun.getBlockDataService().setBlockData(e.getBlock(), sfItem.getId());
+ if (Slimefun.getBlockDataService().isTileEntity(block.getType())) {
+ Slimefun.getBlockDataService().setBlockData(block, sfItem.getId());
}
- Slimefun.getDatabaseManager()
+ var data = Slimefun.getDatabaseManager()
.getBlockDataController()
- .createBlock(e.getBlock().getLocation(), sfItem.getId());
+ .createBlock(block.getLocation(), sfItem.getId());
+
+ if (data instanceof SlimefunUniversalBlockData) {
+ if (Slimefun.getBlockDataService().isTileEntity(block.getType())) {
+ Slimefun.getBlockDataService().updateUniversalDataUUID(block, data.getKey());
+ } else {
+ throw new IllegalStateException(
+ "You must use pdc support material for this Slimefun item!");
+ }
+ }
+
sfItem.callItemHandler(BlockPlaceHandler.class, handler -> handler.onPlayerPlace(e));
}
}
@@ -160,7 +172,9 @@ public void onBlockBreak(BlockBreakEvent e) {
var heldItem = e.getPlayer().getInventory().getItemInMainHand();
var block = e.getBlock();
- var blockData = StorageCacheUtils.getBlock(block.getLocation());
+ var blockData = StorageCacheUtils.hasBlock(block.getLocation())
+ ? StorageCacheUtils.getBlock(block.getLocation())
+ : StorageCacheUtils.getUniversalBlock(block);
var sfItem = blockData == null ? null : SlimefunItem.getById(blockData.getSfId());
// If there is a Slimefun Block here, call our BreakEvent and, if cancelled, cancel this event
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SlimefunItemInteractListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SlimefunItemInteractListener.java
index c30dc7aff3..60fbcbbbe9 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SlimefunItemInteractListener.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/SlimefunItemInteractListener.java
@@ -2,6 +2,8 @@
import com.xzavier0722.mc.plugin.slimefun4.storage.callback.IAsyncReadCallback;
import com.xzavier0722.mc.plugin.slimefun4.storage.controller.SlimefunBlockData;
+import com.xzavier0722.mc.plugin.slimefun4.storage.controller.SlimefunUniversalData;
+import com.xzavier0722.mc.plugin.slimefun4.storage.controller.attributes.UniversalBlock;
import com.xzavier0722.mc.plugin.slimefun4.storage.util.StorageCacheUtils;
import io.github.thebusybiscuit.slimefun4.api.events.PlayerRightClickEvent;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
@@ -11,8 +13,8 @@
import java.util.Optional;
-import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu;
import me.mrCookieSlime.Slimefun.api.inventory.BlockMenuPreset;
+import me.mrCookieSlime.Slimefun.api.inventory.DirtyChestMenu;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.block.Block;
@@ -32,11 +34,9 @@
*
* @author TheBusyBiscuit
* @author Liruxo
- *
* @see PlayerRightClickEvent
* @see ItemUseHandler
* @see BlockUseHandler
- *
*/
public class SlimefunItemInteractListener implements Listener {
public SlimefunItemInteractListener(Slimefun plugin) {
@@ -48,10 +48,7 @@ public void onRightClick(PlayerInteractEvent e) {
if (e.getAction() == Action.RIGHT_CLICK_AIR || e.getAction() == Action.RIGHT_CLICK_BLOCK) {
// Fixes #4087 - Prevents players from interacting with a block that is about to be deleted
// We especially don't want to open inventories as that can cause duplication
- if (e.getClickedBlock() != null
- && StorageCacheUtils.hasBlock(e.getClickedBlock().getLocation())
- && StorageCacheUtils.getBlock(e.getClickedBlock().getLocation())
- .isPendingRemove()) {
+ if (e.getClickedBlock() != null && StorageCacheUtils.isBlockPendingRemove(e.getClickedBlock())) {
e.setCancelled(true);
return;
}
@@ -135,31 +132,62 @@ private void openInventory(Player p, SlimefunItem item, Block clickedBlock, Play
if (!p.isSneaking() || event.getItem().getType() == Material.AIR) {
event.getInteractEvent().setCancelled(true);
- var blockData = StorageCacheUtils.getBlock(clickedBlock.getLocation());
- if (blockData == null) {
- return;
- }
+ if (item instanceof UniversalBlock) {
+ var uniData = StorageCacheUtils.getUniversalBlock(clickedBlock);
+
+ if (uniData == null) {
+ return;
+ }
+
+ if (uniData.isDataLoaded()) {
+ openMenu(uniData.getMenu(), clickedBlock, p);
+ } else {
+ Slimefun.getDatabaseManager()
+ .getBlockDataController()
+ .loadUniversalDataAsync(uniData, new IAsyncReadCallback<>() {
+ @Override
+ public boolean runOnMainThread() {
+ return true;
+ }
- if (blockData.isDataLoaded()) {
- openMenu(blockData.getBlockMenu(), clickedBlock, p);
+ @Override
+ public void onResult(SlimefunUniversalData result) {
+ if (!p.isOnline()) {
+ return;
+ }
+
+ openMenu(result.getMenu(), clickedBlock, p);
+ }
+ });
+ }
} else {
- Slimefun.getDatabaseManager()
- .getBlockDataController()
- .loadBlockDataAsync(blockData, new IAsyncReadCallback<>() {
- @Override
- public boolean runOnMainThread() {
- return true;
- }
-
- @Override
- public void onResult(SlimefunBlockData result) {
- if (!p.isOnline()) {
- return;
+ var blockData = StorageCacheUtils.getBlock(clickedBlock.getLocation());
+
+ if (blockData == null) {
+ return;
+ }
+
+ if (blockData.isDataLoaded()) {
+ openMenu(blockData.getBlockMenu(), clickedBlock, p);
+ } else {
+ Slimefun.getDatabaseManager()
+ .getBlockDataController()
+ .loadBlockDataAsync(blockData, new IAsyncReadCallback<>() {
+ @Override
+ public boolean runOnMainThread() {
+ return true;
}
- openMenu(result.getBlockMenu(), clickedBlock, p);
- }
- });
+ @Override
+ public void onResult(SlimefunBlockData result) {
+ if (!p.isOnline()) {
+ return;
+ }
+
+ openMenu(result.getBlockMenu(), clickedBlock, p);
+ }
+ });
+ }
}
}
} catch (RuntimeException | LinkageError x) {
@@ -167,7 +195,7 @@ public void onResult(SlimefunBlockData result) {
}
}
- private void openMenu(BlockMenu menu, Block b, Player p) {
+ private void openMenu(DirtyChestMenu menu, Block b, Player p) {
if (menu != null) {
if (menu.canOpen(b, p)) {
menu.open(p);
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/crafting/VanillaCrafterListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/crafting/VanillaCrafterListener.java
index d1df2bced8..4d26acf78c 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/crafting/VanillaCrafterListener.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/crafting/VanillaCrafterListener.java
@@ -5,7 +5,6 @@
import io.github.bakedlibs.dough.versions.MinecraftVersion;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
-import javax.annotation.Nonnull;
import org.bukkit.block.Crafter;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
@@ -17,7 +16,7 @@
import org.bukkit.inventory.Inventory;
public class VanillaCrafterListener implements SlimefunCraftingListener {
- public VanillaCrafterListener(@Nonnull Slimefun plugin) {
+ public VanillaCrafterListener(Slimefun plugin) {
if (SlimefunExtended.getMinecraftVersion().isAtLeast(MinecraftVersion.parse("1.20.3")))
plugin.getServer().getPluginManager().registerEvents(this, plugin);
}
@@ -28,9 +27,9 @@ public void onCrafter(InventoryClickEvent e) {
Inventory topInventory = VersionedEvent.getTopInventory(e);
if (clickedInventory != null
- && topInventory.getType() == InventoryType.CRAFTER
- && topInventory.getHolder() instanceof Crafter
- && e.getWhoClicked() instanceof Player) {
+ && topInventory.getType() == InventoryType.CRAFTER
+ && topInventory.getHolder() instanceof Crafter
+ && e.getWhoClicked() instanceof Player) {
if (e.getAction() == InventoryAction.HOTBAR_SWAP) {
e.setCancelled(true);
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/TickerTask.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/TickerTask.java
index 8abdc66f36..f2857023ed 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/TickerTask.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/tasks/TickerTask.java
@@ -1,16 +1,21 @@
package io.github.thebusybiscuit.slimefun4.implementation.tasks;
+import com.xzavier0722.mc.plugin.slimefun4.storage.controller.ASlimefunDataContainer;
import com.xzavier0722.mc.plugin.slimefun4.storage.controller.SlimefunBlockData;
+import com.xzavier0722.mc.plugin.slimefun4.storage.controller.SlimefunUniversalBlockData;
+import com.xzavier0722.mc.plugin.slimefun4.storage.controller.SlimefunUniversalData;
import com.xzavier0722.mc.plugin.slimefun4.storage.util.StorageCacheUtils;
import io.github.bakedlibs.dough.blocks.BlockPosition;
import io.github.bakedlibs.dough.blocks.ChunkPosition;
import io.github.thebusybiscuit.slimefun4.api.ErrorReport;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
+import io.github.thebusybiscuit.slimefun4.core.ticker.TickLocation;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
+import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
@@ -20,7 +25,6 @@
import me.qscbm.slimefun4.tasks.BaseTickerTask;
import org.bukkit.Chunk;
import org.bukkit.Location;
-import org.bukkit.block.Block;
import org.bukkit.scheduler.BukkitScheduler;
/**
@@ -35,7 +39,7 @@ public class TickerTask extends BaseTickerTask {
* This Map holds all currently actively ticking locations.
* The value of this map (Set entries) MUST be thread-safe and mutable.
*/
- private final Map> tickingLocations = new ConcurrentHashMap<>();
+ private final Map> tickingLocations = new ConcurrentHashMap<>();
/**
* This Map tracks how many bugs have occurred in a given Location .
@@ -93,7 +97,7 @@ public void run() {
// Run our ticker code
if (!halted) {
- for (Map.Entry> entry : tickingLocations.entrySet()) {
+ for (Map.Entry> entry : tickingLocations.entrySet()) {
tickChunk(entry.getKey(), tickers, entry.getValue());
}
}
@@ -115,12 +119,16 @@ public void run() {
}
}
- private void tickChunk(ChunkPosition chunk, Set tickers, Set locations) {
+ private void tickChunk(ChunkPosition chunk, Set tickers, Set locations) {
try {
// Only continue if the Chunk is actually loaded
if (chunk.isLoaded()) {
- for (Location l : locations) {
- tickLocation(tickers, l);
+ for (TickLocation l : locations) {
+ if (l.isUniversal()) {
+ tickUniversalLocation(l.getUuid(), l.getLocation(), tickers);
+ } else {
+ tickLocation(tickers, l.getLocation());
+ }
}
}
} catch (ArrayIndexOutOfBoundsException | NumberFormatException x) {
@@ -134,6 +142,7 @@ private void tickLocation(Set tickers, Location l) {
if (blockData == null || !blockData.isDataLoaded() || blockData.isPendingRemove()) {
return;
}
+
SlimefunItem item = SlimefunItem.getById(blockData.getSfId());
if (item != null && item.getBlockTicker() != null) {
if (item.isDisabledIn(l.getWorld())) {
@@ -152,13 +161,11 @@ private void tickLocation(Set tickers, Location l) {
if (blockData.isPendingRemove()) {
return;
}
- Block b = l.getBlock();
- tickBlock(l, b, item, blockData);
+ tickBlock(l, item, blockData);
});
} else {
item.getBlockTicker().update();
- Block b = l.getBlock();
- tickBlock(l, b, item, blockData);
+ tickBlock(l, item, blockData);
}
tickers.add(item.getBlockTicker());
@@ -170,10 +177,57 @@ private void tickLocation(Set tickers, Location l) {
disableTicker(l);
}
- private void tickBlock(Location l, Block b, SlimefunItem item, SlimefunBlockData data) {
+ private void tickUniversalLocation(UUID uuid, Location l, Set tickers) {
+ SlimefunUniversalBlockData data = StorageCacheUtils.getUniversalBlock(uuid);
+ SlimefunItem item = SlimefunItem.getById(data.getSfId());
+
+ if (item != null && item.getBlockTicker() != null) {
+ if (item.isDisabledIn(l.getWorld())) {
+ return;
+ }
+
+ try {
+ if (item.getBlockTicker().isSynchronized()) {
+ item.getBlockTicker().update();
+
+ /*
+ We are inserting a new timestamp because synchronized actions
+ are always ran with a 50ms delay (1 game tick)
+ */
+ Slimefun.runSync(() -> {
+ if (data.isPendingRemove()) {
+ return;
+ }
+ tickBlock(l, item, data);
+ });
+ } else {
+ item.getBlockTicker().update();
+ tickBlock(l, item, data);
+ }
+
+ tickers.add(item.getBlockTicker());
+ } catch (Exception x) {
+ reportErrors(l, item, x);
+ }
+ }
+ }
+
+ private void tickBlock(Location l, SlimefunItem item, ASlimefunDataContainer data) {
try {
- item.getBlockTicker().tick(b, item, data);
- } catch (RuntimeException | LinkageError x) {
+ if (item.getBlockTicker().isUniversal()) {
+ if (data instanceof SlimefunUniversalData universalData) {
+ item.getBlockTicker().tick(l.getBlock(), item, universalData);
+ } else {
+ throw new IllegalStateException("BlockTicker is universal but item is non-universal!");
+ }
+ } else {
+ if (data instanceof SlimefunBlockData blockData) {
+ item.getBlockTicker().tick(l.getBlock(), item, blockData);
+ } else {
+ throw new IllegalStateException("BlockTicker is non-universal but item is universal!");
+ }
+ }
+ } catch (Exception | LinkageError x) {
reportErrors(l, item, x);
}
}
@@ -206,7 +260,21 @@ public void halt() {
halted = true;
}
- public Map> getLocations() {
+ public Map> getLocations() {
+ return tickingLocations;
+ }
+
+
+ /**
+ * This method returns a read-only {@link Map}
+ * representation of every {@link ChunkPosition} and its corresponding
+ * {@link Set} of ticking {@link Location Locations}.
+ *
+ * This does include any {@link Location} from an unloaded {@link Chunk} too!
+ *
+ * @return A {@link Map} representation of all ticking {@link TickLocation Locations}
+ */
+ public Map> getTickLocations() {
return tickingLocations;
}
@@ -219,7 +287,7 @@ public Map> getLocations() {
* @param chunk The {@link Chunk}
* @return A {@link Set} of all ticking {@link Location Locations}
*/
- public Set getLocations(Chunk chunk) {
+ public Set getLocations(Chunk chunk) {
return tickingLocations.getOrDefault(new ChunkPosition(chunk), new HashSet<>());
}
@@ -228,28 +296,30 @@ public Set getLocations(Chunk chunk) {
*
* @param l The {@link Location} to activate
*/
- @Override
public void enableTicker(Location l) {
+ enableTicker(l, null);
+ }
+
+ public void enableTicker(Location l, UUID uuid) {
ChunkPosition chunk = new ChunkPosition(l.getWorld(), l.getBlockX() >> 4, l.getBlockZ() >> 4);
+ final TickLocation tickPosition = uuid == null
+ ? new TickLocation(new BlockPosition(l))
+ : new TickLocation(new BlockPosition(l), uuid);
+
+ /*
+ Note that all the values in #tickingLocations must be thread-safe.
+ Thus, the choice is between the CHM KeySet or a synchronized set.
+ The CHM KeySet was chosen since it at least permits multiple concurrent
+ reads without blocking.
+ */
+ Set newValue = ConcurrentHashMap.newKeySet();
+ Set oldValue = tickingLocations.putIfAbsent(chunk, newValue);
- /*
- Note that all the values in #tickingLocations must be thread-safe.
- Thus, the choice is between the CHM KeySet or a synchronized set.
- The CHM KeySet was chosen since it at least permits multiple concurrent
- reads without blocking.
- */
- Set newValue = ConcurrentHashMap.newKeySet();
- Set oldValue = tickingLocations.putIfAbsent(chunk, newValue);
-
- /*
- This is faster than doing computeIfAbsent(...)
- on a ConcurrentHashMap because it won't block the Thread for too long
- */
//noinspection ReplaceNullCheck
if (oldValue != null) {
- oldValue.add(l);
+ oldValue.add(tickPosition);
} else {
- newValue.add(l);
+ newValue.add(tickPosition);
}
}
@@ -262,14 +332,27 @@ This is faster than doing computeIfAbsent(...)
@Override
public void disableTicker(Location l) {
ChunkPosition chunk = new ChunkPosition(l.getWorld(), l.getBlockX() >> 4, l.getBlockZ() >> 4);
- Set locations = tickingLocations.get(chunk);
+ Set locations = tickingLocations.get(chunk);
if (locations != null) {
- locations.remove(l);
+ locations.removeIf(tk -> l.equals(tk.getLocation()));
if (locations.isEmpty()) {
tickingLocations.remove(chunk);
}
}
}
+
+ /**
+ * This method disables the ticker at the given {@link UUID} and removes it from our internal
+ * "queue".
+ *
+ * DO NOT USE THIS until you cannot disable by location,
+ * or enjoy extremely slow.
+ *
+ * @param uuid The {@link UUID} to remove
+ */
+ public void disableTicker(UUID uuid) {
+ tickingLocations.values().forEach(loc -> loc.removeIf(tk -> uuid.equals(tk.getUuid())));
+ }
}
diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/SlimefunUtils.java b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/SlimefunUtils.java
index 01c7a7e163..8e2ad07dd7 100644
--- a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/SlimefunUtils.java
+++ b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/SlimefunUtils.java
@@ -246,7 +246,7 @@ public static boolean isItemSimilar(@Nullable ItemStack item, @Nullable ItemStac
return isItemSimilar(item, sfitem, checkLore, checkAmount, checkDistinctiveItem, true);
}
- public static boolean isSlimefunItemSimilar(SlimefunItemStack sfItem, ItemStack item,boolean checkLore) {
+ public static boolean isSlimefunItemSimilar(SlimefunItemStack sfItem, ItemStack item, boolean checkLore) {
SlimefunItem sfI = SlimefunItem.getByItem(item);
if (sfI == null) {
return false;
@@ -262,7 +262,7 @@ public static boolean isSlimefunItemSimilar(SlimefunItemStack sfItem, ItemStack
if (lores1.size() != lores2.size()) {
return false;
}
- for (int i = 0;i> itemLore = itemMetaSnapshot.getLore();
-
- //noinspection DataFlowIssue
- if (itemMeta.hasLore() && itemLore.isPresent() && !equalsLore(itemMeta.getLore(), itemLore.get())) {
- return false;
- } else if (itemMeta.hasLore() != itemLore.isPresent()) {
return false;
+ } else if (checkLore) {
+ Optional> itemLore = itemMetaSnapshot.getLore();
+
+ //noinspection DataFlowIssue
+ if (itemMeta.hasLore() && itemLore.isPresent() && !equalsLore(itemMeta.getLore(), itemLore.get())) {
+ return false;
+ } else if (itemMeta.hasLore() != itemLore.isPresent()) {
+ return false;
+ }
}
- }
// Fixes #3133: name and lore are not enough
OptionalInt itemCustomModelData = itemMetaSnapshot.getCustomModelData();
@@ -387,20 +387,20 @@ private static boolean equalsItemMeta(ItemMeta itemMeta, ItemMeta sfitemMeta, bo
return false;
} else //noinspection DataFlowIssue
if (itemMeta.hasDisplayName() && sfitemMeta.hasDisplayName() && !itemMeta.displayName().equals(sfitemMeta.displayName())) {
- return false;
- } else if (checkLore) {
- boolean hasItemMetaLore = itemMeta.hasLore();
- boolean hasSfItemMetaLore = sfitemMeta.hasLore();
+ return false;
+ } else if (checkLore) {
+ boolean hasItemMetaLore = itemMeta.hasLore();
+ boolean hasSfItemMetaLore = sfitemMeta.hasLore();
- if (hasItemMetaLore && hasSfItemMetaLore) {
- //noinspection DataFlowIssue
- if (!equalsLoreNew(itemMeta.lore(), sfitemMeta.lore())) {
+ if (hasItemMetaLore && hasSfItemMetaLore) {
+ //noinspection DataFlowIssue
+ if (!equalsLoreNew(itemMeta.lore(), sfitemMeta.lore())) {
+ return false;
+ }
+ } else if (hasItemMetaLore != hasSfItemMetaLore) {
return false;
}
- } else if (hasItemMetaLore != hasSfItemMetaLore) {
- return false;
}
- }
if (checkCustomModelCheck) {
// Fixes #3133: name and lore are not enough
@@ -422,8 +422,8 @@ private static boolean equalsItemMeta(ItemMeta itemMeta, ItemMeta sfitemMeta, bo
//noinspection ConstantValue
return potionMeta.getBasePotionType() != null
- && sfPotionMeta.getBasePotionType() != null
- && potionMeta.getBasePotionType().equals(sfPotionMeta.getBasePotionType());
+ && sfPotionMeta.getBasePotionType() != null
+ && potionMeta.getBasePotionType().equals(sfPotionMeta.getBasePotionType());
} else if (SlimefunExtended.getMinecraftVersion().isAtLeast(1, 20, 2)) {
return potionMeta.getBasePotionType().equals(sfPotionMeta.getBasePotionType());
} else {
@@ -602,7 +602,7 @@ public static boolean canPlayerUseItem(Player p, @Nullable ItemStack item, boole
* @param reason The {@link ItemSpawnReason} why the item is being dropped
* @return The dropped {@link Item} (or null if the {@link SlimefunItemSpawnEvent} was cancelled)
*/
- public static @Nullable Item spawnItem(Location loc, ItemStack item, ItemSpawnReason reason) {
+ public static Item spawnItem(Location loc, ItemStack item, ItemSpawnReason reason) {
return spawnItem(loc, item, reason, false);
}
diff --git a/src/main/java/me/mrCookieSlime/CSCoreLibPlugin/general/Inventory/ChestMenu.java b/src/main/java/me/mrCookieSlime/CSCoreLibPlugin/general/Inventory/ChestMenu.java
index f41d270bde..1437f53482 100644
--- a/src/main/java/me/mrCookieSlime/CSCoreLibPlugin/general/Inventory/ChestMenu.java
+++ b/src/main/java/me/mrCookieSlime/CSCoreLibPlugin/general/Inventory/ChestMenu.java
@@ -3,6 +3,14 @@
import city.norain.slimefun4.holder.SlimefunInventoryHolder;
import city.norain.slimefun4.utils.InventoryUtil;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItemStack;
+import lombok.Getter;
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.entity.Player;
+import org.bukkit.event.inventory.InventoryClickEvent;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.ItemStack;
+
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -12,12 +20,6 @@
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicBoolean;
-import org.bukkit.Bukkit;
-import org.bukkit.ChatColor;
-import org.bukkit.entity.Player;
-import org.bukkit.event.inventory.InventoryClickEvent;
-import org.bukkit.inventory.Inventory;
-import org.bukkit.inventory.ItemStack;
/**
* An old remnant of CS-CoreLib.
@@ -27,7 +29,10 @@
public class ChestMenu extends SlimefunInventoryHolder {
private boolean clickable;
private boolean emptyClickable;
+
+ @Getter
private final String title;
+
private final List items;
/**
* Size of chestmenu
@@ -56,8 +61,10 @@ public ChestMenu(String title) {
this.items = new ArrayList<>();
this.handlers = new HashMap<>();
- this.open = p -> {};
- this.close = p -> {};
+ this.open = p -> {
+ };
+ this.close = p -> {
+ };
this.playerclick = (p, slot, item, action) -> isPlayerInventoryClickable();
}
@@ -375,8 +382,8 @@ public ChestMenu setSize(int size) {
} else {
throw new IllegalArgumentException(
"The size of a ChestMenu must be a multiple of 9 and within the bounds 0-54,"
- + " received: "
- + size);
+ + " received: "
+ + size);
}
}
diff --git a/src/main/java/me/mrCookieSlime/Slimefun/Objects/handlers/BlockTicker.java b/src/main/java/me/mrCookieSlime/Slimefun/Objects/handlers/BlockTicker.java
index 35a3cbdd63..0e1a6f9fe5 100644
--- a/src/main/java/me/mrCookieSlime/Slimefun/Objects/handlers/BlockTicker.java
+++ b/src/main/java/me/mrCookieSlime/Slimefun/Objects/handlers/BlockTicker.java
@@ -2,17 +2,31 @@
import com.xzavier0722.mc.plugin.slimefun4.storage.controller.BlockDataConfigWrapper;
import com.xzavier0722.mc.plugin.slimefun4.storage.controller.SlimefunBlockData;
+import com.xzavier0722.mc.plugin.slimefun4.storage.controller.SlimefunUniversalData;
import io.github.thebusybiscuit.slimefun4.api.exceptions.IncompatibleItemHandlerException;
import io.github.thebusybiscuit.slimefun4.api.items.ItemHandler;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
-import io.github.thebusybiscuit.slimefun4.core.attributes.NotPlaceable;
+
import java.util.Optional;
+
+import lombok.Getter;
import me.mrCookieSlime.CSCoreLibPlugin.Configuration.Config;
import org.bukkit.block.Block;
public abstract class BlockTicker implements ItemHandler {
+ @Getter
+ private final boolean universal;
+
protected boolean unique = true;
+ public BlockTicker() {
+ this.universal = false;
+ }
+
+ public BlockTicker(boolean universal) {
+ this.universal = universal;
+ }
+
public void update() {
if (unique) {
uniqueTick();
@@ -22,17 +36,7 @@ public void update() {
@Override
public Optional validate(SlimefunItem item) {
- if (!item.getItem().getType().isBlock()) {
- return Optional.of(new IncompatibleItemHandlerException(
- "Only Materials that are blocks can have a BlockTicker.", item, this));
- }
-
- if (item instanceof NotPlaceable) {
- return Optional.of(new IncompatibleItemHandlerException(
- "Only Slimefun items that are not marked as 'NotPlaceable' can have a BlockTicker.", item, this));
- }
-
- return Optional.empty();
+ return ItemHandler.super.validate(item);
}
/**
@@ -46,19 +50,28 @@ public Optional validate(SlimefunItem item) {
/**
* This method is called every tick for every block
*
- * @param b
- * The {@link Block} that was ticked
- * @param item
- * The corresponding {@link SlimefunItem}
- * @param data
- * The data stored in this {@link Block}
+ * @param b The {@link Block} that was ticked
+ * @param item The corresponding {@link SlimefunItem}
+ * @param data The data stored in this {@link Block}
*/
public void tick(Block b, SlimefunItem item, SlimefunBlockData data) {
tick(b, item, new BlockDataConfigWrapper(data));
}
+ /**
+ * This method is called every tick for every block
+ *
+ * @param b The {@link Block} that was ticked
+ * @param item The corresponding {@link SlimefunItem}
+ * @param data The data stored in this {@link Block}
+ */
+ public void tick(Block b, SlimefunItem item, SlimefunUniversalData data) {
+ // Override this method and fill it with content
+ }
+
@Deprecated
- public void tick(Block b, SlimefunItem item, Config data) {}
+ public void tick(Block b, SlimefunItem item, Config data) {
+ }
/**
* This method is called every tick but not per-block and only once.
diff --git a/src/main/java/me/mrCookieSlime/Slimefun/api/inventory/BlockMenuPreset.java b/src/main/java/me/mrCookieSlime/Slimefun/api/inventory/BlockMenuPreset.java
index 56f66c15c9..758a60d513 100644
--- a/src/main/java/me/mrCookieSlime/Slimefun/api/inventory/BlockMenuPreset.java
+++ b/src/main/java/me/mrCookieSlime/Slimefun/api/inventory/BlockMenuPreset.java
@@ -3,9 +3,11 @@
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils;
+
import java.util.HashSet;
import java.util.Set;
import javax.annotation.Nullable;
+
import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu;
import me.mrCookieSlime.Slimefun.api.item_transport.ItemTransportFlow;
import org.bukkit.Location;
@@ -16,12 +18,10 @@
// This class will be deprecated, relocated and rewritten in a future version.
public abstract class BlockMenuPreset extends ChestMenu {
- private final Set occupiedSlots = new HashSet<>();
+ protected final Set occupiedSlots = new HashSet<>();
private final String inventoryTitle;
private final String id;
- private boolean locked;
-
protected BlockMenuPreset(String id, String title) {
super(title);
@@ -33,10 +33,6 @@ protected BlockMenuPreset(String id, String title) {
}
private void checkIfLocked() {
- if (locked) {
- throw new UnsupportedOperationException(
- "You cannot modify the BlockMenuPreset anymore, modify the individual instances" + " instead.");
- }
}
public abstract void init();
@@ -46,11 +42,8 @@ private void checkIfLocked() {
* {@link BlockMenu} of that {@link Block}.
* Override this as necessary.
*
- * @param b
- * The {@link Block} trying to be opened
- * @param p
- * The {@link Player} who wants to open the {@link BlockMenu}
- *
+ * @param b The {@link Block} trying to be opened
+ * @param p The {@link Player} who wants to open the {@link BlockMenu}
* @return Whether that {@link Player} is allowed
*/
public abstract boolean canOpen(Block b, Player p);
@@ -61,12 +54,11 @@ private void checkIfLocked() {
* This method is called whenever an {@link ItemStack} changes.
* You can override this as necessary if you need to listen to these events
*
- * @param next
- * The {@link ItemStack} that it changes to
- *
+ * @param next The {@link ItemStack} that it changes to
* @return The new outcome of this operation
*/
- @Nullable protected ItemStack onItemStackChange(
+ @Nullable
+ protected ItemStack onItemStackChange(
@Nullable ItemStack next) {
// Override this as necessary
return next;
@@ -89,10 +81,8 @@ public void replaceExistingItem(int slot, ItemStack item) {
/**
* This method will draw unclickable background items into this {@link BlockMenuPreset}.
*
- * @param item
- * The {@link ItemStack} that should be used as background
- * @param slots
- * The slots which should be treated as background
+ * @param item The {@link ItemStack} that should be used as background
+ * @param slots The slots which should be treated as background
*/
public void drawBackground(ItemStack item, int[] slots) {
checkIfLocked();
@@ -105,8 +95,7 @@ public void drawBackground(ItemStack item, int[] slots) {
/**
* This method will draw unclickable background items into this {@link BlockMenuPreset}.
*
- * @param slots
- * The slots which should be treated as background
+ * @param slots The slots which should be treated as background
*/
public void drawBackground(int[] slots) {
drawBackground(ChestMenuUtils.getBackground(), slots);
@@ -193,8 +182,6 @@ protected void clone(DirtyChestMenu menu) {
public void newInstance(BlockMenu menu, Location l) {
Slimefun.runSync(() -> {
- locked = true;
-
try {
newInstance(menu, l.getBlock());
} catch (RuntimeException | LinkageError x) {
@@ -224,7 +211,8 @@ public SlimefunItem getSlimefunItem() {
return SlimefunItem.getById(id);
}
- @Nullable public static BlockMenuPreset getPreset(@Nullable String id) {
+ @Nullable
+ public static BlockMenuPreset getPreset(@Nullable String id) {
return id == null ? null : Slimefun.getRegistry().getMenuPresets().get(id);
}
diff --git a/src/main/java/me/mrCookieSlime/Slimefun/api/inventory/DirtyChestMenu.java b/src/main/java/me/mrCookieSlime/Slimefun/api/inventory/DirtyChestMenu.java
index 301fa275fc..b184625e56 100644
--- a/src/main/java/me/mrCookieSlime/Slimefun/api/inventory/DirtyChestMenu.java
+++ b/src/main/java/me/mrCookieSlime/Slimefun/api/inventory/DirtyChestMenu.java
@@ -8,6 +8,7 @@
import io.github.thebusybiscuit.slimefun4.utils.SlimefunUtils;
import io.github.thebusybiscuit.slimefun4.utils.itemstack.ItemStackWrapper;
import lombok.Getter;
+
import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu;
import org.bukkit.Material;
import org.bukkit.block.Block;
@@ -80,9 +81,9 @@ public void close() {
}
public boolean fits(ItemStack item, int... slots) {
- var isSfItem = SlimefunItem.getByItem(item) != null;
- var wrapper = ItemStackWrapper.wrap(item);
- var remain = item.getAmount();
+ boolean isSfItem = SlimefunItem.getByItem(item) != null;
+ ItemStackWrapper wrapper = ItemStackWrapper.wrap(item);
+ int remain = item.getAmount();
for (int slot : slots) {
// A small optimization for empty slots
@@ -234,36 +235,20 @@ public void consumeItem(int slot) {
}
public void consumeItem(int slot, int amount) {
- if (locked()) {
- throw new IllegalStateException("Cannot consume item when menu is locked");
- }
-
consumeItem(slot, amount, false);
}
public void consumeItem(int slot, int amount, boolean replaceConsumables) {
- if (locked()) {
- throw new IllegalStateException("Cannot consume item when menu is locked");
- }
-
ItemUtils.consumeItem(getItemInSlot(slot), amount, replaceConsumables);
markDirty();
}
@Override
public void replaceExistingItem(int slot, ItemStack item) {
- if (locked()) {
- throw new IllegalStateException("Cannot consume item when menu is locked");
- }
-
replaceExistingItem(slot, item, true);
}
public void replaceExistingItem(int slot, ItemStack item, boolean event) {
- if (locked()) {
- throw new IllegalStateException("Cannot consume item when menu is locked");
- }
-
if (event) {
item = preset.onItemStackChange(item);
}
diff --git a/src/main/java/me/qscbm/slimefun4/message/QsTextComponentImpl.java b/src/main/java/me/qscbm/slimefun4/message/QsTextComponentImpl.java
index 8cd496cf97..7c5418f7f9 100644
--- a/src/main/java/me/qscbm/slimefun4/message/QsTextComponentImpl.java
+++ b/src/main/java/me/qscbm/slimefun4/message/QsTextComponentImpl.java
@@ -7,7 +7,6 @@
import net.kyori.adventure.text.format.Style;
import net.kyori.adventure.text.format.TextColor;
-import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
@@ -44,7 +43,7 @@ public String content() {
}
@Override
- public QsTextComponentImpl append(final @NotNull ComponentLike like) {
+ public QsTextComponentImpl append(final ComponentLike like) {
final Component component = like.asComponent();
if (component == Component.empty()) return this;
if (children.equals(Collections.emptyList())) {
@@ -54,7 +53,7 @@ public QsTextComponentImpl append(final @NotNull ComponentLike like) {
return this;
}
- public QsTextComponentImpl append(final @NotNull QsTextComponentImpl like) {
+ public QsTextComponentImpl append(final QsTextComponentImpl like) {
if (children.equals(Collections.emptyList())) {
children = new ArrayList<>();
}
diff --git a/src/main/java/me/qscbm/slimefun4/utils/CacheMap.java b/src/main/java/me/qscbm/slimefun4/utils/CacheMap.java
index 7de2c39213..3dc06d1fd5 100644
--- a/src/main/java/me/qscbm/slimefun4/utils/CacheMap.java
+++ b/src/main/java/me/qscbm/slimefun4/utils/CacheMap.java
@@ -1,11 +1,10 @@
package me.qscbm.slimefun4.utils;
-import javax.annotation.Nonnull;
import java.util.concurrent.ConcurrentHashMap;
-public class CacheMap extends ConcurrentHashMap {
+public class CacheMap extends ConcurrentHashMap {
@Override
- public String put(@Nonnull String key, String value) {
+ public String put(String key, String value) {
if (value == null) {
value = "";
}
@@ -13,7 +12,7 @@ public String put(@Nonnull String key, String value) {
}
@Override
- public String putIfAbsent(@Nonnull String key, String value) {
+ public String putIfAbsent(String key, String value) {
if (value == null) {
value = "";
}