9
0
mirror of https://github.com/Xiao-MoMi/Custom-Fishing.git synced 2026-01-06 15:51:50 +00:00

checkpoint - 14

This commit is contained in:
XiaoMoMi
2024-06-13 02:08:42 +08:00
parent ccbfa68e04
commit 29ca35a031
38 changed files with 980 additions and 577 deletions

View File

@@ -41,6 +41,7 @@ import org.bukkit.plugin.java.JavaPlugin;
import java.io.InputStream;
import java.nio.file.Path;
import java.util.List;
import java.util.function.Consumer;
public class BukkitCustomFishingPluginImpl extends BukkitCustomFishingPlugin {
@@ -48,6 +49,7 @@ public class BukkitCustomFishingPluginImpl extends BukkitCustomFishingPlugin {
private final PluginLogger logger;
private ChatCatcherManager chatCatcherManager;
private BukkitCommandManager commandManager;
private Consumer<String> debugger;
public BukkitCustomFishingPluginImpl(Plugin boostrap) {
super(boostrap);
@@ -56,6 +58,7 @@ public class BukkitCustomFishingPluginImpl extends BukkitCustomFishingPlugin {
this.classPathAppender = new ReflectionClassPathAppender(this);
this.logger = new JavaPluginLogger(getBoostrap().getLogger());
this.dependencyManager = new DependencyManagerImpl(this);
this.debugger = (s) -> {};
}
@Override
@@ -72,10 +75,11 @@ public class BukkitCustomFishingPluginImpl extends BukkitCustomFishingPlugin {
Dependency.JEDIS,
Dependency.EXP4J,
Dependency.MYSQL_DRIVER, Dependency.MARIADB_DRIVER,
Dependency.SQLITE_DRIVER,
Dependency.SQLITE_DRIVER, Dependency.SLF4J_API, Dependency.SLF4J_SIMPLE,
Dependency.H2_DRIVER,
Dependency.MONGODB_DRIVER_CORE, Dependency.MONGODB_DRIVER_SYNC, Dependency.MONGODB_DRIVER_BSON,
Dependency.HIKARI_CP)
Dependency.HIKARI_CP
)
);
}
@@ -118,24 +122,38 @@ public class BukkitCustomFishingPluginImpl extends BukkitCustomFishingPlugin {
@Override
public void reload() {
ItemType.reset();
this.eventManager.reload();
this.configManager.reload();
this.requirementManager.reload();
this.actionManager.reload();
this.itemManager.unload();
this.eventManager.unload();
this.entityManager.unload();
this.lootManager.unload();
this.blockManager.unload();
this.effectManager.unload();
this.hookManager.unload();
// before ConfigManager
this.placeholderManager.reload();
this.itemManager.reload();
this.competitionManager.reload();
this.marketManager.reload();
this.storageManager.reload();
this.lootManager.reload();
this.configManager.reload();
// after ConfigManager
this.debugger = ConfigManager.debug() ? logger::info : (s) -> {};
this.actionManager.reload();
this.requirementManager.reload();
this.coolDownManager.reload();
this.entityManager.reload();
this.blockManager.reload();
this.statisticsManager.reload();
this.effectManager.reload();
this.hookManager.reload();
this.bagManager.reload();
this.translationManager.reload();
this.marketManager.reload();
this.competitionManager.reload();
this.statisticsManager.reload();
this.bagManager.reload();
this.storageManager.reload();
this.itemManager.load();
this.eventManager.load();
this.entityManager.load();
this.lootManager.load();
this.blockManager.load();
this.effectManager.load();
this.hookManager.load();
}
@Override
@@ -192,6 +210,11 @@ public class BukkitCustomFishingPluginImpl extends BukkitCustomFishingPlugin {
return getBoostrap().getDescription().getVersion();
}
@Override
public void debug(String message) {
this.debugger.accept(message);
}
public ChatCatcherManager getChatCatcherManager() {
return chatCatcherManager;
}

View File

@@ -17,12 +17,16 @@
package net.momirealms.customfishing.bukkit.bag;
import dev.dejvokep.boostedyaml.block.implementation.Section;
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
import net.momirealms.customfishing.api.mechanic.action.Action;
import net.momirealms.customfishing.api.mechanic.bag.BagManager;
import net.momirealms.customfishing.api.mechanic.bag.FishingBagHolder;
import net.momirealms.customfishing.api.mechanic.config.ConfigManager;
import net.momirealms.customfishing.api.mechanic.effect.EffectModifier;
import net.momirealms.customfishing.api.mechanic.item.ItemType;
import net.momirealms.customfishing.api.mechanic.requirement.Requirement;
import net.momirealms.customfishing.api.storage.user.UserData;
import net.momirealms.customfishing.bukkit.config.BukkitConfigManager;
import net.momirealms.customfishing.common.helper.AdventureHelper;
import net.momirealms.sparrow.heart.SparrowHeart;
import org.bukkit.Bukkit;
import org.bukkit.Material;
@@ -37,16 +41,19 @@ import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.*;
import java.util.concurrent.CompletableFuture;
public class BukkitBagManager implements BagManager, Listener {
private final BukkitCustomFishingPlugin plugin;
private final HashMap<UUID, UserData> tempEditMap;
private Action<Player>[] collectLootActions;
private Action<Player>[] bagFullActions;
private boolean bagStoreLoots;
private String bagTitle;
private List<Material> bagWhiteListItems = new ArrayList<>();
private Requirement<Player>[] collectRequirements;
public BukkitBagManager(BukkitCustomFishingPlugin plugin) {
this.plugin = plugin;
@@ -55,6 +62,7 @@ public class BukkitBagManager implements BagManager, Listener {
@Override
public void load() {
this.loadConfig();
Bukkit.getPluginManager().registerEvents(this, plugin.getBoostrap());
}
@@ -69,40 +77,33 @@ public class BukkitBagManager implements BagManager, Listener {
this.plugin.getStorageManager().getDataSource().updateManyPlayersData(tempEditMap.values(), true);
}
private void loadConfig() {
Section config = BukkitConfigManager.getMainConfig().getSection("mechanics.fishing-bag");
bagTitle = config.getString("bag-title", "");
bagStoreLoots = config.getBoolean("can-store-loot", false);
bagWhiteListItems = config.getStringList("whitelist-items").stream().map(it -> Material.valueOf(it.toUpperCase(Locale.ENGLISH))).toList();
collectLootActions = plugin.getActionManager().parseActions(config.getSection("collect-actions"));
bagFullActions = plugin.getActionManager().parseActions(config.getSection("full-actions"));
collectRequirements = plugin.getRequirementManager().parseRequirements(config.getSection("collect-requirements"), false);
}
@Override
public CompletableFuture<Boolean> openBag(Player viewer, UUID owner) {
CompletableFuture<Boolean> future = new CompletableFuture<>();
Optional<UserData> onlineUser = plugin.getStorageManager().getOnlineUser(owner);
onlineUser.ifPresentOrElse(data -> {
viewer.openInventory(data.holder().getInventory());
SparrowHeart.getInstance().updateInventoryTitle(viewer,
plugin.getPlaceholderManager().parse(
Bukkit.getOfflinePlayer(owner),
ConfigManager.bagTitle(),
Map.of(
"{uuid}", owner.toString(),
"{player}", data.name()
)
)
);
SparrowHeart.getInstance().updateInventoryTitle(viewer, AdventureHelper.componentToJson(AdventureHelper.miniMessage(plugin.getPlaceholderManager().parse(Bukkit.getOfflinePlayer(owner), bagTitle, Map.of("{uuid}", owner.toString(), "{player}", data.name())))));
future.complete(true);
}, () -> plugin.getStorageManager().getOfflineUserData(owner, true).thenAccept(result -> result.ifPresentOrElse(data -> {
if (data.isLocked()) {
future.complete(false);
future.completeExceptionally(new RuntimeException("Data is locked"));
return;
}
this.tempEditMap.put(viewer.getUniqueId(), data);
viewer.openInventory(data.holder().getInventory());
SparrowHeart.getInstance().updateInventoryTitle(viewer,
plugin.getPlaceholderManager().parse(
Bukkit.getOfflinePlayer(owner),
ConfigManager.bagTitle(),
Map.of(
"{uuid}", owner.toString(),
"{player}", data.name()
)
)
);
SparrowHeart.getInstance().updateInventoryTitle(viewer, AdventureHelper.componentToJson(AdventureHelper.miniMessage(plugin.getPlaceholderManager().parse(Bukkit.getOfflinePlayer(owner), bagTitle, Map.of("{uuid}", owner.toString(), "{player}", data.name())))));
future.complete(true);
}, () -> future.complete(false))));
return future;
@@ -130,32 +131,37 @@ public class BukkitBagManager implements BagManager, Listener {
*
* @param event The InventoryClickEvent triggered when an item is clicked in an inventory.
*/
@EventHandler
@EventHandler (ignoreCancelled = true)
public void onInvClick(InventoryClickEvent event) {
if (event.isCancelled())
return;
if (!(event.getInventory().getHolder() instanceof FishingBagHolder))
return;
ItemStack movedItem = event.getCurrentItem();
Inventory clicked = event.getClickedInventory();
if (clicked != event.getWhoClicked().getInventory()) {
if (event.getAction() != InventoryAction.HOTBAR_SWAP
&& event.getAction() != InventoryAction.HOTBAR_MOVE_AND_READD
) {
if (event.getAction() != InventoryAction.HOTBAR_SWAP && event.getAction() != InventoryAction.HOTBAR_MOVE_AND_READD) {
return;
}
movedItem = event.getWhoClicked().getInventory().getItem(event.getHotbarButton());
}
if (movedItem == null || movedItem.getType() == Material.AIR)
return;
if (ConfigManager.bagWhiteListItems().contains(movedItem.getType()))
if (movedItem == null || movedItem.getType() == Material.AIR || bagWhiteListItems.contains(movedItem.getType()))
return;
String id = plugin.getItemManager().getItemID(movedItem);
Optional<EffectModifier> optionalEffectModifier = plugin.getEffectManager().getEffectModifier(id);
if (optionalEffectModifier.isPresent())
ItemType type = ItemType.getTypeByID(id);
if (type == null) {
event.setCancelled(true);
return;
if (ConfigManager.bagStoreLoots() && plugin.getLootManager().getLoot(id).isPresent())
}
if (type == ItemType.LOOT && bagStoreLoots)
return;
if (type == ItemType.BAIT || type == ItemType.ROD || type == ItemType.UTIL || type == ItemType.HOOK)
return;
event.setCancelled(true);
}

View File

@@ -26,7 +26,11 @@ public class BukkitCommandManager extends AbstractCommandManager<CommandSender>
new StopCompetitionCommand(this),
new StartCompetitionCommand(this),
new OpenMarketCommand(this),
new OpenBagCommand(this)
new OpenBagCommand(this),
new FishingBagCommand(this),
new GUIEditorCommand(this),
new EditOnlineBagCommand(this),
new EditOfflineBagCommand(this)
);
private final Index<String, CommandFeature<CommandSender>> INDEX = Index.create(CommandFeature::getFeatureID, FEATURES);

View File

@@ -0,0 +1,46 @@
package net.momirealms.customfishing.bukkit.command.feature;
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
import net.momirealms.customfishing.bukkit.command.BukkitCommandFeature;
import net.momirealms.customfishing.common.command.CustomFishingCommandManager;
import net.momirealms.customfishing.common.locale.MessageConstants;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.incendo.cloud.Command;
import org.incendo.cloud.CommandManager;
import org.incendo.cloud.parser.standard.UUIDParser;
import java.util.UUID;
public class EditOfflineBagCommand extends BukkitCommandFeature<CommandSender> {
public EditOfflineBagCommand(CustomFishingCommandManager<CommandSender> commandManager) {
super(commandManager);
}
@Override
public Command.Builder<? extends CommandSender> assembleCommand(CommandManager<CommandSender> manager, Command.Builder<CommandSender> builder) {
return builder
.senderType(Player.class)
.required("uuid", UUIDParser.uuidParser())
.handler(context -> {
Player admin = context.sender();
UUID uuid = context.get("uuid");
BukkitCustomFishingPlugin.getInstance().getBagManager().openBag(admin, uuid).whenComplete((result, throwable) -> {
if (throwable != null) {
handleFeedback(context, MessageConstants.COMMAND_BAG_EDIT_FAILURE_UNSAFE);
return;
}
if (!result) {
handleFeedback(context, MessageConstants.COMMAND_BAG_EDIT_FAILURE_NEVER_PLAYED);
return;
}
});
});
}
@Override
public String getFeatureID() {
return "edit_offline_bag";
}
}

View File

@@ -0,0 +1,34 @@
package net.momirealms.customfishing.bukkit.command.feature;
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
import net.momirealms.customfishing.bukkit.command.BukkitCommandFeature;
import net.momirealms.customfishing.common.command.CustomFishingCommandManager;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.incendo.cloud.Command;
import org.incendo.cloud.CommandManager;
import org.incendo.cloud.bukkit.parser.PlayerParser;
public class EditOnlineBagCommand extends BukkitCommandFeature<CommandSender> {
public EditOnlineBagCommand(CustomFishingCommandManager<CommandSender> commandManager) {
super(commandManager);
}
@Override
public Command.Builder<? extends CommandSender> assembleCommand(CommandManager<CommandSender> manager, Command.Builder<CommandSender> builder) {
return builder
.senderType(Player.class)
.required("player", PlayerParser.playerParser())
.handler(context -> {
Player admin = context.sender();
Player online = context.get("player");
BukkitCustomFishingPlugin.getInstance().getBagManager().openBag(admin, online.getUniqueId());
});
}
@Override
public String getFeatureID() {
return "edit_online_bag";
}
}

View File

@@ -0,0 +1,28 @@
package net.momirealms.customfishing.bukkit.command.feature;
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
import net.momirealms.customfishing.bukkit.command.BukkitCommandFeature;
import net.momirealms.customfishing.common.command.CustomFishingCommandManager;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.incendo.cloud.Command;
import org.incendo.cloud.CommandManager;
public class FishingBagCommand extends BukkitCommandFeature<CommandSender> {
public FishingBagCommand(CustomFishingCommandManager<CommandSender> commandManager) {
super(commandManager);
}
@Override
public Command.Builder<? extends CommandSender> assembleCommand(CommandManager<CommandSender> manager, Command.Builder<CommandSender> builder) {
return builder
.senderType(Player.class)
.handler(context -> BukkitCustomFishingPlugin.getInstance().getBagManager().openBag(context.sender(), context.sender().getUniqueId()));
}
@Override
public String getFeatureID() {
return "fishingbag";
}
}

View File

@@ -0,0 +1,33 @@
package net.momirealms.customfishing.bukkit.command.feature;
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
import net.momirealms.customfishing.bukkit.command.BukkitCommandFeature;
import net.momirealms.customfishing.bukkit.gui.page.file.FileSelector;
import net.momirealms.customfishing.common.command.CustomFishingCommandManager;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.incendo.cloud.Command;
import org.incendo.cloud.CommandManager;
import java.io.File;
public class GUIEditorCommand extends BukkitCommandFeature<CommandSender> {
public GUIEditorCommand(CustomFishingCommandManager<CommandSender> commandManager) {
super(commandManager);
}
@Override
public Command.Builder<? extends CommandSender> assembleCommand(CommandManager<CommandSender> manager, Command.Builder<CommandSender> builder) {
return builder
.senderType(Player.class)
.handler(context -> {
new FileSelector(context.sender(), new File(BukkitCustomFishingPlugin.getInstance().getDataFolder(), "contents"));
});
}
@Override
public String getFeatureID() {
return "browser";
}
}

View File

@@ -14,9 +14,7 @@ import org.bukkit.inventory.ItemStack;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.Command;
import org.incendo.cloud.CommandManager;
import org.incendo.cloud.bukkit.data.MultiplePlayerSelector;
import org.incendo.cloud.bukkit.parser.PlayerParser;
import org.incendo.cloud.bukkit.parser.selector.MultiplePlayerSelectorParser;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.context.CommandInput;
import org.incendo.cloud.parser.standard.IntegerParser;

View File

@@ -2,7 +2,6 @@ package net.momirealms.customfishing.bukkit.command.feature;
import net.kyori.adventure.text.Component;
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
import net.momirealms.customfishing.api.mechanic.competition.FishingCompetition;
import net.momirealms.customfishing.bukkit.command.BukkitCommandFeature;
import net.momirealms.customfishing.common.command.CustomFishingCommandManager;
import net.momirealms.customfishing.common.locale.MessageConstants;

View File

@@ -44,8 +44,6 @@ import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import static java.util.Objects.requireNonNull;
public class BukkitCompetitionManager implements CompetitionManager {
private final BukkitCustomFishingPlugin plugin;
@@ -75,7 +73,7 @@ public class BukkitCompetitionManager implements CompetitionManager {
if (this.timerCheckTask != null)
this.timerCheckTask.cancel();
if (currentCompetition != null && currentCompetition.isOnGoing())
currentCompetition.stop(true);
this.currentCompetition.stop(true);
this.commandConfigMap.clear();
this.timeConfigMap.clear();
}
@@ -84,7 +82,7 @@ public class BukkitCompetitionManager implements CompetitionManager {
if (this.timerCheckTask != null)
this.timerCheckTask.cancel();
if (currentCompetition != null && currentCompetition.isOnGoing())
currentCompetition.stop(false);
this.currentCompetition.stop(false);
this.commandConfigMap.clear();
this.timeConfigMap.clear();
}

View File

@@ -47,8 +47,52 @@ public class BukkitConfigManager extends ConfigManager {
@Override
public void load() {
this.loadConfigs();
MAIN_CONFIG = loadConfig("config.yml");
this.loadSettings();
this.loadConfigs();
}
private void loadSettings() {
YamlDocument config = getMainConfig();
metrics = config.getBoolean("metrics", true);
checkUpdate = config.getBoolean("update-checker", true);
debug = config.getBoolean("debug", false);
overrideVanillaWaitTime = config.getBoolean("mechanics.fishing-wait-time.override-vanilla", false);
waterMinTime = config.getInt("mechanics.fishing-wait-time.min-wait-time", 100);
waterMaxTime = config.getInt("mechanics.fishing-wait-time.max-wait-time", 600);
lavaMinTime = config.getInt("mechanics.lava-fishing.min-wait-time", 100);
lavaMaxTime = config.getInt("mechanics.lava-fishing.max-wait-time", 600);
restrictedSizeRange = config.getBoolean("mechanics.size.restricted-size-range", true);
placeholderLimit = config.getInt("mechanics.competition.placeholder-limit", 3);
serverGroup = config.getString("mechanics.competition.server-group", "default");
redisRanking = config.getBoolean("mechanics.competition.redis-ranking", false);
AdventureHelper.legacySupport = config.getBoolean("other-settings.legacy-color-code-support", true);
dataSaveInterval = config.getInt("other-settings.data-save-interval", 600);
logDataSaving = config.getBoolean("other-settings.log-data-saving", true);
lockData = config.getBoolean("other-settings.lock-data", true);
durabilityLore = new ArrayList<>(config.getStringList("other-settings.custom-durability-format"));
itemDetectOrder = config.getStringList("other-settings.item-detection-order").toArray(new String[0]);
blockDetectOrder = config.getStringList("other-settings.block-detection-order").toArray(new String[0]);
allowMultipleTotemType = config.getBoolean("mechanics.totem.allow-multiple-type", true);
allowSameTotemType = config.getBoolean("mechanics.totem.allow-same-type", false);
Section placeholderSection = config.getSection("other-settings.placeholder-register");
if (placeholderSection != null) {
for (Map.Entry<String, Object> entry : placeholderSection.getStringRouteMappedValues(false).entrySet()) {
if (entry.getValue() instanceof String original) {
plugin.getPlaceholderManager().registerCustomPlaceholder(entry.getKey(), original);
}
}
}
}
private void loadConfigs() {

View File

@@ -33,10 +33,16 @@ public class BukkitEffectManager implements EffectManager {
this.plugin = plugin;
}
public void disable() {
@Override
public void unload() {
this.effectModifiers.clear();
}
@Override
public void load() {
}
@Override
public boolean registerEffectModifier(EffectModifier effect) {
if (effectModifiers.containsKey(effect.id())) return false;

View File

@@ -72,11 +72,13 @@ public class BukkitItemManager implements ItemManager, Listener {
@Override
public void unload() {
HandlerList.unregisterAll(this);
this.items.clear();
}
@Override
public void load() {
Bukkit.getPluginManager().registerEvents(this, plugin.getBoostrap());
this.resetItemDetectionOrder();
}
@Override

View File

@@ -24,6 +24,17 @@ public class BukkitLootManager implements LootManager {
this.plugin = plugin;
}
@Override
public void unload() {
this.lootMap.clear();
this.groupMembersMap.clear();
}
@Override
public void load() {
}
@Override
public void registerLoot(@NotNull Loot loot) {
this.lootMap.put(loot.id(), loot);

View File

@@ -17,12 +17,10 @@
package net.momirealms.customfishing.bukkit.market;
import dev.dejvokep.boostedyaml.YamlDocument;
import dev.dejvokep.boostedyaml.block.implementation.Section;
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
import net.momirealms.customfishing.api.mechanic.action.Action;
import net.momirealms.customfishing.api.mechanic.action.ActionManager;
import net.momirealms.customfishing.api.mechanic.config.ConfigManager;
import net.momirealms.customfishing.api.mechanic.config.GUIItemParser;
import net.momirealms.customfishing.api.mechanic.context.Context;
import net.momirealms.customfishing.api.mechanic.context.ContextKeys;
@@ -56,12 +54,11 @@ import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
@SuppressWarnings("DuplicatedCode")
public class BukkitMarketManager implements MarketManager, Listener {
private final BukkitCustomFishingPlugin plugin;
private boolean enable;
private final HashMap<String, MathValue<Player>> priceMap;
private String formula;
private MathValue<Player> earningsLimit;
@@ -108,7 +105,6 @@ public class BukkitMarketManager implements MarketManager, Listener {
public void load() {
this.loadConfig();
Bukkit.getPluginManager().registerEvents(this, plugin.getBoostrap());
if (!enable) return;
this.resetEarningsTask = plugin.getScheduler().asyncRepeating(() -> {
int now = getRealTimeDate();
if (this.cachedDate != now) {
@@ -365,7 +361,7 @@ public class BukkitMarketManager implements MarketManager, Listener {
}
} else if (element.getSymbol() == sellAllSlot) {
ArrayList<ItemStack> itemStacksToSell = new ArrayList<>(List.of(gui.context.getHolder().getInventory().getStorageContents()));
if (sellFishingBag && ConfigManager.enableFishingBag()) {
if (sellFishingBag) {
Optional<UserData> optionalUserData = BukkitCustomFishingPlugin.getInstance().getStorageManager().getOnlineUser(gui.context.getHolder().getUniqueId());
optionalUserData.ifPresent(userData -> itemStacksToSell.addAll(List.of(userData.holder().getInventory().getStorageContents())));
}
@@ -441,6 +437,7 @@ public class BukkitMarketManager implements MarketManager, Listener {
}
@Override
@SuppressWarnings("UnstableApiUsage")
public double getItemPrice(Context<Player> context, ItemStack itemStack) {
if (itemStack == null || itemStack.getType() == Material.AIR)
return 0;
@@ -500,6 +497,7 @@ public class BukkitMarketManager implements MarketManager, Listener {
return Pair.of(amount, worth);
}
@SuppressWarnings("UnstableApiUsage")
public void clearWorthyItems(Context<Player> context, List<ItemStack> itemStacks) {
for (ItemStack itemStack : itemStacks) {
double price = getItemPrice(context, itemStack);

View File

@@ -18,7 +18,6 @@
package net.momirealms.customfishing.bukkit.market;
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
import net.momirealms.customfishing.api.mechanic.config.ConfigManager;
import net.momirealms.customfishing.api.mechanic.context.Context;
import net.momirealms.customfishing.api.mechanic.context.ContextKeys;
import net.momirealms.customfishing.api.mechanic.market.MarketGUIHolder;
@@ -37,6 +36,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.*;
@SuppressWarnings("DuplicatedCode")
public class MarketGUI {
private final HashMap<Character, MarketGUIElement> itemsCharMap;
@@ -109,7 +109,6 @@ public class MarketGUI {
* Refresh the GUI, updating the display based on current data.
* @return The MarketGUI instance.
*/
@SuppressWarnings("DuplicatedCode")
public MarketGUI refresh() {
double earningLimit = manager.earningLimit(context);
MarketDynamicGUIElement sellElement = (MarketDynamicGUIElement) getElement(manager.sellSlot);
@@ -134,7 +133,7 @@ public class MarketGUI {
MarketDynamicGUIElement sellAllElement = (MarketDynamicGUIElement) getElement(manager.sellAllSlot);
if (sellAllElement != null && !sellAllElement.getSlots().isEmpty()) {
ArrayList<ItemStack> itemStacksToSell = new ArrayList<>(List.of(context.getHolder().getInventory().getStorageContents()));
if (manager.sellFishingBag && ConfigManager.enableFishingBag()) {
if (manager.sellFishingBag) {
Optional<UserData> optionalUserData = BukkitCustomFishingPlugin.getInstance().getStorageManager().getOnlineUser(context.getHolder().getUniqueId());
optionalUserData.ifPresent(userData -> itemStacksToSell.addAll(List.of(userData.holder().getInventory().getStorageContents())));
}

View File

@@ -121,7 +121,9 @@ public class MongoDBProvider extends AbstractStorage {
if (doc == null) {
if (Bukkit.getPlayer(uuid) != null) {
if (lock) lockOrUnlockPlayerData(uuid, true);
future.complete(Optional.of(PlayerData.empty()));
var data = PlayerData.empty();
data.uuid(uuid);
future.complete(Optional.of(data));
} else {
future.complete(Optional.empty());
}

View File

@@ -144,6 +144,7 @@ public abstract class AbstractSQLDatabase extends AbstractStorage {
} else if (Bukkit.getPlayer(uuid) != null) {
// the player is online
var data = PlayerData.empty();
data.uuid(uuid);
insertPlayerData(uuid, data, lock);
future.complete(Optional.of(data));
} else {

View File

@@ -21,7 +21,6 @@ import dev.dejvokep.boostedyaml.YamlDocument;
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
import net.momirealms.customfishing.api.storage.StorageType;
import net.momirealms.customfishing.common.dependency.Dependency;
import org.h2.jdbcx.JdbcConnectionPool;
import java.io.File;
import java.lang.reflect.Method;

View File

@@ -127,6 +127,7 @@ public class SQLiteProvider extends AbstractSQLDatabase {
future.complete(Optional.of(data));
} else if (Bukkit.getPlayer(uuid) != null) {
var data = PlayerData.empty();
data.uuid(uuid);
insertPlayerData(uuid, data, lock);
future.complete(Optional.of(data));
} else {

View File

@@ -60,6 +60,7 @@ public class JsonProvider extends AbstractStorage {
playerData = readFromJsonFile(file, PlayerData.class);
} else if (Bukkit.getPlayer(uuid) != null) {
playerData = PlayerData.empty();
playerData.uuid(uuid);
} else {
playerData = null;
}

View File

@@ -64,7 +64,9 @@ public class YAMLProvider extends AbstractStorage {
File dataFile = getPlayerDataFile(uuid);
if (!dataFile.exists()) {
if (Bukkit.getPlayer(uuid) != null) {
return CompletableFuture.completedFuture(Optional.of(PlayerData.empty()));
var data = PlayerData.empty();
data.uuid(uuid);
return CompletableFuture.completedFuture(Optional.of(data));
} else {
return CompletableFuture.completedFuture(Optional.empty());
}

View File

@@ -1,86 +1,87 @@
///*
// * Copyright (C) <2022> <XiaoMoMi>
// *
// * This program is free software: you can redistribute it and/or modify
// * it under the terms of the GNU General Public License as published by
// * the Free Software Foundation, either version 3 of the License, or
// * any later version.
// *
// * This program is distributed in the hope that it will be useful,
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// * GNU General Public License for more details.
// *
// * You should have received a copy of the GNU General Public License
// * along with this program. If not, see <https://www.gnu.org/licenses/>.
// */
//
//package net.momirealms.customfishing.bukkit.totem;
//
//import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
//import net.momirealms.customfishing.api.mechanic.action.Action;
//import net.momirealms.customfishing.api.mechanic.action.ActionTrigger;
//import net.momirealms.customfishing.api.mechanic.totem.TotemConfig;
//import net.momirealms.customfishing.api.mechanic.totem.TotemParticle;
//import net.momirealms.customfishing.common.plugin.scheduler.SchedulerTask;
//import org.bukkit.Location;
//
//import java.util.ArrayList;
//import java.util.HashMap;
//import java.util.List;
//
//public class ActivatedTotem {
//
// private final List<SchedulerTask> subTasks;
// private final Location coreLocation;
// private final TotemConfig totemConfig;
// private final long expireTime;
// private final EffectCarrier effectCarrier;
//
// public ActivatedTotem(Location coreLocation, TotemConfig config) {
// this.subTasks = new ArrayList<>();
// this.expireTime = System.currentTimeMillis() + config.getDuration() * 1000L;
// this.coreLocation = coreLocation.clone().add(0.5,0,0.5);
// this.totemConfig = config;
// this.effectCarrier = BukkitCustomFishingPlugin.get().getEffectManager().getEffectCarrier("totem", config.getKey());
// for (TotemParticle particleSetting : config.getParticleSettings()) {
// this.subTasks.add(particleSetting.start(coreLocation, config.getRadius()));
// }
// }
//
// public TotemConfig getTotemConfig() {
// return totemConfig;
// }
//
// public Location getCoreLocation() {
// return coreLocation;
// }
//
// public void cancel() {
// for (CancellableTask task : subTasks) {
// task.cancel();
// }
// }
//
// public long getExpireTime() {
// return expireTime;
// }
//
// public void doTimerAction() {
// HashMap<String, String> args = new HashMap<>();
// args.put("{time_left}", String.valueOf((expireTime - System.currentTimeMillis())/1000));
// PlayerContext playerContext = new PlayerContext(coreLocation, null, args);
// if (effectCarrier != null) {
// Action[] actions = effectCarrier.getActions(ActionTrigger.TIMER);
// if (actions != null) {
// for (Action action : actions) {
// action.trigger(playerContext);
// }
// }
// }
// }
//
// public EffectCarrier getEffectCarrier() {
// return effectCarrier;
// }
//}
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customfishing.bukkit.totem;
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
import net.momirealms.customfishing.api.mechanic.action.ActionTrigger;
import net.momirealms.customfishing.api.mechanic.context.Context;
import net.momirealms.customfishing.api.mechanic.context.ContextKeys;
import net.momirealms.customfishing.api.mechanic.totem.TotemConfig;
import net.momirealms.customfishing.api.mechanic.totem.TotemParticle;
import net.momirealms.customfishing.common.plugin.scheduler.SchedulerTask;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
public class ActivatedTotem {
private final List<SchedulerTask> subTasks;
private final Location coreLocation;
private final TotemConfig totemConfig;
private final long expireTime;
private final Context<Player> context;
private final double radius;
public ActivatedTotem(Player activator, Location coreLocation, TotemConfig config) {
this.context = Context.player(activator, true)
.arg(ContextKeys.LOCATION, coreLocation)
.arg(ContextKeys.X, coreLocation.getBlockX())
.arg(ContextKeys.Y, coreLocation.getBlockY())
.arg(ContextKeys.Z, coreLocation.getBlockZ())
.arg(ContextKeys.ID, config.id());
this.subTasks = new ArrayList<>();
this.expireTime = (long) (System.currentTimeMillis() + config.duration().evaluate(context) * 1000L);
this.coreLocation = coreLocation.clone().add(0.5,0,0.5);
this.totemConfig = config;
this.radius = config.duration().evaluate(context);
for (TotemParticle particleSetting : config.particleSettings()) {
this.subTasks.add(particleSetting.start(coreLocation, radius));
}
}
public TotemConfig getTotemConfig() {
return totemConfig;
}
public Location getCoreLocation() {
return coreLocation;
}
public void cancel() {
for (SchedulerTask task : this.subTasks) {
task.cancel();
}
this.subTasks.clear();
}
public long getExpireTime() {
return this.expireTime;
}
public double getRadius() {
return radius;
}
public void doTimerAction() {
this.context.arg(ContextKeys.TIME_LEFT, String.valueOf((expireTime - System.currentTimeMillis())/1000));
BukkitCustomFishingPlugin.getInstance().getEventManager().getEventCarrier(totemConfig.id())
.ifPresent(carrier -> carrier.trigger(context, ActionTrigger.TIMER));
}
}

View File

@@ -17,357 +17,406 @@
package net.momirealms.customfishing.bukkit.totem;
import dev.dejvokep.boostedyaml.YamlDocument;
import dev.dejvokep.boostedyaml.block.implementation.Section;
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
import net.momirealms.customfishing.api.mechanic.config.ConfigManager;
import net.momirealms.customfishing.api.mechanic.misc.value.MathValue;
import net.momirealms.customfishing.api.mechanic.totem.TotemConfig;
import net.momirealms.customfishing.api.mechanic.totem.TotemManager;
import net.momirealms.customfishing.api.mechanic.totem.TotemModel;
import net.momirealms.customfishing.api.mechanic.totem.block.TotemBlock;
import net.momirealms.customfishing.api.mechanic.totem.block.property.AxisImpl;
import net.momirealms.customfishing.api.mechanic.totem.block.property.FaceImpl;
import net.momirealms.customfishing.api.mechanic.totem.block.property.HalfImpl;
import net.momirealms.customfishing.api.mechanic.totem.block.property.TotemBlockProperty;
import net.momirealms.customfishing.api.mechanic.totem.block.type.TypeCondition;
import net.momirealms.customfishing.api.util.SimpleLocation;
import net.momirealms.customfishing.bukkit.totem.particle.DustParticleSetting;
import net.momirealms.customfishing.bukkit.totem.particle.ParticleSetting;
import net.momirealms.customfishing.bukkit.util.LocationUtils;
import net.momirealms.customfishing.common.plugin.scheduler.SchedulerTask;
import net.momirealms.customfishing.common.util.Pair;
import org.bukkit.*;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.Bisected;
import org.bukkit.event.EventHandler;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.EquipmentSlot;
import java.io.File;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
public class BukkitTotemManager implements TotemManager, Listener {
// private final BukkitCustomFishingPlugin plugin;
// private final HashMap<String, List<TotemConfig>> totemConfigMap;
// private final List<String> allMaterials;
// private final ConcurrentHashMap<SimpleLocation, ActivatedTotem> activatedTotems;
// private SchedulerTask timerCheckTask;
//
// public BukkitTotemManager(BukkitCustomFishingPlugin plugin) {
// this.plugin = plugin;
// this.totemConfigMap = new HashMap<>();
// this.allMaterials = Arrays.stream(Material.values()).map(Enum::name).toList();
// this.activatedTotems = new ConcurrentHashMap<>();
// }
//
// @Override
// public void load() {
// this.loadConfig();
// Bukkit.getPluginManager().registerEvents(this, plugin.getBoostrap());
// this.timerCheckTask = plugin.getScheduler().asyncRepeating(() -> {
// long time = System.currentTimeMillis();
// ArrayList<SimpleLocation> removed = new ArrayList<>();
// for (Map.Entry<SimpleLocation, ActivatedTotem> entry : activatedTotems.entrySet()) {
// if (time > entry.getValue().getExpireTime()) {
// removed.add(entry.getKey());
// entry.getValue().cancel();
// } else {
// entry.getValue().doTimerAction();
// }
// }
// for (SimpleLocation simpleLocation : removed) {
// activatedTotems.remove(simpleLocation);
// }
// }, 1, 1, TimeUnit.SECONDS);
// }
//
// @Override
// public void unload() {
// HandlerList.unregisterAll(this);
// for (ActivatedTotem activatedTotem : this.activatedTotems.values())
// activatedTotem.cancel();
// this.activatedTotems.clear();
// if (this.timerCheckTask != null)
// this.timerCheckTask.cancel();
// this.totemConfigMap.clear();
// }
//
//// /**
//// * Get the EffectCarrier associated with an activated totem located near the specified location.
//// *
//// * @param location The location to search for activated totems.
//// * @return The EffectCarrier associated with the nearest activated totem or null if none are found.
//// */
//// @Override
//// @Nullable
//// public EffectCarrier getTotemEffect(Location location) {
//// for (ActivatedTotem activatedTotem : activatedTotems.values()) {
//// if (LocationUtils.getDistance(activatedTotem.getCoreLocation(), location) < activatedTotem.getTotemConfig().radius()) {
//// return activatedTotem.getEffectCarrier();
//// }
//// }
//// return null;
//// }
//
// @EventHandler
// public void onBreakTotemCore(BlockBreakEvent event) {
// if (event.isCancelled())
// return;
// Location location = event.getBlock().getLocation();
// SimpleLocation simpleLocation = SimpleLocation.of(location);
// ActivatedTotem activatedTotem = activatedTotems.remove(simpleLocation);
// if (activatedTotem != null)
// activatedTotem.cancel();
// }
//
// @EventHandler
// public void onInteractBlock(PlayerInteractEvent event) {
// if (event.isBlockInHand())
// return;
// if (event.useItemInHand() == Event.Result.DENY)
// return;
// if (event.getAction() != org.bukkit.event.block.Action.RIGHT_CLICK_BLOCK)
// return;
// if (event.getHand() != EquipmentSlot.HAND)
// return;
// Block block = event.getClickedBlock();
// assert block != null;
// String id = plugin.getBlockManager().getBlockID(block);
// List<TotemConfig> configs = totemConfigMap.get(id);
// if (configs == null)
// return;
// TotemConfig config = null;
// for (TotemConfig temp : configs) {
// if (temp.isRightPattern(block.getLocation())) {
// config = temp;
// break;
// }
// }
// if (config == null)
// return;
// }
//
// @SuppressWarnings("DuplicatedCode")
// private void loadConfig() {
// Deque<File> fileDeque = new ArrayDeque<>();
// for (String type : List.of("totem")) {
// File typeFolder = new File(plugin.getDataFolder() + File.separator + "contents" + File.separator + type);
// if (!typeFolder.exists()) {
// if (!typeFolder.mkdirs()) return;
// plugin.getBoostrap().saveResource("contents" + File.separator + type + File.separator + "default.yml", false);
// }
// fileDeque.push(typeFolder);
// while (!fileDeque.isEmpty()) {
// File file = fileDeque.pop();
// File[] files = file.listFiles();
// if (files == null) continue;
// for (File subFile : files) {
// if (subFile.isDirectory()) {
// fileDeque.push(subFile);
// } else if (subFile.isFile() && subFile.getName().endsWith(".yml")) {
// this.loadSingleFile(subFile);
// }
// }
// }
// }
// }
//
// private void loadSingleFile(File file) {
//// YamlConfiguration config = YamlConfiguration.loadConfiguration(file);
//// for (Map.Entry<String, Object> entry : config.getValues(false).entrySet()) {
//// if (entry.getValue() instanceof ConfigurationSection section) {
//// TotemConfig totemConfig = new TotemConfig.Builder(entry.getKey())
//// .setTotemModels(getTotemModels(section.getConfigurationSection("pattern")))
//// .setParticleSettings(getParticleSettings(section.getConfigurationSection("particles")))
//// .setRequirements(plugin.getRequirementManager().parseRequirements(section.getConfigurationSection("requirements"), true))
//// .setRadius(section.getDouble("radius", 8))
//// .setDuration(section.getInt("duration", 300))
//// .build();
////
//// HashSet<String> coreMaterials = new HashSet<>();
//// for (TotemBlock totemBlock : totemConfig.getTotemCore()) {
//// String text = totemBlock.getTypeCondition().getRawText();
//// if (text.startsWith("*")) {
//// String sub = text.substring(1);
//// coreMaterials.addAll(allMaterials.stream().filter(it -> it.endsWith(sub)).toList());
//// } else if (text.endsWith("*")) {
//// String sub = text.substring(0, text.length() - 1);
//// coreMaterials.addAll(allMaterials.stream().filter(it -> it.startsWith(sub)).toList());
//// } else {
//// coreMaterials.add(text);
//// }
//// }
//// for (String material : coreMaterials) {
//// putTotemConfigToMap(material, totemConfig);
//// }
//// }
//// }
// }
//
// private void putTotemConfigToMap(String material, TotemConfig totemConfig) {
// List<TotemConfig> configs = this.totemConfigMap.getOrDefault(material, new ArrayList<>());
// configs.add(totemConfig);
// this.totemConfigMap.put(material, configs);
// }
//
//// public ParticleSetting[] getParticleSettings(ConfigurationSection section) {
//// List<ParticleSetting> particleSettings = new ArrayList<>();
//// if (section != null)
//// for (Map.Entry<String, Object> entry : section.getValues(false).entrySet()) {
//// if (entry.getValue() instanceof ConfigurationSection innerSection) {
//// particleSettings.add(getParticleSetting(innerSection));
//// }
//// }
//// return particleSettings.toArray(new ParticleSetting[0]);
//// }
//
//// public ParticleSetting getParticleSetting(ConfigurationSection section) {
//// Particle particle = Particle.valueOf(section.getString("type","REDSTONE"));
//// String formulaHorizontal = section.getString("polar-coordinates-formula.horizontal");
//// String formulaVertical = section.getString("polar-coordinates-formula.vertical");
//// List<Pair<Double, Double>> ranges = section.getStringList("theta.range")
//// .stream().map(it -> {
//// String[] split = it.split("~");
//// return Pair.of(Double.parseDouble(split[0]) * Math.PI / 180, Double.parseDouble(split[1]) * Math.PI / 180);
//// }).toList();
////
//// double interval = section.getDouble("theta.draw-interval", 3d);
//// int delay = section.getInt("task.delay", 0);
//// int period = section.getInt("task.period", 0);
//// if (particle == Particle.REDSTONE) {
//// String color = section.getString("options.color","0,0,0");
//// String[] colorSplit = color.split(",");
//// return new DustParticleSetting(
//// formulaHorizontal,
//// formulaVertical,
//// particle,
//// interval,
//// ranges,
//// delay,
//// period,
//// new Particle.DustOptions(
//// Color.fromRGB(
//// Integer.parseInt(colorSplit[0]),
//// Integer.parseInt(colorSplit[1]),
//// Integer.parseInt(colorSplit[2])
//// ),
//// (float) section.getDouble("options.scale", 1)
//// )
//// );
//// } else if (particle == Particle.DUST_COLOR_TRANSITION) {
//// String color = section.getString("options.from","0,0,0");
//// String[] colorSplit = color.split(",");
//// String toColor = section.getString("options.to","255,255,255");
//// String[] toColorSplit = toColor.split(",");
//// return new DustParticleSetting(
//// formulaHorizontal,
//// formulaVertical,
//// particle,
//// interval,
//// ranges,
//// delay,
//// period,
//// new Particle.DustTransition(
//// Color.fromRGB(
//// Integer.parseInt(colorSplit[0]),
//// Integer.parseInt(colorSplit[1]),
//// Integer.parseInt(colorSplit[2])
//// ),
//// Color.fromRGB(
//// Integer.parseInt(toColorSplit[0]),
//// Integer.parseInt(toColorSplit[1]),
//// Integer.parseInt(toColorSplit[2])
//// ),
//// (float) section.getDouble("options.scale", 1)
//// )
//// );
//// } else {
//// return new ParticleSetting(
//// formulaHorizontal,
//// formulaVertical,
//// particle,
//// interval,
//// ranges,
//// delay,
//// period
//// );
//// }
//// }
//
// public TotemModel[] getTotemModels(ConfigurationSection section) {
// TotemModel originalModel = parseModel(section);
// List<TotemModel> modelList = new ArrayList<>();
// for (int i = 0; i < 4; i++) {
// originalModel = originalModel.deepClone().rotate90();
// modelList.add(originalModel);
// if (i % 2 == 0) {
// modelList.add(originalModel.mirrorVertically());
// } else {
// modelList.add(originalModel.mirrorHorizontally());
// }
// }
// return modelList.toArray(new TotemModel[0]);
// }
//
// @SuppressWarnings("unchecked")
// public TotemModel parseModel(ConfigurationSection section) {
// ConfigurationSection layerSection = section.getConfigurationSection("layer");
// List<TotemBlock[][][]> totemBlocksList = new ArrayList<>();
// if (layerSection != null) {
// var set = layerSection.getValues(false).entrySet();
// TotemBlock[][][][] totemBlocks = new TotemBlock[set.size()][][][];
// for (Map.Entry<String, Object> entry : set) {
// if (entry.getValue() instanceof List<?> list) {
// totemBlocks[Integer.parseInt(entry.getKey())-1] = parseLayer((List<String>) list);
// }
// }
// totemBlocksList.addAll(List.of(totemBlocks));
// }
//
// String[] core = section.getString("core","1,1,1").split(",");
// int x = Integer.parseInt(core[2]) - 1;
// int z = Integer.parseInt(core[1]) - 1;
// int y = Integer.parseInt(core[0]) - 1;
// return new TotemModel(
// x,y,z,
// totemBlocksList.toArray(new TotemBlock[0][][][])
// );
// }
//
// public TotemBlock[][][] parseLayer(List<String> lines) {
// List<TotemBlock[][]> totemBlocksList = new ArrayList<>();
// for (String line : lines) {
// totemBlocksList.add(parseSingleLine(line));
// }
// return totemBlocksList.toArray(new TotemBlock[0][][]);
// }
//
// public TotemBlock[][] parseSingleLine(String line) {
// List<TotemBlock[]> totemBlocksList = new ArrayList<>();
// String[] splits = line.split("\\s+");
// for (String split : splits) {
// totemBlocksList.add(parseSingleElement(split));
// }
// return totemBlocksList.toArray(new TotemBlock[0][]);
// }
//
// public TotemBlock[] parseSingleElement(String element) {
// String[] orBlocks = element.split("\\|\\|");
// List<TotemBlock> totemBlockList = new ArrayList<>();
// for (String block : orBlocks) {
// int index = block.indexOf("{");
// List<TotemBlockProperty> propertyList = new ArrayList<>();
// if (index == -1) {
// index = block.length();
// } else {
// String propertyStr = block.substring(index+1, block.length()-1);
// String[] properties = propertyStr.split(";");
// for (String property : properties) {
// String[] split = property.split("=");
// if (split.length < 2) continue;
// String key = split[0];
// String value = split[1];
// switch (key) {
// // Block face
// case "face" -> {
// BlockFace blockFace = BlockFace.valueOf(value.toUpperCase(Locale.ENGLISH));
// propertyList.add(new FaceImpl(blockFace));
// }
// // Block axis
// case "axis" -> {
// Axis axis = Axis.valueOf(value.toUpperCase(Locale.ENGLISH));
// propertyList.add(new AxisImpl(axis));
// }
// // Slab, Stair half
// case "half" -> {
// Bisected.Half half = Bisected.Half.valueOf(value.toUpperCase(Locale.ENGLISH));
// propertyList.add(new HalfImpl(half));
// }
// }
// }
// }
// String type = block.substring(0, index);
// TotemBlock totemBlock = new TotemBlock(
// TypeCondition.getTypeCondition(type),
// propertyList.toArray(new TotemBlockProperty[0])
// );
// totemBlockList.add(totemBlock);
// }
// return totemBlockList.toArray(new TotemBlock[0]);
// }
private final BukkitCustomFishingPlugin plugin;
private final HashMap<String, List<TotemConfig>> totemConfigMap;
private final List<String> allMaterials;
private final ConcurrentHashMap<SimpleLocation, ActivatedTotem> activatedTotems;
private SchedulerTask timerCheckTask;
public BukkitTotemManager(BukkitCustomFishingPlugin plugin) {
this.plugin = plugin;
this.totemConfigMap = new HashMap<>();
this.allMaterials = Arrays.stream(Material.values()).map(Enum::name).toList();
this.activatedTotems = new ConcurrentHashMap<>();
}
@Override
public void load() {
this.loadConfig();
Bukkit.getPluginManager().registerEvents(this, plugin.getBoostrap());
this.timerCheckTask = plugin.getScheduler().asyncRepeating(() -> {
long time = System.currentTimeMillis();
ArrayList<SimpleLocation> removed = new ArrayList<>();
for (Map.Entry<SimpleLocation, ActivatedTotem> entry : activatedTotems.entrySet()) {
if (time > entry.getValue().getExpireTime()) {
removed.add(entry.getKey());
entry.getValue().cancel();
} else {
entry.getValue().doTimerAction();
}
}
for (SimpleLocation simpleLocation : removed) {
activatedTotems.remove(simpleLocation);
}
}, 1, 1, TimeUnit.SECONDS);
}
@Override
public void unload() {
HandlerList.unregisterAll(this);
for (ActivatedTotem activatedTotem : this.activatedTotems.values())
activatedTotem.cancel();
this.activatedTotems.clear();
if (this.timerCheckTask != null)
this.timerCheckTask.cancel();
this.totemConfigMap.clear();
}
@Override
public Collection<String> getActivatedTotems(Location location) {
Collection<String> activated = new ArrayList<>();
double nearest = Double.MAX_VALUE;
String nearestTotemID = null;
for (ActivatedTotem activatedTotem : activatedTotems.values()) {
double distance = LocationUtils.getDistance(activatedTotem.getCoreLocation(), location);
if (distance < activatedTotem.getRadius()) {
activated.add(activatedTotem.getTotemConfig().id());
if (nearest > distance) {
nearest = distance;
nearestTotemID = activatedTotem.getTotemConfig().id();
}
}
}
if (nearestTotemID == null) return List.of();
if (!ConfigManager.allowMultipleTotemType()) {
if (ConfigManager.allowSameTotemType()) {
String finalNearestTotemID = nearestTotemID;
activated.removeIf(element -> !element.equals(finalNearestTotemID));
return activated;
} else {
return List.of(nearestTotemID);
}
} else {
if (ConfigManager.allowSameTotemType()) {
return activated;
} else {
return new HashSet<>(activated);
}
}
}
@EventHandler
public void onBreakTotemCore(BlockBreakEvent event) {
if (event.isCancelled())
return;
Location location = event.getBlock().getLocation();
SimpleLocation simpleLocation = SimpleLocation.of(location);
ActivatedTotem activatedTotem = activatedTotems.remove(simpleLocation);
if (activatedTotem != null)
activatedTotem.cancel();
}
@EventHandler (ignoreCancelled = true)
public void onInteractBlock(PlayerInteractEvent event) {
if (
event.isBlockInHand() ||
event.getAction() != org.bukkit.event.block.Action.RIGHT_CLICK_BLOCK ||
event.getHand() != EquipmentSlot.HAND
)
return;
Block block = event.getClickedBlock();
assert block != null;
String id = plugin.getBlockManager().getBlockID(block);
List<TotemConfig> configs = totemConfigMap.get(id);
if (configs == null)
return;
TotemConfig config = null;
for (TotemConfig temp : configs) {
if (temp.isRightPattern(block.getLocation())) {
config = temp;
break;
}
}
if (config == null)
return;
}
@SuppressWarnings("DuplicatedCode")
private void loadConfig() {
Deque<File> fileDeque = new ArrayDeque<>();
for (String type : List.of("totem")) {
File typeFolder = new File(plugin.getBoostrap().getDataFolder() + File.separator + "contents" + File.separator + type);
if (!typeFolder.exists()) {
if (!typeFolder.mkdirs()) return;
plugin.getBoostrap().saveResource("contents" + File.separator + type + File.separator + "default.yml", false);
}
fileDeque.push(typeFolder);
while (!fileDeque.isEmpty()) {
File file = fileDeque.pop();
File[] files = file.listFiles();
if (files == null) continue;
for (File subFile : files) {
if (subFile.isDirectory()) {
fileDeque.push(subFile);
} else if (subFile.isFile() && subFile.getName().endsWith(".yml")) {
this.loadSingleFile(subFile);
}
}
}
}
}
private void loadSingleFile(File file) {
YamlDocument config = plugin.getConfigManager().loadData(file);
for (Map.Entry<String, Object> entry : config.getStringRouteMappedValues(false).entrySet()) {
if (entry.getValue() instanceof Section section) {
TotemConfig totemConfig = TotemConfig.builder()
.id(entry.getKey())
.totemModels(getTotemModels(section.getSection("pattern")))
.activateRequirements(plugin.getRequirementManager().parseRequirements(section.getSection("requirements"), true))
.radius(MathValue.auto(section.get("radius", 8.0)))
.duration(MathValue.auto(section.get("duration", 100)))
.particleSettings(getParticleSettings(section.getSection("particles")))
.build();
HashSet<String> coreMaterials = new HashSet<>();
for (TotemBlock totemBlock : totemConfig.totemCore()) {
String text = totemBlock.getTypeCondition().getRawText();
if (text.startsWith("*")) {
String sub = text.substring(1);
coreMaterials.addAll(allMaterials.stream().filter(it -> it.endsWith(sub)).toList());
} else if (text.endsWith("*")) {
String sub = text.substring(0, text.length() - 1);
coreMaterials.addAll(allMaterials.stream().filter(it -> it.startsWith(sub)).toList());
} else {
coreMaterials.add(text);
}
}
for (String material : coreMaterials) {
putTotemConfigToMap(material, totemConfig);
}
}
}
}
private void putTotemConfigToMap(String material, TotemConfig totemConfig) {
List<TotemConfig> configs = this.totemConfigMap.getOrDefault(material, new ArrayList<>());
configs.add(totemConfig);
this.totemConfigMap.put(material, configs);
}
public ParticleSetting[] getParticleSettings(Section section) {
List<ParticleSetting> particleSettings = new ArrayList<>();
if (section != null)
for (Map.Entry<String, Object> entry : section.getStringRouteMappedValues(false).entrySet()) {
if (entry.getValue() instanceof Section innerSection) {
particleSettings.add(getParticleSetting(innerSection));
}
}
return particleSettings.toArray(new ParticleSetting[0]);
}
public ParticleSetting getParticleSetting(Section section) {
Particle particle = Particle.valueOf(section.getString("type","REDSTONE"));
String formulaHorizontal = section.getString("polar-coordinates-formula.horizontal");
String formulaVertical = section.getString("polar-coordinates-formula.vertical");
List<Pair<Double, Double>> ranges = section.getStringList("theta.range")
.stream().map(it -> {
String[] split = it.split("~");
return Pair.of(Double.parseDouble(split[0]) * Math.PI / 180, Double.parseDouble(split[1]) * Math.PI / 180);
}).toList();
double interval = section.getDouble("theta.draw-interval", 3d);
int delay = section.getInt("task.delay", 0);
int period = section.getInt("task.period", 0);
if (particle == Particle.REDSTONE) {
String color = section.getString("options.color","0,0,0");
String[] colorSplit = color.split(",");
return new DustParticleSetting(
formulaHorizontal,
formulaVertical,
particle,
interval,
ranges,
delay,
period,
new Particle.DustOptions(
Color.fromRGB(
Integer.parseInt(colorSplit[0]),
Integer.parseInt(colorSplit[1]),
Integer.parseInt(colorSplit[2])
),
section.getDouble("options.scale", 1.0).floatValue()
)
);
} else if (particle == Particle.DUST_COLOR_TRANSITION) {
String color = section.getString("options.from","0,0,0");
String[] colorSplit = color.split(",");
String toColor = section.getString("options.to","255,255,255");
String[] toColorSplit = toColor.split(",");
return new DustParticleSetting(
formulaHorizontal,
formulaVertical,
particle,
interval,
ranges,
delay,
period,
new Particle.DustTransition(
Color.fromRGB(
Integer.parseInt(colorSplit[0]),
Integer.parseInt(colorSplit[1]),
Integer.parseInt(colorSplit[2])
),
Color.fromRGB(
Integer.parseInt(toColorSplit[0]),
Integer.parseInt(toColorSplit[1]),
Integer.parseInt(toColorSplit[2])
),
section.getDouble("options.scale", 1.0).floatValue()
)
);
} else {
return new ParticleSetting(
formulaHorizontal,
formulaVertical,
particle,
interval,
ranges,
delay,
period
);
}
}
private TotemModel[] getTotemModels(Section section) {
TotemModel originalModel = parseModel(section);
List<TotemModel> modelList = new ArrayList<>();
for (int i = 0; i < 4; i++) {
originalModel = originalModel.deepClone().rotate90();
modelList.add(originalModel);
if (i % 2 == 0) {
modelList.add(originalModel.mirrorVertically());
} else {
modelList.add(originalModel.mirrorHorizontally());
}
}
return modelList.toArray(new TotemModel[0]);
}
@SuppressWarnings("unchecked")
private TotemModel parseModel(Section section) {
Section layerSection = section.getSection("layer");
List<TotemBlock[][][]> totemBlocksList = new ArrayList<>();
if (layerSection != null) {
var set = layerSection.getStringRouteMappedValues(false).entrySet();
TotemBlock[][][][] totemBlocks = new TotemBlock[set.size()][][][];
for (Map.Entry<String, Object> entry : set) {
if (entry.getValue() instanceof List<?> list) {
totemBlocks[Integer.parseInt(entry.getKey())-1] = parseLayer((List<String>) list);
}
}
totemBlocksList.addAll(List.of(totemBlocks));
}
String[] core = section.getString("core","1,1,1").split(",");
int x = Integer.parseInt(core[2]) - 1;
int z = Integer.parseInt(core[1]) - 1;
int y = Integer.parseInt(core[0]) - 1;
return new TotemModel(
x,y,z,
totemBlocksList.toArray(new TotemBlock[0][][][])
);
}
private TotemBlock[][][] parseLayer(List<String> lines) {
List<TotemBlock[][]> totemBlocksList = new ArrayList<>();
for (String line : lines) {
totemBlocksList.add(parseSingleLine(line));
}
return totemBlocksList.toArray(new TotemBlock[0][][]);
}
private TotemBlock[][] parseSingleLine(String line) {
List<TotemBlock[]> totemBlocksList = new ArrayList<>();
String[] splits = line.split("\\s+");
for (String split : splits) {
totemBlocksList.add(parseSingleElement(split));
}
return totemBlocksList.toArray(new TotemBlock[0][]);
}
private TotemBlock[] parseSingleElement(String element) {
String[] orBlocks = element.split("\\|\\|");
List<TotemBlock> totemBlockList = new ArrayList<>();
for (String block : orBlocks) {
int index = block.indexOf("{");
List<TotemBlockProperty> propertyList = new ArrayList<>();
if (index == -1) {
index = block.length();
} else {
String propertyStr = block.substring(index+1, block.length()-1);
String[] properties = propertyStr.split(";");
for (String property : properties) {
String[] split = property.split("=");
if (split.length < 2) continue;
String key = split[0];
String value = split[1];
switch (key) {
// Block face
case "face" -> {
BlockFace blockFace = BlockFace.valueOf(value.toUpperCase(Locale.ENGLISH));
propertyList.add(new FaceImpl(blockFace));
}
// Block axis
case "axis" -> {
Axis axis = Axis.valueOf(value.toUpperCase(Locale.ENGLISH));
propertyList.add(new AxisImpl(axis));
}
// Slab, Stair half
case "half" -> {
Bisected.Half half = Bisected.Half.valueOf(value.toUpperCase(Locale.ENGLISH));
propertyList.add(new HalfImpl(half));
}
}
}
}
String type = block.substring(0, index);
TotemBlock totemBlock = new TotemBlock(
TypeCondition.getTypeCondition(type),
propertyList.toArray(new TotemBlockProperty[0])
);
totemBlockList.add(totemBlock);
}
return totemBlockList.toArray(new TotemBlock[0]);
}
}

View File

@@ -15,10 +15,16 @@ reload:
sellfish:
enable: true
permission: customfishing.command.sellfish
permission: customfishing.sellfish
usage:
- /sellfish
fishingbag:
enable: true
permission: fishingbag.user
usage:
- /fishingbag
get_item:
enable: true
permission: customfishing.command.getitem
@@ -66,4 +72,25 @@ open_bag:
permission: customfishing.command.open.bag
usage:
- /customfishing open bag
- /cfishing open bag
- /cfishing open bag
edit_online_bag:
enable: true
permission: customfishing.command.edit.bag
usage:
- /customfishing fishingbag edit-online
- /cfishing fishingbag edit-online
edit_offline_bag:
enable: true
permission: customfishing.command.edit.bag
usage:
- /customfishing fishingbag edit-offline
- /cfishing fishingbag edit-offline
browser:
enable: true
permission: customfishing.command.browser
usage:
- /customfishing browser
- /cfishing browser

View File

@@ -143,8 +143,6 @@ mechanics:
# Fishing bag is where players can store their baits, utils, hooks and rods (Loot optional)
fishing-bag:
# Enable
enable: true
# Fishing bag container title
bag-title: '<blue>{player}''s Fishing Bag</blue>'
# Other whitelist-items
@@ -368,21 +366,18 @@ mechanics:
placeholder-limit: 3
# If a player could get multiple loots from fishing, should the loots spawn at the same time or have delay for each (measured in ticks)
multiple-loot-spawn-delay: 4
# Totem settings
totem:
# Is it allowed for different types of totems to take effect at the same time
allow-multiple-type: true
# Is it allowed for totems of the same type to take effect cumulatively
allow-same-type: false
# Other settings
other-settings:
# It's recommended to use MiniMessage format. If you insist on using legacy color code "&", enable the support below.
# Disable this would improve performance
legacy-color-code-support: true
# Thread pool settings
thread-pool-settings:
# The size of the core Thread pool, that is, the size of the Thread pool when there is no task to execute
# Increase the size of corePoolSize when you are running a large server with many players fishing at the same time
corePoolSize: 10
# The maximum number of threads allowed to be created in the Thread pool. The current number of threads in the Thread pool will not exceed this value
maximumPoolSize: 10
# If a thread is idle for more than this attribute value, it will exit due to timeout
keepAliveTime: 30
# Event priority: MONITOR HIGHEST HIGH NORMAL LOW LOWEST
event-priority: NORMAL
# Save the data from cache to file periodically to minimize the data loss if server crashes

View File

@@ -38,7 +38,7 @@ argument.parse.failure.aggregate.missing: "<red>Missing component '<arg:0>'</red
argument.parse.failure.aggregate.failure: "<red>Invalid component '<arg:0>': <arg:1></red>"
argument.parse.failure.either: "<red>Could not resolve <arg:1> or <arg:2> from '<arg:0>'</red>"
argument.parse.failure.namedtextcolor: "<red>'<arg:0>' is not a named text color</red>"
command.reload.success: "<white>Reloaded. Took <green><arg:0></green>ms.</white>"
command.reload.success: "<white>Reloaded. Took <green><arg:0></green> ms.</white>"
command.item.failure.not_exist: "<red>Item [<arg:0>] not exists.</red>"
command.item.give.success: "<white>Successfully given <arg:0> <arg:1>x <arg:2>.</white>"
command.item.get.success: "<white>Successfully got <arg:0>x <arg:1>.</white>"