mirror of
https://github.com/Xiao-MoMi/Custom-Fishing.git
synced 2025-12-29 11:59:11 +00:00
checkpoint - 6
This commit is contained in:
@@ -1,291 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
|
||||
import net.momirealms.customfishing.api.event.CustomFishingReloadEvent;
|
||||
import net.momirealms.customfishing.api.mechanic.misc.cooldown.CoolDownManager;
|
||||
import net.momirealms.customfishing.api.mechanic.misc.placeholder.BukkitPlaceholderManager;
|
||||
import net.momirealms.customfishing.bukkit.bag.BukkitBagManager;
|
||||
import net.momirealms.customfishing.bukkit.block.BukkitBlockManager;
|
||||
import net.momirealms.customfishing.bukkit.compatibility.BukkitIntegrationManager;
|
||||
import net.momirealms.customfishing.bukkit.competition.BukkitCompetitionManager;
|
||||
import net.momirealms.customfishing.bukkit.effect.BukkitEffectManager;
|
||||
import net.momirealms.customfishing.bukkit.entity.BukkitEntityManager;
|
||||
import net.momirealms.customfishing.bukkit.fishing.BukkitFishingManager;
|
||||
import net.momirealms.customfishing.bukkit.game.BukkitGameManager;
|
||||
import net.momirealms.customfishing.bukkit.hook.BukkitHookManager;
|
||||
import net.momirealms.customfishing.bukkit.item.ItemManagerImpl;
|
||||
import net.momirealms.customfishing.bukkit.loot.LootManagerImpl;
|
||||
import net.momirealms.customfishing.bukkit.market.BukkitMarketManager;
|
||||
import net.momirealms.customfishing.bukkit.misc.ChatCatcherManager;
|
||||
import net.momirealms.customfishing.bukkit.statistic.BukkitStatisticsManager;
|
||||
import net.momirealms.customfishing.bukkit.storage.BukkitStorageManager;
|
||||
import net.momirealms.customfishing.bukkit.totem.BukkitTotemManager;
|
||||
import net.momirealms.customfishing.common.helper.VersionHelper;
|
||||
import org.bstats.bukkit.Metrics;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class BukkitCustomFishingPluginImpl extends BukkitCustomFishingPlugin {
|
||||
|
||||
private static ProtocolManager protocolManager;
|
||||
private CoolDownManager coolDownManager;
|
||||
private ChatCatcherManager chatCatcherManager;
|
||||
private DependencyManager dependencyManager;
|
||||
|
||||
public BukkitCustomFishingPluginImpl() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
this.versionManager = new VersionHelper(this);
|
||||
this.dependencyManager = new DependencyManagerImpl(this, new ReflectionClassPathAppender(this.getClassLoader()));
|
||||
this.dependencyManager.loadDependencies(new ArrayList<>(
|
||||
List.of(
|
||||
Dependency.GSON,
|
||||
Dependency.SLF4J_API,
|
||||
Dependency.SLF4J_SIMPLE,
|
||||
Dependency.BOOSTED_YAML,
|
||||
Dependency.EXP4J,
|
||||
Dependency.MYSQL_DRIVER,
|
||||
Dependency.MARIADB_DRIVER,
|
||||
Dependency.MONGODB_DRIVER_SYNC,
|
||||
Dependency.MONGODB_DRIVER_CORE,
|
||||
Dependency.MONGODB_DRIVER_BSON,
|
||||
Dependency.JEDIS,
|
||||
Dependency.COMMONS_POOL_2,
|
||||
Dependency.COMMONS_LANG_3,
|
||||
Dependency.H2_DRIVER,
|
||||
Dependency.SQLITE_DRIVER,
|
||||
Dependency.BSTATS_BASE,
|
||||
Dependency.HIKARI,
|
||||
Dependency.BSTATS_BUKKIT,
|
||||
versionManager.isMojmap() ? Dependency.COMMAND_API_MOJMAP : Dependency.COMMAND_API
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
protocolManager = ProtocolLibrary.getProtocolManager();
|
||||
|
||||
NBTUtils.disableNBTAPILogs();
|
||||
ReflectionUtils.load();
|
||||
|
||||
this.actionManager = new ActionManagerImpl(this);
|
||||
this.adventure = new AdventureHelper(this);
|
||||
this.bagManager = new BukkitBagManager(this);
|
||||
this.blockManager = new BukkitBlockManager(this);
|
||||
this.commandManager = new CommandManagerImpl(this);
|
||||
this.effectManager = new BukkitEffectManager(this);
|
||||
this.fishingManager = new BukkitFishingManager(this);
|
||||
this.gameManager = new BukkitGameManager(this);
|
||||
this.itemManager = new ItemManagerImpl(this);
|
||||
this.lootManager = new LootManagerImpl(this);
|
||||
this.marketManager = new BukkitMarketManager(this);
|
||||
this.entityManager = new BukkitEntityManager(this);
|
||||
this.placeholderManager = new BukkitPlaceholderManager(this);
|
||||
this.requirementManager = new RequirementManagerImpl(this);
|
||||
this.scheduler = new SchedulerImpl(this);
|
||||
this.storageManager = new BukkitStorageManager(this);
|
||||
this.competitionManager = new BukkitCompetitionManager(this);
|
||||
this.integrationManager = new BukkitIntegrationManager(this);
|
||||
this.statisticsManager = new BukkitStatisticsManager(this);
|
||||
this.coolDownManager = new CoolDownManager(this);
|
||||
this.totemManager = new BukkitTotemManager(this);
|
||||
this.hookManager = new BukkitHookManager(this);
|
||||
this.chatCatcherManager = new ChatCatcherManager(this);
|
||||
this.reload();
|
||||
super.initialized = true;
|
||||
|
||||
if (CFConfig.metrics) new Metrics(this, 16648);
|
||||
if (CFConfig.updateChecker)
|
||||
this.versionManager.checkUpdate().thenAccept(result -> {
|
||||
if (!result) this.getAdventure().sendConsoleMessage("[CustomFishing] You are using the latest version.");
|
||||
else this.getAdventure().sendConsoleMessage("[CustomFishing] Update is available: <u>https://polymart.org/resource/2723<!u>");
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
if (this.adventure != null) ((AdventureHelper) this.adventure).close();
|
||||
if (this.bagManager != null) ((BukkitBagManager) this.bagManager).disable();
|
||||
if (this.blockManager != null) ((BukkitBlockManager) this.blockManager).disable();
|
||||
if (this.effectManager != null) ((BukkitEffectManager) this.effectManager).disable();
|
||||
if (this.fishingManager != null) ((BukkitFishingManager) this.fishingManager).disable();
|
||||
if (this.gameManager != null) ((BukkitGameManager) this.gameManager).disable();
|
||||
if (this.itemManager != null) ((ItemManagerImpl) this.itemManager).disable();
|
||||
if (this.lootManager != null) ((LootManagerImpl) this.lootManager).disable();
|
||||
if (this.marketManager != null) ((BukkitMarketManager) this.marketManager).disable();
|
||||
if (this.entityManager != null) ((BukkitEntityManager) this.entityManager).disable();
|
||||
if (this.requirementManager != null) ((RequirementManagerImpl) this.requirementManager).disable();
|
||||
if (this.scheduler != null) ((SchedulerImpl) this.scheduler).shutdown();
|
||||
if (this.integrationManager != null) ((BukkitIntegrationManager) this.integrationManager).disable();
|
||||
if (this.competitionManager != null) ((BukkitCompetitionManager) this.competitionManager).disable();
|
||||
if (this.storageManager != null) ((BukkitStorageManager) this.storageManager).disable();
|
||||
if (this.placeholderManager != null) ((BukkitPlaceholderManager) this.placeholderManager).disable();
|
||||
if (this.statisticsManager != null) ((BukkitStatisticsManager) this.statisticsManager).disable();
|
||||
if (this.actionManager != null) ((ActionManagerImpl) this.actionManager).disable();
|
||||
if (this.totemManager != null) ((BukkitTotemManager) this.totemManager).disable();
|
||||
if (this.hookManager != null) ((BukkitHookManager) this.hookManager).disable();
|
||||
if (this.coolDownManager != null) this.coolDownManager.disable();
|
||||
if (this.chatCatcherManager != null) this.chatCatcherManager.disable();
|
||||
if (this.commandManager != null) this.commandManager.unload();
|
||||
HandlerList.unregisterAll(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reload the plugin
|
||||
*/
|
||||
@Override
|
||||
public void reload() {
|
||||
CFConfig.load();
|
||||
CFLocale.load();
|
||||
((SchedulerImpl) this.scheduler).reload();
|
||||
((RequirementManagerImpl) this.requirementManager).unload();
|
||||
((RequirementManagerImpl) this.requirementManager).load();
|
||||
((ActionManagerImpl) this.actionManager).unload();
|
||||
((ActionManagerImpl) this.actionManager).load();
|
||||
((BukkitGameManager) this.gameManager).unload();
|
||||
((BukkitGameManager) this.gameManager).load();
|
||||
((ItemManagerImpl) this.itemManager).unload();
|
||||
((ItemManagerImpl) this.itemManager).load();
|
||||
((LootManagerImpl) this.lootManager).unload();
|
||||
((LootManagerImpl) this.lootManager).load();
|
||||
((BukkitFishingManager) this.fishingManager).unload();
|
||||
((BukkitFishingManager) this.fishingManager).load();
|
||||
((BukkitTotemManager) this.totemManager).unload();
|
||||
((BukkitTotemManager) this.totemManager).load();
|
||||
((BukkitEffectManager) this.effectManager).unload();
|
||||
((BukkitEffectManager) this.effectManager).load();
|
||||
((BukkitMarketManager) this.marketManager).unload();
|
||||
((BukkitMarketManager) this.marketManager).load();
|
||||
((BukkitBagManager) this.bagManager).unload();
|
||||
((BukkitBagManager) this.bagManager).load();
|
||||
((BukkitBlockManager) this.blockManager).unload();
|
||||
((BukkitBlockManager) this.blockManager).load();
|
||||
((BukkitEntityManager) this.entityManager).unload();
|
||||
((BukkitEntityManager) this.entityManager).load();
|
||||
((BukkitCompetitionManager) this.competitionManager).unload();
|
||||
((BukkitCompetitionManager) this.competitionManager).load();
|
||||
((BukkitStorageManager) this.storageManager).reload();
|
||||
((BukkitStatisticsManager) this.statisticsManager).unload();
|
||||
((BukkitStatisticsManager) this.statisticsManager).load();
|
||||
((BukkitPlaceholderManager) this.placeholderManager).unload();
|
||||
((BukkitPlaceholderManager) this.placeholderManager).load();
|
||||
((BukkitHookManager) this.hookManager).unload();
|
||||
((BukkitHookManager) this.hookManager).load();
|
||||
this.commandManager.unload();
|
||||
this.commandManager.load();
|
||||
this.coolDownManager.unload();
|
||||
this.coolDownManager.load();
|
||||
this.chatCatcherManager.unload();
|
||||
this.chatCatcherManager.load();
|
||||
|
||||
CustomFishingReloadEvent event = new CustomFishingReloadEvent(this);
|
||||
Bukkit.getPluginManager().callEvent(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a YAML configuration from a file within the plugin's data folder.
|
||||
*
|
||||
* @param file The name of the configuration file.
|
||||
* @return A YamlConfiguration object representing the configuration.
|
||||
*/
|
||||
@Override
|
||||
public YamlConfiguration getConfig(String file) {
|
||||
File config = new File(this.getDataFolder(), file);
|
||||
if (!config.exists()) this.saveResource(file, false);
|
||||
return YamlConfiguration.loadConfiguration(config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a specified plugin is enabled on the Bukkit server.
|
||||
*
|
||||
* @param plugin The name of the plugin to check.
|
||||
* @return True if the plugin is enabled, false otherwise.
|
||||
*/
|
||||
@Override
|
||||
public boolean isHookedPluginEnabled(String plugin) {
|
||||
return Bukkit.getPluginManager().isPluginEnabled(plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs a debugging message if the debug mode is enabled.
|
||||
*
|
||||
* @param message The debugging message to be logged.
|
||||
*/
|
||||
@Override
|
||||
public void debug(String message) {
|
||||
if (!CFConfig.debug) return;
|
||||
LogUtils.info(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the CoolDownManager instance associated with the plugin.
|
||||
*
|
||||
* @return The CoolDownManager instance.
|
||||
*/
|
||||
public CoolDownManager getCoolDownManager() {
|
||||
return coolDownManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ChatCatcherManager instance associated with the plugin.
|
||||
*
|
||||
* @return The ChatCatcherManager instance.
|
||||
*/
|
||||
public ChatCatcherManager getChatCatcherManager() {
|
||||
return chatCatcherManager;
|
||||
}
|
||||
|
||||
public DependencyManager getDependencyManager() {
|
||||
return dependencyManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the ProtocolManager instance used for managing packets.
|
||||
*
|
||||
* @return The ProtocolManager instance.
|
||||
*/
|
||||
@NotNull
|
||||
public static ProtocolManager getProtocolManager() {
|
||||
return protocolManager;
|
||||
}
|
||||
|
||||
public static void sendPacket(Player player, PacketContainer packet) {
|
||||
protocolManager.sendServerPacket(player, packet);
|
||||
}
|
||||
|
||||
public static void sendPackets(Player player, PacketContainer... packets) {
|
||||
List<PacketContainer> bundle = new ArrayList<>(Arrays.asList(packets));
|
||||
PacketContainer bundlePacket = new PacketContainer(PacketType.Play.Server.BUNDLE);
|
||||
bundlePacket.getPacketBundles().write(0, bundle);
|
||||
sendPacket(player, bundlePacket);
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,9 @@ import net.momirealms.customfishing.api.mechanic.misc.placeholder.BukkitPlacehol
|
||||
import net.momirealms.customfishing.api.mechanic.misc.value.MathValue;
|
||||
import net.momirealms.customfishing.api.mechanic.misc.value.TextValue;
|
||||
import net.momirealms.customfishing.api.mechanic.requirement.Requirement;
|
||||
import net.momirealms.customfishing.bukkit.compatibility.VaultHook;
|
||||
import net.momirealms.customfishing.bukkit.integration.VaultHook;
|
||||
import net.momirealms.customfishing.bukkit.util.ItemUtils;
|
||||
import net.momirealms.customfishing.bukkit.util.LocationUtils;
|
||||
import net.momirealms.customfishing.bukkit.util.PlayerUtils;
|
||||
import net.momirealms.customfishing.common.helper.AdventureHelper;
|
||||
import net.momirealms.customfishing.common.plugin.scheduler.SchedulerTask;
|
||||
@@ -20,8 +22,6 @@ import net.momirealms.customfishing.common.util.ClassUtils;
|
||||
import net.momirealms.customfishing.common.util.ListUtils;
|
||||
import net.momirealms.customfishing.common.util.Pair;
|
||||
import net.momirealms.customfishing.common.util.RandomUtils;
|
||||
import net.momirealms.customfishing.bukkit.util.ItemUtils;
|
||||
import net.momirealms.customfishing.bukkit.util.LocationUtils;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Entity;
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
|
||||
package net.momirealms.customfishing.bukkit.bag;
|
||||
|
||||
import net.momirealms.customfishing.bukkit.BukkitCustomFishingPluginImpl;
|
||||
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
|
||||
import net.momirealms.customfishing.api.mechanic.action.Action;
|
||||
import net.momirealms.customfishing.api.mechanic.misc.placeholder.BukkitPlaceholderManager;
|
||||
@@ -45,12 +44,12 @@ public class BukkitBagManager implements BagManager, Listener {
|
||||
|
||||
private final BukkitCustomFishingPlugin plugin;
|
||||
private final HashMap<UUID, UserData> tempEditMap;
|
||||
private Action[] collectLootActions;
|
||||
private Action[] bagFullActions;
|
||||
private Action<Player>[] collectLootActions;
|
||||
private Action<Player>[] bagFullActions;
|
||||
private boolean bagStoreLoots;
|
||||
private String bagTitle;
|
||||
private List<Material> bagWhiteListItems;
|
||||
private Requirement[] collectRequirements;
|
||||
private Requirement<Player>[] collectRequirements;
|
||||
|
||||
public BukkitBagManager(BukkitCustomFishingPluginImpl plugin) {
|
||||
this.plugin = plugin;
|
||||
|
||||
@@ -17,27 +17,27 @@
|
||||
|
||||
package net.momirealms.customfishing.bukkit.block;
|
||||
|
||||
import net.momirealms.customfishing.bukkit.BukkitCustomFishingPluginImpl;
|
||||
import dev.dejvokep.boostedyaml.block.implementation.Section;
|
||||
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
|
||||
import net.momirealms.customfishing.api.common.Pair;
|
||||
import net.momirealms.customfishing.api.common.Tuple;
|
||||
import net.momirealms.customfishing.api.integration.BlockProvider;
|
||||
import net.momirealms.customfishing.api.mechanic.block.*;
|
||||
import net.momirealms.customfishing.api.mechanic.loot.Loot;
|
||||
import net.momirealms.customfishing.bukkit.compatibility.block.VanillaBlockProvider;
|
||||
import net.momirealms.customfishing.bukkit.util.ConfigUtils;
|
||||
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.misc.value.MathValue;
|
||||
import net.momirealms.customfishing.common.util.Pair;
|
||||
import net.momirealms.customfishing.common.util.RandomUtils;
|
||||
import net.momirealms.customfishing.common.util.Tuple;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.block.*;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.block.Container;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.block.data.Directional;
|
||||
import org.bukkit.block.data.Rotatable;
|
||||
import org.bukkit.block.data.type.Campfire;
|
||||
import org.bukkit.block.data.type.Farmland;
|
||||
import org.bukkit.block.data.type.NoteBlock;
|
||||
import org.bukkit.block.data.type.TurtleEgg;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.Ageable;
|
||||
import org.bukkit.entity.FallingBlock;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
@@ -49,61 +49,77 @@ import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
import org.bukkit.util.Vector;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
public class BukkitBlockManager implements BlockManager, Listener {
|
||||
|
||||
private final BukkitCustomFishingPlugin plugin;
|
||||
private final HashMap<String, BlockProvider> blockLibraryMap;
|
||||
private BlockProvider[] blockDetectionArray;
|
||||
private final HashMap<String, BlockConfigImpl> blockConfigMap;
|
||||
private final HashMap<String, BlockDataModifierFactory> dataBuilderMap;
|
||||
private final HashMap<String, BlockStateModifierFactory> stateBuilderMap;
|
||||
private final HashMap<String, BlockProvider> blockProviders = new HashMap<>();
|
||||
private final HashMap<String, BlockConfig> blocks = new HashMap<>();
|
||||
private final HashMap<String, BlockDataModifierFactory> dataFactories = new HashMap<>();
|
||||
private final HashMap<String, BlockStateModifierFactory> stateFactories = new HashMap<>();
|
||||
private BlockProvider[] blockDetectArray;
|
||||
|
||||
public BukkitBlockManager(BukkitCustomFishingPluginImpl plugin) {
|
||||
this.plugin = plugin;
|
||||
this.blockLibraryMap = new HashMap<>();
|
||||
this.blockConfigMap = new HashMap<>();
|
||||
this.dataBuilderMap = new HashMap<>();
|
||||
this.stateBuilderMap = new HashMap<>();
|
||||
this.registerInbuiltProperties();
|
||||
this.registerBlockLibrary(new VanillaBlockProvider());
|
||||
this.registerBlockProvider(new BlockProvider() {
|
||||
@Override
|
||||
public String identifier() {
|
||||
return "vanilla";
|
||||
}
|
||||
@Override
|
||||
public BlockData blockData(@NotNull Context<Player> context, @NotNull String id, List<BlockDataModifier> modifiers) {
|
||||
BlockData blockData = Material.valueOf(id.toUpperCase(Locale.ENGLISH)).createBlockData();
|
||||
for (BlockDataModifier modifier : modifiers)
|
||||
modifier.apply(context, blockData);
|
||||
return blockData;
|
||||
}
|
||||
@NotNull
|
||||
@Override
|
||||
public String blockID(@NotNull Block block) {
|
||||
return block.getType().name();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean registerBlock(@NotNull String id, @NotNull BlockConfig block) {
|
||||
if (blocks.containsKey(id)) return false;
|
||||
blocks.put(id, block);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
this.loadConfig();
|
||||
Bukkit.getPluginManager().registerEvents(this, plugin);
|
||||
Bukkit.getPluginManager().registerEvents(this, plugin.getBoostrap());
|
||||
this.resetBlockDetectionOrder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unload() {
|
||||
HandlerList.unregisterAll(this);
|
||||
HashMap<String, BlockConfigImpl> tempMap = new HashMap<>(this.blockConfigMap);
|
||||
this.blockConfigMap.clear();
|
||||
for (Map.Entry<String, BlockConfigImpl> entry : tempMap.entrySet()) {
|
||||
if (entry.getValue().isPersist()) {
|
||||
tempMap.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
this.blocks.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disable() {
|
||||
this.blockLibraryMap.clear();
|
||||
this.blockProviders.clear();
|
||||
}
|
||||
|
||||
private void resetBlockDetectionOrder() {
|
||||
ArrayList<BlockProvider> list = new ArrayList<>();
|
||||
for (String plugin : CFConfig.itemDetectOrder) {
|
||||
BlockProvider library = blockLibraryMap.get(plugin);
|
||||
if (library != null) {
|
||||
for (String plugin : ConfigManager.blockDetectOrder()) {
|
||||
BlockProvider library = blockProviders.get(plugin);
|
||||
if (library != null)
|
||||
list.add(library);
|
||||
}
|
||||
}
|
||||
this.blockDetectionArray = list.toArray(new BlockProvider[0]);
|
||||
this.blockDetectArray = list.toArray(new BlockProvider[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -117,7 +133,7 @@ public class BukkitBlockManager implements BlockManager, Listener {
|
||||
|
||||
// Retrieve a custom string value stored in the entity's persistent data container.
|
||||
String temp = event.getEntity().getPersistentDataContainer().get(
|
||||
Objects.requireNonNull(NamespacedKey.fromString("block", BukkitCustomFishingPlugin.get())),
|
||||
requireNonNull(NamespacedKey.fromString("block", plugin.getBoostrap())),
|
||||
PersistentDataType.STRING
|
||||
);
|
||||
|
||||
@@ -128,8 +144,8 @@ public class BukkitBlockManager implements BlockManager, Listener {
|
||||
String[] split = temp.split(";");
|
||||
|
||||
// If no BlockConfig is found for the specified key, return without further action.
|
||||
BlockConfigImpl blockConfigImpl = blockConfigMap.get(split[0]);
|
||||
if (blockConfigImpl == null) return;
|
||||
BlockConfig blockConfig= blocks.get(split[0]);
|
||||
if (blockConfig == null) return;
|
||||
|
||||
// If the player is not online or not found, remove the entity and set the block to air
|
||||
Player player = Bukkit.getPlayer(split[1]);
|
||||
@@ -138,254 +154,107 @@ public class BukkitBlockManager implements BlockManager, Listener {
|
||||
event.getBlock().setType(Material.AIR);
|
||||
return;
|
||||
}
|
||||
|
||||
Context<Player> context = Context.player(player);
|
||||
Location location = event.getBlock().getLocation();
|
||||
|
||||
// Apply block state modifiers from the BlockConfig to the block 1 tick later.
|
||||
plugin.getScheduler().runTaskSyncLater(() -> {
|
||||
plugin.getScheduler().sync().runLater(() -> {
|
||||
BlockState state = location.getBlock().getState();
|
||||
for (BlockStateModifier modifier : blockConfigImpl.stateModifiers()) {
|
||||
modifier.apply(player, state);
|
||||
for (BlockStateModifier modifier : blockConfig.stateModifiers()) {
|
||||
modifier.apply(context, state);
|
||||
}
|
||||
}, location, 50, TimeUnit.MILLISECONDS);
|
||||
}, 1, location);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a BlockLibrary instance.
|
||||
* This method associates a BlockLibrary with its unique identification and adds it to the registry.
|
||||
*
|
||||
* @param blockProvider The BlockLibrary instance to register.
|
||||
* @return True if the registration was successful (the identification is not already registered), false otherwise.
|
||||
*/
|
||||
@Override
|
||||
public boolean registerBlockLibrary(BlockProvider blockProvider) {
|
||||
if (this.blockLibraryMap.containsKey(blockProvider.identification())) return false;
|
||||
this.blockLibraryMap.put(blockProvider.identification(), blockProvider);
|
||||
public boolean registerBlockProvider(BlockProvider blockProvider) {
|
||||
if (this.blockProviders.containsKey(blockProvider.identifier())) return false;
|
||||
this.blockProviders.put(blockProvider.identifier(), blockProvider);
|
||||
this.resetBlockDetectionOrder();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters a BlockLibrary instance by its identification.
|
||||
* This method removes a BlockLibrary from the registry based on its unique identification.
|
||||
*
|
||||
* @param identification The unique identification of the BlockLibrary to unregister.
|
||||
* @return True if the BlockLibrary was successfully unregistered, false if it was not found.
|
||||
*/
|
||||
@Override
|
||||
public boolean unregisterBlockLibrary(String identification) {
|
||||
boolean success = blockLibraryMap.remove(identification) != null;
|
||||
public boolean unregisterBlockProvider(String identification) {
|
||||
boolean success = blockProviders.remove(identification) != null;
|
||||
if (success)
|
||||
this.resetBlockDetectionOrder();
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a BlockDataModifierBuilder for a specific type.
|
||||
* This method associates a BlockDataModifierBuilder with its type and adds it to the registry.
|
||||
*
|
||||
* @param type The type of the BlockDataModifierBuilder to register.
|
||||
* @param builder The BlockDataModifierBuilder instance to register.
|
||||
* @return True if the registration was successful (the type is not already registered), false otherwise.
|
||||
*/
|
||||
@Override
|
||||
public boolean registerBlockDataModifierBuilder(String type, BlockDataModifierFactory builder) {
|
||||
if (dataBuilderMap.containsKey(type)) return false;
|
||||
dataBuilderMap.put(type, builder);
|
||||
public boolean registerBlockDataModifierBuilder(String type, BlockDataModifierFactory factory) {
|
||||
if (this.dataFactories.containsKey(type)) return false;
|
||||
this.dataFactories.put(type, factory);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a BlockStateModifierBuilder for a specific type.
|
||||
* This method associates a BlockStateModifierBuilder with its type and adds it to the registry.
|
||||
*
|
||||
* @param type The type of the BlockStateModifierBuilder to register.
|
||||
* @param builder The BlockStateModifierBuilder instance to register.
|
||||
* @return True if the registration was successful (the type is not already registered), false otherwise.
|
||||
*/
|
||||
@Override
|
||||
public boolean registerBlockStateModifierBuilder(String type, BlockStateModifierFactory builder) {
|
||||
if (stateBuilderMap.containsKey(type)) return false;
|
||||
stateBuilderMap.put(type, builder);
|
||||
public boolean registerBlockStateModifierBuilder(String type, BlockStateModifierFactory factory) {
|
||||
if (stateFactories.containsKey(type)) return false;
|
||||
this.stateFactories.put(type, factory);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters a BlockDataModifierBuilder with the specified type.
|
||||
*
|
||||
* @param type The type of the BlockDataModifierBuilder to unregister.
|
||||
* @return True if the BlockDataModifierBuilder was successfully unregistered, false otherwise.
|
||||
*/
|
||||
@Override
|
||||
public boolean unregisterBlockDataModifierBuilder(String type) {
|
||||
return dataBuilderMap.remove(type) != null;
|
||||
return this.dataFactories.remove(type) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters a BlockStateModifierBuilder with the specified type.
|
||||
*
|
||||
* @param type The type of the BlockStateModifierBuilder to unregister.
|
||||
* @return True if the BlockStateModifierBuilder was successfully unregistered, false otherwise.
|
||||
*/
|
||||
@Override
|
||||
public boolean unregisterBlockStateModifierBuilder(String type) {
|
||||
return stateBuilderMap.remove(type) != null;
|
||||
return this.stateFactories.remove(type) != null;
|
||||
}
|
||||
|
||||
private void registerInbuiltProperties() {
|
||||
this.registerDirectional();
|
||||
this.registerStorage();
|
||||
this.registerRotatable();
|
||||
this.registerTurtleEggs();
|
||||
this.registerMoisture();
|
||||
this.registerNoteBlock();
|
||||
this.registerCampfire();
|
||||
this.registerAge();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads configuration files from the plugin's data folder and processes them.
|
||||
* Configuration files are organized by type (e.g., "block").
|
||||
*/
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
private void loadConfig() {
|
||||
Deque<File> fileDeque = new ArrayDeque<>();
|
||||
for (String type : List.of("block")) {
|
||||
File typeFolder = new File(plugin.getDataFolder() + File.separator + "contents" + File.separator + type);
|
||||
if (!typeFolder.exists()) {
|
||||
if (!typeFolder.mkdirs()) return;
|
||||
plugin.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads configuration data from a single YAML file and processes it to create BlockConfig instances.
|
||||
*
|
||||
* @param file The YAML file to load and process.
|
||||
*/
|
||||
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) {
|
||||
|
||||
// Check if the "block" is null and log a warning if so.
|
||||
String blockID = section.getString("block");
|
||||
if (blockID == null) {
|
||||
LogUtils.warn("Block can't be null. File:" + file.getAbsolutePath() + "; Section:" + section.getCurrentPath());
|
||||
continue;
|
||||
}
|
||||
List<BlockDataModifier> dataModifiers = new ArrayList<>();
|
||||
List<BlockStateModifier> stateModifiers = new ArrayList<>();
|
||||
|
||||
// If a "properties" section exists, process its entries.
|
||||
ConfigurationSection property = section.getConfigurationSection("properties");
|
||||
if (property != null) {
|
||||
for (Map.Entry<String, Object> innerEntry : property.getValues(false).entrySet()) {
|
||||
BlockDataModifierFactory dataBuilder = dataBuilderMap.get(innerEntry.getKey());
|
||||
if (dataBuilder != null) {
|
||||
dataModifiers.add(dataBuilder.build(innerEntry.getValue()));
|
||||
continue;
|
||||
}
|
||||
BlockStateModifierFactory stateBuilder = stateBuilderMap.get(innerEntry.getKey());
|
||||
if (stateBuilder != null) {
|
||||
stateModifiers.add(stateBuilder.build(innerEntry.getValue()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create a BlockConfig instance with the processed data and add it to the blockConfigMap.
|
||||
BlockConfigImpl blockConfigImpl = new BlockConfigImpl.Builder()
|
||||
.blockID(blockID)
|
||||
.persist(false)
|
||||
.horizontalVector(section.getDouble("velocity.horizontal", 1.1))
|
||||
.verticalVector(section.getDouble("velocity.vertical", 1.2))
|
||||
.dataModifiers(dataModifiers)
|
||||
.stateModifiers(stateModifiers)
|
||||
.build();
|
||||
blockConfigMap.put(entry.getKey(), blockConfigImpl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Summons a falling block at a specified location based on the provided loot.
|
||||
* This method spawns a falling block at the given hookLocation with specific properties determined by the loot.
|
||||
*
|
||||
* @param player The player who triggered the action.
|
||||
* @param hookLocation The location where the hook is positioned.
|
||||
* @param playerLocation The location of the player.
|
||||
* @param loot The loot to be associated with the summoned block.
|
||||
*/
|
||||
@Override
|
||||
public void summonBlock(Player player, Location hookLocation, Location playerLocation, Loot loot) {
|
||||
BlockConfigImpl config = blockConfigMap.get(loot.getID());
|
||||
if (config == null) {
|
||||
LogUtils.warn("Block: " + loot.getID() + " doesn't exist.");
|
||||
return;
|
||||
}
|
||||
@Nullable
|
||||
public FallingBlock summonBlockLoot(@NotNull Context<Player> context) {
|
||||
String id = context.arg(ContextKeys.ID);
|
||||
BlockConfig config = requireNonNull(blocks.get(id), "Block " + id + " not found");
|
||||
String blockID = config.blockID();
|
||||
BlockData blockData;
|
||||
if (blockID.contains(":")) {
|
||||
String[] split = blockID.split(":", 2);
|
||||
String lib = split[0];
|
||||
String id = split[1];
|
||||
blockData = blockLibraryMap.get(lib).blockData(player, id, config.dataModifier());
|
||||
BlockProvider provider = requireNonNull(blockProviders.get(split[0]), "BlockProvider " + split[0] + " doesn't exist");
|
||||
blockData = requireNonNull(provider.blockData(context, split[1], config.dataModifier()), "Block " + split[1] + " doesn't exist");
|
||||
} else {
|
||||
blockData = blockLibraryMap.get("vanilla").blockData(player, blockID, config.dataModifier());
|
||||
blockData = blockProviders.get("vanilla").blockData(context, blockID, config.dataModifier());
|
||||
}
|
||||
FallingBlock fallingBlock = hookLocation.getWorld().spawnFallingBlock(hookLocation, blockData);
|
||||
Location hookLocation = requireNonNull(context.arg(ContextKeys.HOOK_LOCATION));
|
||||
Location playerLocation = requireNonNull(context.getHolder()).getLocation();
|
||||
FallingBlock fallingBlock = hookLocation.getWorld().spawn(hookLocation, FallingBlock.class, (fb -> fb.setBlockData(blockData)));
|
||||
fallingBlock.getPersistentDataContainer().set(
|
||||
Objects.requireNonNull(NamespacedKey.fromString("block", BukkitCustomFishingPlugin.get())),
|
||||
requireNonNull(NamespacedKey.fromString("block", plugin.getBoostrap())),
|
||||
PersistentDataType.STRING,
|
||||
loot.getID() + ";" + player.getName()
|
||||
id + ";" + context.getHolder().getName()
|
||||
);
|
||||
Vector vector = playerLocation.subtract(hookLocation).toVector().multiply((config.horizontalVector()) - 1);
|
||||
vector = vector.setY((vector.getY() + 0.2) * config.verticalVector());
|
||||
Vector vector = playerLocation.subtract(hookLocation).toVector().multiply((config.horizontalVector().evaluate(context)) - 1);
|
||||
vector = vector.setY((vector.getY() + 0.2) * config.verticalVector().evaluate(context));
|
||||
fallingBlock.setVelocity(vector);
|
||||
return fallingBlock;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the block ID associated with a given Block instance using block detection order.
|
||||
* This method iterates through the configured block detection order to find the block's ID
|
||||
* by checking different BlockLibrary instances in the specified order.
|
||||
*
|
||||
* @param block The Block instance for which to retrieve the block ID.
|
||||
* @return The block ID
|
||||
*/
|
||||
@Override
|
||||
@NotNull
|
||||
public String getAnyPluginBlockID(Block block) {
|
||||
for (BlockProvider blockProvider : blockDetectionArray) {
|
||||
public String getBlockID(@NotNull Block block) {
|
||||
for (BlockProvider blockProvider : blockDetectArray) {
|
||||
String id = blockProvider.blockID(block);
|
||||
if (id != null) {
|
||||
return id;
|
||||
}
|
||||
if (id != null) return id;
|
||||
}
|
||||
// Should not reach this because vanilla library would always work
|
||||
return "AIR";
|
||||
}
|
||||
|
||||
private void registerDirectional() {
|
||||
this.registerBlockDataModifierBuilder("directional-4", (args) -> (player, blockData) -> {
|
||||
this.registerBlockDataModifierBuilder("directional-4", (args) -> (context, blockData) -> {
|
||||
boolean arg = (boolean) args;
|
||||
if (arg && blockData instanceof Directional directional) {
|
||||
directional.setFacing(BlockFace.values()[ThreadLocalRandom.current().nextInt(0, 4)]);
|
||||
}
|
||||
});
|
||||
this.registerBlockDataModifierBuilder("directional-6", (args) -> (player, blockData) -> {
|
||||
this.registerBlockDataModifierBuilder("directional-6", (args) -> (context, blockData) -> {
|
||||
boolean arg = (boolean) args;
|
||||
if (arg && blockData instanceof Directional directional) {
|
||||
directional.setFacing(BlockFace.values()[ThreadLocalRandom.current().nextInt(0, 6)]);
|
||||
@@ -393,32 +262,10 @@ public class BukkitBlockManager implements BlockManager, Listener {
|
||||
});
|
||||
}
|
||||
|
||||
private void registerMoisture() {
|
||||
this.registerBlockDataModifierBuilder("moisture", (args) -> {
|
||||
int arg = (int) args;
|
||||
return (player, blockData) -> {
|
||||
if (blockData instanceof Farmland farmland) {
|
||||
farmland.setMoisture(arg);
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
private void registerCampfire() {
|
||||
this.registerBlockDataModifierBuilder("campfire", (args) -> {
|
||||
boolean arg = (boolean) args;
|
||||
return (player, blockData) -> {
|
||||
if (blockData instanceof Campfire campfire) {
|
||||
campfire.setSignalFire(arg);
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
private void registerRotatable() {
|
||||
this.registerBlockDataModifierBuilder("rotatable", (args) -> {
|
||||
boolean arg = (boolean) args;
|
||||
return (player, blockData) -> {
|
||||
return (context, blockData) -> {
|
||||
if (arg && blockData instanceof Rotatable rotatable) {
|
||||
rotatable.setRotation(BlockFace.values()[ThreadLocalRandom.current().nextInt(BlockFace.values().length)]);
|
||||
}
|
||||
@@ -428,99 +275,64 @@ public class BukkitBlockManager implements BlockManager, Listener {
|
||||
|
||||
private void registerNoteBlock() {
|
||||
this.registerBlockDataModifierBuilder("noteblock", (args) -> {
|
||||
if (args instanceof ConfigurationSection section) {
|
||||
if (args instanceof Section section) {
|
||||
var instrument = Instrument.valueOf(section.getString("instrument"));
|
||||
var note = new Note(section.getInt("note"));
|
||||
return (player, blockData) -> {
|
||||
return (context, blockData) -> {
|
||||
if (blockData instanceof NoteBlock noteBlock) {
|
||||
noteBlock.setNote(note);
|
||||
noteBlock.setInstrument(instrument);
|
||||
}
|
||||
};
|
||||
} else {
|
||||
LogUtils.warn("Invalid property format found at block noteblock.");
|
||||
return null;
|
||||
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at noteblock property which should be Section");
|
||||
return EmptyBlockDataModifier.INSTANCE;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void registerAge() {
|
||||
this.registerBlockDataModifierBuilder("age", (args) -> {
|
||||
int arg = (int) args;
|
||||
return (player, blockData) -> {
|
||||
if (blockData instanceof Ageable ageable) {
|
||||
ageable.setAge(arg);
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
private void registerTurtleEggs() {
|
||||
this.registerBlockDataModifierBuilder("turtle-eggs", (args) -> {
|
||||
int arg = (int) args;
|
||||
return (player, blockData) -> {
|
||||
if (blockData instanceof TurtleEgg egg) {
|
||||
egg.setEggs(arg);
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
private void registerStorage() {
|
||||
this.registerBlockStateModifierBuilder("storage", (args) -> {
|
||||
if (args instanceof ConfigurationSection section) {
|
||||
ArrayList<Tuple<Double, String, Pair<Integer, Integer>>> tempChanceList = new ArrayList<>();
|
||||
for (Map.Entry<String, Object> entry : section.getValues(false).entrySet()) {
|
||||
if (args instanceof Section section) {
|
||||
List<Tuple<MathValue<Player>, String, Pair<MathValue<Player>, MathValue<Player>>>> contents = new ArrayList<>();
|
||||
for (Map.Entry<String, Object> entry : section.getStringRouteMappedValues(false).entrySet()) {
|
||||
if (entry.getValue() instanceof ConfigurationSection inner) {
|
||||
String item = inner.getString("item");
|
||||
Pair<Integer, Integer> amountPair = ConfigUtils.splitStringIntegerArgs(inner.getString("amount","1~1"), "~");
|
||||
double chance = inner.getDouble("chance", 1);
|
||||
tempChanceList.add(Tuple.of(chance, item, amountPair));
|
||||
String[] split = inner.getString("amount","1~1").split("~");
|
||||
Pair<MathValue<Player>, MathValue<Player>> amountPair = Pair.of(MathValue.auto(split[0]), MathValue.auto(split[1]));
|
||||
MathValue<Player> chance = MathValue.auto(inner.get("chance", 1d));
|
||||
contents.add(Tuple.of(chance, item, amountPair));
|
||||
}
|
||||
}
|
||||
return (player, blockState) -> {
|
||||
if (blockState instanceof Chest chest) {
|
||||
setInventoryItems(tempChanceList, player, chest.getInventory());
|
||||
return;
|
||||
}
|
||||
if (blockState instanceof Barrel barrel) {
|
||||
setInventoryItems(tempChanceList, player, barrel.getInventory());
|
||||
return;
|
||||
}
|
||||
if (blockState instanceof ShulkerBox shulkerBox) {
|
||||
setInventoryItems(tempChanceList, player, shulkerBox.getInventory());
|
||||
return;
|
||||
return (context, blockState) -> {
|
||||
if (blockState instanceof Container container) {
|
||||
setInventoryItems(contents, context, container.getInventory());
|
||||
}
|
||||
};
|
||||
} else {
|
||||
LogUtils.warn("Invalid property format found at block storage.");
|
||||
return null;
|
||||
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at storage property which should be Section");
|
||||
return EmptyBlockStateModifier.INSTANCE;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets items in the BLOCK's inventory based on chance and configuration.
|
||||
*
|
||||
* @param tempChanceList A list of tuples containing chance, item ID, and quantity range for each item.
|
||||
* @param player The inventory items are being set.
|
||||
* @param inventory The inventory where the items will be placed.
|
||||
*/
|
||||
private void setInventoryItems(
|
||||
ArrayList<Tuple<Double, String, Pair<Integer, Integer>>> tempChanceList,
|
||||
Player player,
|
||||
List<Tuple<MathValue<Player>, String, Pair<MathValue<Player>, MathValue<Player>>>> contents,
|
||||
Context<Player> context,
|
||||
Inventory inventory
|
||||
) {
|
||||
LinkedList<Integer> unused = new LinkedList<>();
|
||||
for (int i = 0; i < 27; i++) {
|
||||
for (int i = 0; i < inventory.getSize(); i++) {
|
||||
unused.add(i);
|
||||
}
|
||||
Collections.shuffle(unused);
|
||||
for (Tuple<Double, String, Pair<Integer, Integer>> tuple : tempChanceList) {
|
||||
ItemStack itemStack = plugin.getItemManager().buildAnyPluginItemByID(player, tuple.getMid());
|
||||
itemStack.setAmount(ThreadLocalRandom.current().nextInt(tuple.getRight().left(), tuple.getRight().right() + 1));
|
||||
if (tuple.getLeft() > Math.random()) {
|
||||
inventory.setItem(unused.pop(), itemStack);
|
||||
for (Tuple<MathValue<Player>, String, Pair<MathValue<Player>, MathValue<Player>>> tuple : contents) {
|
||||
if (tuple.getLeft().evaluate(context) > Math.random()) {
|
||||
ItemStack itemStack = plugin.getItemManager().buildAny(context, tuple.getMid());
|
||||
if (itemStack != null) {
|
||||
itemStack.setAmount(RandomUtils.generateRandomInt((int) tuple.getRight().left().evaluate(context), (int) (tuple.getRight().right().evaluate(context) + 1)));
|
||||
inventory.setItem(unused.pop(), itemStack);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,271 +0,0 @@
|
||||
/*
|
||||
* 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.compatibility;
|
||||
|
||||
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
|
||||
import net.momirealms.customfishing.api.integration.EnchantmentProvider;
|
||||
import net.momirealms.customfishing.api.integration.IntegrationManager;
|
||||
import net.momirealms.customfishing.api.integration.LevelerProvider;
|
||||
import net.momirealms.customfishing.api.integration.SeasonProvider;
|
||||
import net.momirealms.customfishing.bukkit.compatibility.block.ItemsAdderBlockProvider;
|
||||
import net.momirealms.customfishing.bukkit.compatibility.enchant.AdvancedEnchantmentsProvider;
|
||||
import net.momirealms.customfishing.bukkit.compatibility.enchant.VanillaEnchantmentsProvider;
|
||||
import net.momirealms.customfishing.bukkit.compatibility.entity.ItemsAdderEntityProvider;
|
||||
import net.momirealms.customfishing.bukkit.compatibility.entity.MythicEntityProvider;
|
||||
import net.momirealms.customfishing.bukkit.compatibility.item.*;
|
||||
import net.momirealms.customfishing.bukkit.compatibility.level.*;
|
||||
import net.momirealms.customfishing.bukkit.compatibility.quest.BattlePassQuest;
|
||||
import net.momirealms.customfishing.bukkit.compatibility.quest.BetonQuestQuest;
|
||||
import net.momirealms.customfishing.bukkit.compatibility.quest.ClueScrollsQuest;
|
||||
import net.momirealms.customfishing.bukkit.compatibility.season.CustomCropsSeasonProvider;
|
||||
import net.momirealms.customfishing.bukkit.compatibility.season.RealisticSeasonsProvider;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
public class BukkitIntegrationManager implements IntegrationManager {
|
||||
|
||||
private final BukkitCustomFishingPlugin plugin;
|
||||
private final HashMap<String, LevelerProvider> levelPluginMap;
|
||||
private final HashMap<String, EnchantmentProvider> enchantmentPluginMap;
|
||||
private SeasonProvider seasonProvider;
|
||||
|
||||
public BukkitIntegrationManager(BukkitCustomFishingPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
this.levelPluginMap = new HashMap<>();
|
||||
this.enchantmentPluginMap = new HashMap<>();
|
||||
this.load();
|
||||
}
|
||||
|
||||
public void disable() {
|
||||
this.enchantmentPluginMap.clear();
|
||||
this.levelPluginMap.clear();
|
||||
}
|
||||
|
||||
public void load() {
|
||||
if (Bukkit.getPluginManager().getPlugin("ItemsAdder") != null) {
|
||||
plugin.getItemManager().registerItemLibrary(new ItemsAdderItemProvider());
|
||||
plugin.getBlockManager().registerBlockLibrary(new ItemsAdderBlockProvider());
|
||||
plugin.getEntityManager().registerEntityProvider(new ItemsAdderEntityProvider());
|
||||
hookMessage("ItemsAdder");
|
||||
}
|
||||
if (Bukkit.getPluginManager().getPlugin("MMOItems") != null) {
|
||||
plugin.getItemManager().registerItemLibrary(new MMOItemsItemProvider());
|
||||
hookMessage("MMOItems");
|
||||
}
|
||||
if (Bukkit.getPluginManager().getPlugin("Oraxen") != null) {
|
||||
plugin.getItemManager().registerItemLibrary(new OraxenItemProvider());
|
||||
hookMessage("Oraxen");
|
||||
}
|
||||
if (plugin.isHookedPluginEnabled("Zaphkiel")) {
|
||||
plugin.getItemManager().registerItemLibrary(new ZaphkielItemImpl());
|
||||
hookMessage("Zaphkiel");
|
||||
}
|
||||
if (plugin.isHookedPluginEnabled("NeigeItems")) {
|
||||
plugin.getItemManager().registerItemLibrary(new NeigeItemsItemProvider());
|
||||
hookMessage("NeigeItems");
|
||||
}
|
||||
if (Bukkit.getPluginManager().getPlugin("MythicMobs") != null) {
|
||||
plugin.getItemManager().registerItemLibrary(new MythicMobsItemProvider());
|
||||
plugin.getEntityManager().registerEntityProvider(new MythicEntityProvider());
|
||||
hookMessage("MythicMobs");
|
||||
}
|
||||
if (plugin.isHookedPluginEnabled("EcoJobs")) {
|
||||
registerLevelerProvider("EcoJobs", new EcoJobsLevelerProvider());
|
||||
hookMessage("EcoJobs");
|
||||
}
|
||||
if (plugin.isHookedPluginEnabled("EcoSkills")) {
|
||||
registerLevelerProvider("EcoSkills", new EcoSkillsLevelerProvider());
|
||||
hookMessage("EcoSkills");
|
||||
}
|
||||
if (Bukkit.getPluginManager().getPlugin("Jobs") != null) {
|
||||
registerLevelerProvider("JobsReborn", new JobsRebornLevelerProvider());
|
||||
hookMessage("JobsReborn");
|
||||
}
|
||||
if (plugin.isHookedPluginEnabled("MMOCore")) {
|
||||
registerLevelerProvider("MMOCore", new MMOCoreLevelerProvider());
|
||||
hookMessage("MMOCore");
|
||||
}
|
||||
if (plugin.isHookedPluginEnabled("mcMMO")) {
|
||||
try {
|
||||
plugin.getItemManager().registerItemLibrary(new McMMOTreasureProvider());
|
||||
} catch (ClassNotFoundException | NoSuchMethodException e) {
|
||||
LogUtils.warn("Failed to initialize mcMMO Treasure");
|
||||
}
|
||||
registerLevelerProvider("mcMMO", new McMMOLevelerProvider());
|
||||
hookMessage("mcMMO");
|
||||
}
|
||||
if (plugin.isHookedPluginEnabled("AureliumSkills")) {
|
||||
registerLevelerProvider("AureliumSkills", new AureliumSkillsProvider());
|
||||
hookMessage("AureliumSkills");
|
||||
}
|
||||
if (plugin.isHookedPluginEnabled("AuraSkills")) {
|
||||
registerLevelerProvider("AuraSkills", new AuraSkillsLevelerProvider());
|
||||
hookMessage("AuraSkills");
|
||||
}
|
||||
if (plugin.isHookedPluginEnabled("EcoEnchants")) {
|
||||
this.enchantmentPluginMap.put("EcoEnchants", new VanillaEnchantmentsProvider());
|
||||
hookMessage("EcoEnchants");
|
||||
} else {
|
||||
this.enchantmentPluginMap.put("vanilla", new VanillaEnchantmentsProvider());
|
||||
}
|
||||
if (plugin.isHookedPluginEnabled("AdvancedEnchantments")) {
|
||||
this.enchantmentPluginMap.put("AdvancedEnchantments", new AdvancedEnchantmentsProvider());
|
||||
hookMessage("AdvancedEnchantments");
|
||||
}
|
||||
if (plugin.isHookedPluginEnabled("RealisticSeasons")) {
|
||||
this.seasonProvider = new RealisticSeasonsProvider();
|
||||
} else if (plugin.isHookedPluginEnabled("CustomCrops")) {
|
||||
this.seasonProvider = new CustomCropsSeasonProvider();
|
||||
}
|
||||
if (plugin.isHookedPluginEnabled("Vault")) {
|
||||
VaultHook.initialize();
|
||||
}
|
||||
if (plugin.isHookedPluginEnabled("BattlePass")){
|
||||
BattlePassQuest battlePassQuest = new BattlePassQuest();
|
||||
battlePassQuest.register();
|
||||
hookMessage("BattlePass");
|
||||
}
|
||||
if (plugin.isHookedPluginEnabled("ClueScrolls")) {
|
||||
ClueScrollsQuest clueScrollsQuest = new ClueScrollsQuest();
|
||||
clueScrollsQuest.register();
|
||||
hookMessage("ClueScrolls");
|
||||
}
|
||||
if (plugin.isHookedPluginEnabled("BetonQuest")) {
|
||||
BetonQuestQuest.register();
|
||||
hookMessage("BetonQuest");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a level plugin with the specified name.
|
||||
*
|
||||
* @param plugin The name of the level plugin.
|
||||
* @param level The implementation of the LevelInterface.
|
||||
* @return true if the registration was successful, false if the plugin name is already registered.
|
||||
*/
|
||||
@Override
|
||||
public boolean registerLevelerProvider(String plugin, LevelerProvider level) {
|
||||
if (levelPluginMap.containsKey(plugin)) return false;
|
||||
levelPluginMap.put(plugin, level);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters a level plugin with the specified name.
|
||||
*
|
||||
* @param plugin The name of the level plugin to unregister.
|
||||
* @return true if the unregistration was successful, false if the plugin name is not found.
|
||||
*/
|
||||
@Override
|
||||
public boolean unregisterLevelerProvider(String plugin) {
|
||||
return levelPluginMap.remove(plugin) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers an enchantment provided by a plugin.
|
||||
*
|
||||
* @param plugin The name of the plugin providing the enchantment.
|
||||
* @param enchantment The enchantment to register.
|
||||
* @return true if the registration was successful, false if the enchantment name is already in use.
|
||||
*/
|
||||
@Override
|
||||
public boolean registerEnchantment(String plugin, EnchantmentProvider enchantment) {
|
||||
if (enchantmentPluginMap.containsKey(plugin)) return false;
|
||||
enchantmentPluginMap.put(plugin, enchantment);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters an enchantment provided by a plugin.
|
||||
*
|
||||
* @param plugin The name of the plugin providing the enchantment.
|
||||
* @return true if the enchantment was successfully unregistered, false if the enchantment was not found.
|
||||
*/
|
||||
@Override
|
||||
public boolean unregisterEnchantment(String plugin) {
|
||||
return enchantmentPluginMap.remove(plugin) != null;
|
||||
}
|
||||
|
||||
private void hookMessage(String plugin) {
|
||||
LogUtils.info( plugin + " hooked!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the LevelInterface provided by a plugin.
|
||||
*
|
||||
* @param plugin The name of the plugin providing the LevelInterface.
|
||||
* @return The LevelInterface provided by the specified plugin, or null if the plugin is not registered.
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public LevelerProvider getLevelPlugin(String plugin) {
|
||||
return levelPluginMap.get(plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an enchantment plugin by its plugin name.
|
||||
*
|
||||
* @param plugin The name of the enchantment plugin.
|
||||
* @return The enchantment plugin interface, or null if not found.
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public EnchantmentProvider getEnchantmentPlugin(String plugin) {
|
||||
return enchantmentPluginMap.get(plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of enchantment keys with level applied to the given ItemStack.
|
||||
*
|
||||
* @param itemStack The ItemStack to check for enchantments.
|
||||
* @return A list of enchantment names applied to the ItemStack.
|
||||
*/
|
||||
@Override
|
||||
public List<String> getEnchantments(ItemStack itemStack) {
|
||||
ArrayList<String> list = new ArrayList<>();
|
||||
for (EnchantmentProvider enchantmentProvider : enchantmentPluginMap.values()) {
|
||||
list.addAll(enchantmentProvider.getEnchants(itemStack));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current season interface, if available.
|
||||
*
|
||||
* @return The current season interface, or null if not available.
|
||||
*/
|
||||
@Nullable
|
||||
public SeasonProvider getSeasonInterface() {
|
||||
return seasonProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current season interface.
|
||||
*
|
||||
* @param season The season interface to set.
|
||||
*/
|
||||
@Override
|
||||
public void setSeasonInterface(SeasonProvider season) {
|
||||
this.seasonProvider = season;
|
||||
}
|
||||
}
|
||||
@@ -116,7 +116,6 @@ public class BukkitCompetitionManager implements CompetitionManager {
|
||||
YamlDocument document = plugin.getConfigManager().loadData(file);
|
||||
for (Map.Entry<String, Object> entry : document.getStringRouteMappedValues(false).entrySet()) {
|
||||
if (entry.getValue() instanceof Section section) {
|
||||
|
||||
CompetitionConfig.Builder builder = CompetitionConfig.builder()
|
||||
.key(entry.getKey())
|
||||
.goal(CompetitionGoal.index().value(section.getString("goal", "TOTAL_SCORE").toLowerCase(Locale.ENGLISH)))
|
||||
@@ -128,7 +127,6 @@ public class BukkitCompetitionManager implements CompetitionManager {
|
||||
.startActions(plugin.getActionManager().parseActions(section.getSection("start-actions")))
|
||||
.endActions(plugin.getActionManager().parseActions(section.getSection("end-actions")))
|
||||
.skipActions(plugin.getActionManager().parseActions(section.getSection("skip-actions")));;
|
||||
|
||||
if (section.getBoolean("bossbar.enable", false)) {
|
||||
builder.bossBarConfig(
|
||||
BossBarConfig.builder()
|
||||
@@ -142,7 +140,6 @@ public class BukkitCompetitionManager implements CompetitionManager {
|
||||
.build()
|
||||
);
|
||||
}
|
||||
|
||||
if (section.getBoolean("actionbar.enable", false)) {
|
||||
builder.actionBarConfig(
|
||||
ActionBarConfig.builder()
|
||||
@@ -154,7 +151,6 @@ public class BukkitCompetitionManager implements CompetitionManager {
|
||||
.build()
|
||||
);
|
||||
}
|
||||
|
||||
CompetitionConfig competitionConfig = builder.build();
|
||||
List<Pair<Integer, Integer>> timePairs = section.getStringList("start-time")
|
||||
.stream().map(it -> {
|
||||
|
||||
@@ -84,7 +84,7 @@ public class ActionBarSender {
|
||||
DynamicText text = texts[counter % (texts.length)];
|
||||
updatePrivatePlaceholders();
|
||||
text.update(this.privateContext.placeholderMap());
|
||||
audience.sendActionBar(AdventureHelper.miniMessage().deserialize(text.getLatestValue()));
|
||||
audience.sendActionBar(AdventureHelper.miniMessage(text.getLatestValue()));
|
||||
}
|
||||
}, 50, 50, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ public class BossBarSender {
|
||||
texts[i].update(privateContext.placeholderMap());
|
||||
}
|
||||
bossBar = BossBar.bossBar(
|
||||
AdventureHelper.miniMessage().deserialize(texts[0].getLatestValue()),
|
||||
AdventureHelper.miniMessage(texts[0].getLatestValue()),
|
||||
competition.getProgress(),
|
||||
config.color(),
|
||||
config.overlay(),
|
||||
@@ -95,7 +95,7 @@ public class BossBarSender {
|
||||
DynamicText text = texts[counter % (texts.length)];
|
||||
updatePrivatePlaceholders();
|
||||
if (text.update(privateContext.placeholderMap())) {
|
||||
bossBar.name(AdventureHelper.miniMessage().deserialize(text.getLatestValue()));
|
||||
bossBar.name(AdventureHelper.miniMessage(text.getLatestValue()));
|
||||
}
|
||||
bossBar.progress(competition.getProgress());
|
||||
}
|
||||
|
||||
@@ -88,27 +88,27 @@ public class BukkitConfigLoader extends ConfigManager {
|
||||
this.registerBaseEffectParser(object -> {
|
||||
MathValue<Player> mathValue = MathValue.auto(object);
|
||||
return builder -> builder.difficultyAdder(mathValue);
|
||||
}, "base-difficulty-adder");
|
||||
}, "base-effects", "difficulty-adder");
|
||||
this.registerBaseEffectParser(object -> {
|
||||
MathValue<Player> mathValue = MathValue.auto(object);
|
||||
return builder -> builder.difficultyMultiplier(mathValue);
|
||||
}, "base-difficulty-multiplier");
|
||||
}, "base-effects", "difficulty-multiplier");
|
||||
this.registerBaseEffectParser(object -> {
|
||||
MathValue<Player> mathValue = MathValue.auto(object);
|
||||
return builder -> builder.gameTimeAdder(mathValue);
|
||||
}, "base-game-time-adder");
|
||||
}, "base-effects", "game-time-adder");
|
||||
this.registerBaseEffectParser(object -> {
|
||||
MathValue<Player> mathValue = MathValue.auto(object);
|
||||
return builder -> builder.gameTimeMultiplier(mathValue);
|
||||
}, "base-game-time-multiplier");
|
||||
}, "base-effects", "game-time-multiplier");
|
||||
this.registerBaseEffectParser(object -> {
|
||||
MathValue<Player> mathValue = MathValue.auto(object);
|
||||
return builder -> builder.waitTimeAdder(mathValue);
|
||||
}, "base-wait-time-adder");
|
||||
}, "base-effects", "wait-time-adder");
|
||||
this.registerBaseEffectParser(object -> {
|
||||
MathValue<Player> mathValue = MathValue.auto(object);
|
||||
return builder -> builder.waitTimeMultiplier(mathValue);
|
||||
}, "base-wait-time-multiplier");
|
||||
}, "base-effects", "wait-time-multiplier");
|
||||
}
|
||||
|
||||
private void registerBuiltInLootParser() {
|
||||
|
||||
@@ -18,371 +18,35 @@
|
||||
package net.momirealms.customfishing.bukkit.effect;
|
||||
|
||||
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
|
||||
import net.momirealms.customfishing.api.common.Key;
|
||||
import net.momirealms.customfishing.api.common.Pair;
|
||||
import net.momirealms.customfishing.api.mechanic.effect.LootBaseEffectImpl;
|
||||
import net.momirealms.customfishing.api.mechanic.misc.value.MathValue;
|
||||
import net.momirealms.customfishing.api.mechanic.requirement.Requirement;
|
||||
import net.momirealms.customfishing.mechanic.misc.value.PlainMathValue;
|
||||
import net.momirealms.customfishing.bukkit.util.ConfigUtils;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import net.momirealms.customfishing.api.mechanic.effect.EffectManager;
|
||||
import net.momirealms.customfishing.api.mechanic.effect.EffectModifier;
|
||||
import net.momirealms.customfishing.common.util.Key;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.HashMap;
|
||||
import java.util.Optional;
|
||||
|
||||
public class BukkitEffectManager implements EffectManager {
|
||||
|
||||
private final BukkitCustomFishingPlugin plugin;
|
||||
|
||||
private final HashMap<Key, EffectCarrier> effectMap;
|
||||
private final HashMap<Key, EffectModifier> effectModifiers = new HashMap<>();
|
||||
|
||||
public BukkitEffectManager(BukkitCustomFishingPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
this.effectMap = new HashMap<>();
|
||||
}
|
||||
|
||||
public void disable() {
|
||||
this.effectMap.clear();
|
||||
this.effectModifiers.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers an EffectCarrier with a unique Key.
|
||||
*
|
||||
* @param key The unique Key associated with the EffectCarrier.
|
||||
* @param effect The EffectCarrier to be registered.
|
||||
* @return True if the registration was successful, false if the Key already exists.
|
||||
*/
|
||||
@Override
|
||||
public boolean registerEffectCarrier(Key key, EffectCarrier effect) {
|
||||
if (effectMap.containsKey(key)) return false;
|
||||
this.effectMap.put(key, effect);
|
||||
public boolean registerEffectModifier(Key key, EffectModifier effect) {
|
||||
if (effectModifiers.containsKey(key)) return false;
|
||||
this.effectModifiers.put(key, effect);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters an EffectCarrier associated with the specified Key.
|
||||
*
|
||||
* @param key The unique Key of the EffectCarrier to unregister.
|
||||
* @return True if the EffectCarrier was successfully unregistered, false if the Key does not exist.
|
||||
*/
|
||||
@Override
|
||||
public boolean unregisterEffectCarrier(Key key) {
|
||||
return this.effectMap.remove(key) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an EffectCarrier with the specified namespace and id exists.
|
||||
*
|
||||
* @param namespace The namespace of the EffectCarrier.
|
||||
* @param id The unique identifier of the EffectCarrier.
|
||||
* @return True if an EffectCarrier with the given namespace and id exists, false otherwise.
|
||||
*/
|
||||
@Override
|
||||
public boolean hasEffectCarrier(String namespace, String id) {
|
||||
return effectMap.containsKey(Key.of(namespace, id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves an EffectCarrier with the specified namespace and id.
|
||||
*
|
||||
* @param namespace The namespace of the EffectCarrier.
|
||||
* @param id The unique identifier of the EffectCarrier.
|
||||
* @return The EffectCarrier with the given namespace and id, or null if it doesn't exist.
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
public EffectCarrier getEffectCarrier(String namespace, String id) {
|
||||
return effectMap.get(Key.of(namespace, id));
|
||||
}
|
||||
|
||||
public void load() {
|
||||
this.loadFiles();
|
||||
this.loadGlobalEffects();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads EffectCarrier configurations from YAML files in different content folders.
|
||||
* EffectCarrier configurations are organized by type (rod, bait, enchant, util, totem, hook) in separate folders.
|
||||
* Each YAML file within these folders is processed to populate the effectMap.
|
||||
*/
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
private void loadFiles() {
|
||||
Deque<File> fileDeque = new ArrayDeque<>();
|
||||
for (String type : List.of("rod", "bait", "enchant", "util", "totem", "hook")) {
|
||||
File typeFolder = new File(plugin.getDataFolder() + File.separator + "contents" + File.separator + type);
|
||||
if (!typeFolder.exists()) {
|
||||
if (!typeFolder.mkdirs()) return;
|
||||
plugin.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, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads EffectCarrier configurations from a YAML file and populates the effectMap.
|
||||
*
|
||||
* @param file The YAML file to load configurations from.
|
||||
* @param namespace The namespace to use when creating keys for EffectCarriers.
|
||||
*/
|
||||
private void loadSingleFile(File file, String namespace) {
|
||||
YamlConfiguration yaml = YamlConfiguration.loadConfiguration(file);
|
||||
for (Map.Entry<String, Object> entry : yaml.getValues(false).entrySet()) {
|
||||
String value = entry.getKey();
|
||||
if (entry.getValue() instanceof ConfigurationSection section) {
|
||||
Key key = Key.of(namespace, value);
|
||||
EffectCarrier item = getEffectCarrierFromSection(key, section);
|
||||
if (item != null)
|
||||
effectMap.put(key, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a ConfigurationSection to create an EffectCarrier based on the specified key and configuration.
|
||||
*
|
||||
* @param key The key that uniquely identifies the EffectCarrier.
|
||||
* @param section The ConfigurationSection containing the EffectCarrier configuration.
|
||||
* @return An EffectCarrier instance based on the key and configuration, or null if the section is null.
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public EffectCarrier getEffectCarrierFromSection(Key key, ConfigurationSection section) {
|
||||
if (section == null) return null;
|
||||
return new EffectCarrier.Builder()
|
||||
.key(key)
|
||||
.requirements(plugin.getRequirementManager().parseRequirements(section.getConfigurationSection("requirements"), true))
|
||||
.effect(getEffectModifiers(section.getConfigurationSection("effects")))
|
||||
.actionMap(plugin.getActionManager().getActionMap(section.getConfigurationSection("events")))
|
||||
.build();
|
||||
}
|
||||
|
||||
public void unload() {
|
||||
HashMap<Key, EffectCarrier> temp = new HashMap<>(effectMap);
|
||||
effectMap.clear();
|
||||
for (Map.Entry<Key, EffectCarrier> entry : temp.entrySet()) {
|
||||
if (entry.getValue().isPersist()) {
|
||||
effectMap.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the initial FishingEffect that represents no special effects.
|
||||
*
|
||||
* @return The initial FishingEffect.
|
||||
*/
|
||||
@NotNull
|
||||
@Override
|
||||
public FishingEffect getInitialEffect() {
|
||||
return new FishingEffect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a list of modifiers based on specified loot groups.
|
||||
*
|
||||
* @param modList A list of strings containing group modifiers in the format "group:modifier".
|
||||
* @return A list of pairs where each pair represents a loot item and its associated modifier.
|
||||
*/
|
||||
private List<Pair<String, WeightModifier>> getGroupModifiers(List<String> modList) {
|
||||
List<Pair<String, WeightModifier>> result = new ArrayList<>();
|
||||
for (String group : modList) {
|
||||
String[] split = group.split(":",2);
|
||||
String key = split[0];
|
||||
List<String> members = plugin.getLootManager().getGroupMembers(key);
|
||||
if (members == null) {
|
||||
LogUtils.warn("Group " + key + " doesn't contain any loot. The effect would not take effect.");
|
||||
return result;
|
||||
}
|
||||
for (String loot : members) {
|
||||
result.add(Pair.of(loot, ConfigUtils.getModifier(split[1])));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a ConfigurationSection to retrieve an array of EffectModifiers.
|
||||
*
|
||||
* @param section The ConfigurationSection to parse.
|
||||
* @return An array of EffectModifiers based on the values found in the section.
|
||||
*/
|
||||
@NotNull
|
||||
@Override
|
||||
public EffectModifier[] getEffectModifiers(ConfigurationSection section) {
|
||||
if (section == null) return new EffectModifier[0];
|
||||
ArrayList<EffectModifier> modifiers = new ArrayList<>();
|
||||
for (Map.Entry<String, Object> entry: section.getValues(false).entrySet()) {
|
||||
if (entry.getValue() instanceof ConfigurationSection inner) {
|
||||
EffectModifier effectModifier = getEffectModifier(inner);
|
||||
if (effectModifier != null)
|
||||
modifiers.add(effectModifier);
|
||||
}
|
||||
}
|
||||
return modifiers.toArray(new EffectModifier[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LootBaseEffectImpl getBaseEffect(ConfigurationSection section) {
|
||||
if (section == null) return new LootBaseEffectImpl(
|
||||
new PlainMathValue(0), new PlainMathValue(1d),
|
||||
new PlainMathValue(0), new PlainMathValue(1d),
|
||||
new PlainMathValue(0), new PlainMathValue(1d)
|
||||
);
|
||||
MathValue waitTime = section.contains("wait-time") ? ConfigUtils.getValue(section.get("wait-time")) : new PlainMathValue(0);
|
||||
MathValue difficulty = section.contains("difficulty") ? ConfigUtils.getValue(section.get("difficulty")) : new PlainMathValue(0);
|
||||
MathValue gameTime = section.contains("game-time") ? ConfigUtils.getValue(section.get("game-time")) : new PlainMathValue(0);
|
||||
MathValue waitTimeMultiplier = section.contains("wait-time-multiplier") ? ConfigUtils.getValue(section.get("wait-time-multiplier")) : new PlainMathValue(1);
|
||||
MathValue difficultyMultiplier = section.contains("difficulty-multiplier") ? ConfigUtils.getValue(section.get("difficulty-multiplier")) : new PlainMathValue(1);
|
||||
MathValue gameTimeMultiplier = section.contains("game-time-multiplier") ? ConfigUtils.getValue(section.get("game-time-multiplier")) : new PlainMathValue(1);
|
||||
return new LootBaseEffectImpl(
|
||||
waitTime, waitTimeMultiplier,
|
||||
difficulty, difficultyMultiplier,
|
||||
gameTime, gameTimeMultiplier
|
||||
);
|
||||
}
|
||||
|
||||
private void loadGlobalEffects() {
|
||||
YamlConfiguration config = plugin.getConfig("config.yml");
|
||||
ConfigurationSection section = config.getConfigurationSection("mechanics.global-effects");
|
||||
GlobalSettings.setEffects(getEffectModifiers(section));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a ConfigurationSection to create an EffectModifier based on the specified type and configuration.
|
||||
*
|
||||
* @param section The ConfigurationSection containing the effect modifier configuration.
|
||||
* @return An EffectModifier instance based on the type and configuration.
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public EffectModifier getEffectModifier(ConfigurationSection section) {
|
||||
String type = section.getString("type");
|
||||
if (type == null) return null;
|
||||
switch (type) {
|
||||
case "weight-mod" -> {
|
||||
var modList = ConfigUtils.getModifiers(section.getStringList("value"));
|
||||
return ((effect, condition) -> {
|
||||
effect.addWeightModifier(modList);
|
||||
});
|
||||
}
|
||||
case "weight-mod-ignore-conditions" -> {
|
||||
var modList = ConfigUtils.getModifiers(section.getStringList("value"));
|
||||
return ((effect, condition) -> {
|
||||
effect.addWeightModifierIgnored(modList);
|
||||
});
|
||||
}
|
||||
case "group-mod" -> {
|
||||
var modList = getGroupModifiers(section.getStringList("value"));
|
||||
return ((effect, condition) -> {
|
||||
effect.addWeightModifier(modList);
|
||||
});
|
||||
}
|
||||
case "group-mod-ignore-conditions" -> {
|
||||
var modList = getGroupModifiers(section.getStringList("value"));
|
||||
return ((effect, condition) -> {
|
||||
effect.addWeightModifierIgnored(modList);
|
||||
});
|
||||
}
|
||||
case "wait-time" -> {
|
||||
var value = ConfigUtils.getValue(section.get("value"));
|
||||
return ((effect, condition) -> {
|
||||
effect.setWaitTime(effect.waitTimeAdder() + value.get(condition.getPlayer(), condition.getArgs()));
|
||||
});
|
||||
}
|
||||
case "hook-time", "wait-time-multiplier" -> {
|
||||
var value = ConfigUtils.getValue(section.get("value"));
|
||||
return ((effect, condition) -> {
|
||||
effect.setWaitTimeMultiplier(effect.getWaitTimeMultiplier() + value.get(condition.getPlayer(), condition.getArgs()) - 1);
|
||||
});
|
||||
}
|
||||
case "difficulty" -> {
|
||||
var value = ConfigUtils.getValue(section.get("value"));
|
||||
return ((effect, condition) -> {
|
||||
effect.setDifficulty(effect.difficultyAdder() + value.get(condition.getPlayer(), condition.getArgs()));
|
||||
});
|
||||
}
|
||||
case "difficulty-multiplier", "difficulty-bonus" -> {
|
||||
var value = ConfigUtils.getValue(section.get("value"));
|
||||
return ((effect, condition) -> {
|
||||
effect.setDifficultyMultiplier(effect.difficultyMultiplier() + value.get(condition.getPlayer(), condition.getArgs()) - 1);
|
||||
});
|
||||
}
|
||||
case "multiple-loot" -> {
|
||||
var value = ConfigUtils.getValue(section.get("value"));
|
||||
return ((effect, condition) -> {
|
||||
effect.setMultipleLootChance(effect.multipleLootChance() + value.get(condition.getPlayer(), condition.getArgs()));
|
||||
});
|
||||
}
|
||||
case "score" -> {
|
||||
var value = ConfigUtils.getValue(section.get("value"));
|
||||
return ((effect, condition) -> {
|
||||
effect.setScore(effect.scoreAdder() + value.get(condition.getPlayer(), condition.getArgs()));
|
||||
});
|
||||
}
|
||||
case "score-bonus", "score-multiplier" -> {
|
||||
var value = ConfigUtils.getValue(section.get("value"));
|
||||
return ((effect, condition) -> {
|
||||
effect.setScoreMultiplier(effect.scoreMultiplier() + value.get(condition.getPlayer(), condition.getArgs()) - 1);
|
||||
});
|
||||
}
|
||||
case "size" -> {
|
||||
var value = ConfigUtils.getValue(section.get("value"));
|
||||
return ((effect, condition) -> {
|
||||
effect.setSize(effect.sizeAdder() + value.get(condition.getPlayer(), condition.getArgs()));
|
||||
});
|
||||
}
|
||||
case "size-bonus", "size-multiplier" -> {
|
||||
var value = ConfigUtils.getValue(section.get("value"));
|
||||
return ((effect, condition) -> {
|
||||
effect.setSizeMultiplier(effect.sizeMultiplier() + value.get(condition.getPlayer(), condition.getArgs()) - 1);
|
||||
});
|
||||
}
|
||||
case "game-time" -> {
|
||||
var value = ConfigUtils.getValue(section.get("value"));
|
||||
return ((effect, condition) -> {
|
||||
effect.setGameTime(effect.gameTimeAdder() + value.get(condition.getPlayer(), condition.getArgs()));
|
||||
});
|
||||
}
|
||||
case "game-time-bonus", "game-time-multiplier" -> {
|
||||
var value = ConfigUtils.getValue(section.get("value"));
|
||||
return ((effect, condition) -> {
|
||||
effect.setGameTimeMultiplier(effect.gameTimeMultiplier() + value.get(condition.getPlayer(), condition.getArgs()) - 1);
|
||||
});
|
||||
}
|
||||
case "lava-fishing" -> {
|
||||
return ((effect, condition) -> effect.setLavaFishing(true));
|
||||
}
|
||||
case "conditional" -> {
|
||||
Requirement[] requirements = plugin.getRequirementManager().parseRequirements(section.getConfigurationSection("conditions"), true);
|
||||
EffectModifier[] modifiers = getEffectModifiers(section.getConfigurationSection("effects"));
|
||||
return ((effect, condition) -> {
|
||||
for (Requirement requirement : requirements)
|
||||
if (!requirement.check(condition))
|
||||
return;
|
||||
for (EffectModifier modifier : modifiers) {
|
||||
modifier.modify(effect, condition);
|
||||
}
|
||||
});
|
||||
}
|
||||
default -> {
|
||||
LogUtils.warn("Effect " + type + " doesn't exist.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public Optional<EffectModifier> getEffectModifier(Key key) {
|
||||
return Optional.ofNullable(this.effectModifiers.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,162 +19,98 @@ package net.momirealms.customfishing.bukkit.entity;
|
||||
|
||||
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
|
||||
import net.momirealms.customfishing.api.integration.EntityProvider;
|
||||
import net.momirealms.customfishing.api.mechanic.entity.EntityConfigImpl;
|
||||
import net.momirealms.customfishing.api.mechanic.context.Context;
|
||||
import net.momirealms.customfishing.api.mechanic.context.ContextKeys;
|
||||
import net.momirealms.customfishing.api.mechanic.entity.EntityConfig;
|
||||
import net.momirealms.customfishing.api.mechanic.entity.EntityManager;
|
||||
import net.momirealms.customfishing.api.mechanic.loot.Loot;
|
||||
import net.momirealms.customfishing.bukkit.compatibility.entity.VanillaEntityProvider;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.util.Vector;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
public class BukkitEntityManager implements EntityManager {
|
||||
|
||||
private final BukkitCustomFishingPlugin plugin;
|
||||
private final HashMap<String, EntityProvider> entityLibraryMap;
|
||||
private final HashMap<String, EntityConfigImpl> entityConfigMap;
|
||||
private final HashMap<String, EntityProvider> entityProviders = new HashMap<>();
|
||||
private final HashMap<String, EntityConfig> entities = new HashMap<>();
|
||||
|
||||
public BukkitEntityManager(BukkitCustomFishingPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
this.entityLibraryMap = new HashMap<>();
|
||||
this.entityConfigMap = new HashMap<>();
|
||||
this.registerEntityProvider(new VanillaEntityProvider());
|
||||
}
|
||||
|
||||
public void load() {
|
||||
this.loadConfig();
|
||||
}
|
||||
|
||||
public void unload() {
|
||||
HashMap<String, EntityConfigImpl> tempMap = new HashMap<>(this.entityConfigMap);
|
||||
this.entityConfigMap.clear();
|
||||
for (Map.Entry<String, EntityConfigImpl> entry : tempMap.entrySet()) {
|
||||
if (entry.getValue().isPersist()) {
|
||||
tempMap.put(entry.getKey(), entry.getValue());
|
||||
this.registerEntityProvider(new EntityProvider() {
|
||||
@Override
|
||||
public String identifier() {
|
||||
return "vanilla";
|
||||
}
|
||||
}
|
||||
@NotNull
|
||||
@Override
|
||||
public Entity spawn(@NotNull Location location, @NotNull String id, @NotNull Map<String, Object> propertyMap) {
|
||||
return location.getWorld().spawnEntity(location, EntityType.valueOf(id.toUpperCase(Locale.ENGLISH)));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers an entity library for use in the plugin.
|
||||
*
|
||||
* @param entityProvider The entity library to register.
|
||||
* @return {@code true} if the entity library was successfully registered, {@code false} if it already exists.
|
||||
*/
|
||||
@Override
|
||||
public boolean registerEntityProvider(EntityProvider entityProvider) {
|
||||
if (entityLibraryMap.containsKey(entityProvider.identifier())) return false;
|
||||
else entityLibraryMap.put(entityProvider.identifier(), entityProvider);
|
||||
public void unload() {
|
||||
this.entities.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disable() {
|
||||
unload();
|
||||
this.entityProviders.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<EntityConfig> getEntity(String id) {
|
||||
return Optional.ofNullable(this.entities.get(id));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean registerEntity(String id, EntityConfig entity) {
|
||||
if (entities.containsKey(id)) return false;
|
||||
this.entities.put(id, entity);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters an entity library by its identification key.
|
||||
*
|
||||
* @param identification The identification key of the entity library to unregister.
|
||||
* @return {@code true} if the entity library was successfully unregistered, {@code false} if it does not exist.
|
||||
*/
|
||||
public boolean registerEntityProvider(EntityProvider entityProvider) {
|
||||
if (entityProviders.containsKey(entityProvider.identifier())) return false;
|
||||
else entityProviders.put(entityProvider.identifier(), entityProvider);
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean unregisterEntityProvider(String id) {
|
||||
return entityProviders.remove(id) != null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public boolean unregisterEntityProvider(String identification) {
|
||||
return entityLibraryMap.remove(identification) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load configuration files for entity properties.
|
||||
*/
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
private void loadConfig() {
|
||||
Deque<File> fileDeque = new ArrayDeque<>();
|
||||
for (String type : List.of("entity")) {
|
||||
File typeFolder = new File(plugin.getDataFolder() + File.separator + "contents" + File.separator + type);
|
||||
if (!typeFolder.exists()) {
|
||||
if (!typeFolder.mkdirs()) return;
|
||||
plugin.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a single entity configuration file.
|
||||
*
|
||||
* @param file The YAML file to load.
|
||||
*/
|
||||
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) {
|
||||
String entityID = section.getString("entity");
|
||||
if (entityID == null) {
|
||||
LogUtils.warn("Entity can't be null. File:" + file.getAbsolutePath() + "; Section:" + section.getCurrentPath());
|
||||
continue;
|
||||
}
|
||||
HashMap<String, Object> propertyMap = new HashMap<>();
|
||||
ConfigurationSection property = section.getConfigurationSection("properties");
|
||||
if (property != null) {
|
||||
propertyMap.putAll(property.getValues(false));
|
||||
}
|
||||
EntityConfigImpl entityConfigImpl = new EntityConfigImpl.BuilderImpl()
|
||||
.entityID(entityID)
|
||||
.persist(false)
|
||||
.horizontalVector(section.getDouble("velocity.horizontal", 1.1))
|
||||
.verticalVector(section.getDouble("velocity.vertical", 1.2))
|
||||
.propertyMap(propertyMap)
|
||||
.build();
|
||||
entityConfigMap.put(entry.getKey(), entityConfigImpl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void disable() {
|
||||
unload();
|
||||
this.entityConfigMap.clear();
|
||||
this.entityLibraryMap.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Summons an entity based on the given loot configuration to a specified location.
|
||||
*
|
||||
* @param hookLocation The location where the entity will be summoned, typically where the fishing hook is.
|
||||
* @param playerLocation The location of the player who triggered the entity summoning.
|
||||
* @param loot The loot configuration that defines the entity to be summoned.
|
||||
*/
|
||||
@Override
|
||||
public void summonEntity(Location hookLocation, Location playerLocation, Loot loot) {
|
||||
EntityConfigImpl config = entityConfigMap.get(loot.getID());
|
||||
if (config == null) {
|
||||
LogUtils.warn("Entity: " + loot.getID() + " doesn't exist.");
|
||||
return;
|
||||
}
|
||||
public Entity summonEntityLoot(Context<Player> context) {
|
||||
String id = context.arg(ContextKeys.ID);
|
||||
EntityConfig config = requireNonNull(entities.get(id), "Entity " + id + " not found");
|
||||
Location hookLocation = requireNonNull(context.arg(ContextKeys.HOOK_LOCATION));
|
||||
Location playerLocation = requireNonNull(context.getHolder().getLocation());
|
||||
String entityID = config.getEntityID();
|
||||
Entity entity;
|
||||
if (entityID.contains(":")) {
|
||||
String[] split = entityID.split(":", 2);
|
||||
String identification = split[0];
|
||||
String id = split[1];
|
||||
EntityProvider library = entityLibraryMap.get(identification);
|
||||
entity = library.spawn(hookLocation, id, config.getPropertyMap());
|
||||
EntityProvider provider = requireNonNull(entityProviders.get(split[0]), "EntityProvider " + split[0] + " doesn't exist");
|
||||
entity = requireNonNull(provider.spawn(hookLocation, split[1], config.getPropertyMap()), "Entity " + entityID + " doesn't exist");
|
||||
} else {
|
||||
entity = entityLibraryMap.get("vanilla").spawn(hookLocation, entityID, config.getPropertyMap());
|
||||
entity = entityProviders.get("vanilla").spawn(hookLocation, entityID, config.getPropertyMap());
|
||||
}
|
||||
Vector vector = playerLocation.subtract(hookLocation).toVector().multiply((config.getHorizontalVector()) - 1);
|
||||
vector = vector.setY((vector.getY() + 0.2) * config.getVerticalVector());
|
||||
entity.setVelocity(vector);
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,32 +1,73 @@
|
||||
package net.momirealms.customfishing.bukkit.event;
|
||||
|
||||
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.event.EventCarrier;
|
||||
import net.momirealms.customfishing.api.mechanic.event.EventManager;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.event.player.PlayerItemConsumeEvent;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Optional;
|
||||
|
||||
public class BukkitEventManager implements EventManager {
|
||||
public class BukkitEventManager implements EventManager, Listener {
|
||||
|
||||
private final HashMap<String, EventCarrier> carrierMap = new HashMap<>();
|
||||
private BukkitCustomFishingPlugin plugin;
|
||||
private final HashMap<String, EventCarrier> carriers = new HashMap<>();
|
||||
private final BukkitCustomFishingPlugin plugin;
|
||||
|
||||
public BukkitEventManager(BukkitCustomFishingPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unload() {
|
||||
this.carriers.clear();
|
||||
HandlerList.unregisterAll(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
Bukkit.getPluginManager().registerEvents(this, plugin.getBoostrap());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<EventCarrier> getEventCarrier(String id) {
|
||||
return Optional.ofNullable(carrierMap.get(id));
|
||||
return Optional.ofNullable(carriers.get(id));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean registerEventCarrier(String id, EventCarrier carrier) {
|
||||
if (carrierMap.containsKey(id)) {
|
||||
return false;
|
||||
}
|
||||
carrierMap.put(id, carrier);
|
||||
if (carriers.containsKey(id)) return false;
|
||||
carriers.put(id, carrier);
|
||||
return true;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onInteract(PlayerInteractEvent event) {
|
||||
if (event.getHand() != EquipmentSlot.HAND)
|
||||
return;
|
||||
if (event.getAction() != org.bukkit.event.block.Action.RIGHT_CLICK_AIR && event.getAction() != org.bukkit.event.block.Action.RIGHT_CLICK_BLOCK)
|
||||
return;
|
||||
ItemStack itemStack = event.getPlayer().getInventory().getItemInMainHand();
|
||||
if (itemStack.getType() == Material.AIR || itemStack.getAmount() == 0)
|
||||
return;
|
||||
String id = plugin.getItemManager().getItemID(itemStack);
|
||||
Optional.ofNullable(carriers.get(id)).ifPresent(carrier -> {
|
||||
carrier.trigger(Context.player(event.getPlayer()), ActionTrigger.INTERACT);
|
||||
});
|
||||
}
|
||||
|
||||
@EventHandler (ignoreCancelled = true)
|
||||
public void onConsumeItem(PlayerItemConsumeEvent event) {
|
||||
Optional.ofNullable(carriers.get(plugin.getItemManager().getItemID(event.getItem())))
|
||||
.ifPresent(carrier -> carrier.trigger(Context.player(event.getPlayer()), ActionTrigger.CONSUME));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
/*
|
||||
* 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.fishing;
|
||||
|
||||
import net.momirealms.customfishing.bukkit.BukkitCustomFishingPluginImpl;
|
||||
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
|
||||
import net.momirealms.customfishing.api.scheduler.CancellableTask;
|
||||
import net.momirealms.customfishing.bukkit.util.FakeItemUtils;
|
||||
import org.bukkit.entity.FishHook;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* A task responsible for animating bait when it's attached to a fishing hook.
|
||||
*/
|
||||
public class BaitAnimationTask implements Runnable {
|
||||
|
||||
private final CancellableTask cancellableTask;
|
||||
private final int entityID;
|
||||
private final Player player;
|
||||
private final FishHook fishHook;
|
||||
|
||||
/**
|
||||
* Constructs a new BaitAnimationTask.
|
||||
*
|
||||
* @param plugin The CustomFishingPlugin instance.
|
||||
* @param player The player who cast the fishing rod.
|
||||
* @param fishHook The FishHook entity.
|
||||
* @param baitItem The bait ItemStack.
|
||||
*/
|
||||
public BaitAnimationTask(BukkitCustomFishingPlugin plugin, Player player, FishHook fishHook, ItemStack baitItem) {
|
||||
this.player = player;
|
||||
this.fishHook = fishHook;
|
||||
entityID = ThreadLocalRandom.current().nextInt(Integer.MAX_VALUE);
|
||||
if (plugin.getVersionManager().isVersionNewerThan1_19_4()) {
|
||||
BukkitCustomFishingPluginImpl.sendPackets(player, FakeItemUtils.getSpawnPacket(entityID, fishHook.getLocation()), FakeItemUtils.getMetaPacket(entityID, baitItem));
|
||||
} else {
|
||||
BukkitCustomFishingPluginImpl.sendPacket(player, FakeItemUtils.getSpawnPacket(entityID, fishHook.getLocation()));
|
||||
BukkitCustomFishingPluginImpl.sendPacket(player, FakeItemUtils.getMetaPacket(entityID, baitItem));
|
||||
}
|
||||
this.cancellableTask = plugin.getScheduler().runTaskAsyncTimer(this, 50, 50, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if ( fishHook == null
|
||||
|| fishHook.isOnGround()
|
||||
|| fishHook.isInLava()
|
||||
|| fishHook.isInWater()
|
||||
|| !fishHook.isValid()
|
||||
) {
|
||||
cancelAnimation();
|
||||
} else {
|
||||
BukkitCustomFishingPluginImpl.getProtocolManager().sendServerPacket(player, FakeItemUtils.getVelocityPacket(entityID, fishHook.getVelocity()));
|
||||
BukkitCustomFishingPluginImpl.getProtocolManager().sendServerPacket(player, FakeItemUtils.getTpPacket(entityID, fishHook.getLocation()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels the bait animation and cleans up resources.
|
||||
*/
|
||||
private void cancelAnimation() {
|
||||
cancellableTask.cancel();
|
||||
BukkitCustomFishingPluginImpl.getProtocolManager().sendServerPacket(player, FakeItemUtils.getDestroyPacket(entityID));
|
||||
}
|
||||
}
|
||||
@@ -1,872 +0,0 @@
|
||||
/*
|
||||
* 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.fishing;
|
||||
|
||||
import com.destroystokyo.paper.event.player.PlayerJumpEvent;
|
||||
import de.tr7zw.changeme.nbtapi.NBTCompound;
|
||||
import de.tr7zw.changeme.nbtapi.NBTItem;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import net.kyori.adventure.sound.Sound;
|
||||
import net.momirealms.customfishing.bukkit.BukkitCustomFishingPluginImpl;
|
||||
import net.momirealms.customfishing.api.common.Pair;
|
||||
import net.momirealms.customfishing.api.event.FishingResultEvent;
|
||||
import net.momirealms.customfishing.api.event.LavaFishingEvent;
|
||||
import net.momirealms.customfishing.api.event.RodCastEvent;
|
||||
import net.momirealms.customfishing.api.mechanic.action.ActionTrigger;
|
||||
import net.momirealms.customfishing.api.mechanic.competition.FishingCompetition;
|
||||
import net.momirealms.customfishing.api.mechanic.effect.Effect;
|
||||
import net.momirealms.customfishing.api.mechanic.fishing.FishingManager;
|
||||
import net.momirealms.customfishing.api.mechanic.game.BasicGameConfig;
|
||||
import net.momirealms.customfishing.api.mechanic.game.GameInstance;
|
||||
import net.momirealms.customfishing.api.mechanic.game.GameSettings;
|
||||
import net.momirealms.customfishing.api.mechanic.game.GamingPlayer;
|
||||
import net.momirealms.customfishing.api.mechanic.loot.Loot;
|
||||
import net.momirealms.customfishing.api.mechanic.loot.LootType;
|
||||
import net.momirealms.customfishing.api.mechanic.requirement.RequirementManager;
|
||||
import net.momirealms.customfishing.api.util.WeightUtils;
|
||||
import net.momirealms.customfishing.bukkit.util.ItemUtils;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.entity.*;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.event.player.*;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class BukkitFishingManager implements Listener, FishingManager {
|
||||
|
||||
private final BukkitCustomFishingPluginImpl plugin;
|
||||
private final ConcurrentHashMap<UUID, FishHook> hookCacheMap;
|
||||
private final ConcurrentHashMap<UUID, HookCheckTimerTask> hookCheckMap;
|
||||
private final ConcurrentHashMap<UUID, TempFishingState> tempFishingStateMap;
|
||||
private final ConcurrentHashMap<UUID, GamingPlayer> gamingPlayerMap;
|
||||
private final ConcurrentHashMap<UUID, Pair<ItemStack, Integer>> vanillaLootMap;
|
||||
|
||||
public BukkitFishingManager(BukkitCustomFishingPluginImpl plugin) {
|
||||
this.plugin = plugin;
|
||||
this.hookCacheMap = new ConcurrentHashMap<>();
|
||||
this.tempFishingStateMap = new ConcurrentHashMap<>();
|
||||
this.gamingPlayerMap = new ConcurrentHashMap<>();
|
||||
this.hookCheckMap = new ConcurrentHashMap<>();
|
||||
this.vanillaLootMap = new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
public void load() {
|
||||
Bukkit.getPluginManager().registerEvents(this, plugin);
|
||||
}
|
||||
|
||||
public void unload() {
|
||||
HandlerList.unregisterAll(this);
|
||||
for (FishHook hook : hookCacheMap.values()) {
|
||||
hook.remove();
|
||||
}
|
||||
for (HookCheckTimerTask task : hookCheckMap.values()) {
|
||||
task.destroy();
|
||||
}
|
||||
for (GamingPlayer gamingPlayer : gamingPlayerMap.values()) {
|
||||
gamingPlayer.cancel();
|
||||
}
|
||||
this.hookCacheMap.clear();
|
||||
this.tempFishingStateMap.clear();
|
||||
this.gamingPlayerMap.clear();
|
||||
this.hookCheckMap.clear();
|
||||
}
|
||||
|
||||
public void disable() {
|
||||
unload();
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onFishMONITOR(PlayerFishEvent event) {
|
||||
if (CFConfig.eventPriority != EventPriority.MONITOR) return;
|
||||
this.selectState(event);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onFishHIGHEST(PlayerFishEvent event) {
|
||||
if (CFConfig.eventPriority != EventPriority.HIGHEST) return;
|
||||
this.selectState(event);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH)
|
||||
public void onFishHIGH(PlayerFishEvent event) {
|
||||
if (CFConfig.eventPriority != EventPriority.HIGH) return;
|
||||
this.selectState(event);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.NORMAL)
|
||||
public void onFishNORMAL(PlayerFishEvent event) {
|
||||
if (CFConfig.eventPriority != EventPriority.NORMAL) return;
|
||||
this.selectState(event);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOW)
|
||||
public void onFishLOW(PlayerFishEvent event) {
|
||||
if (CFConfig.eventPriority != EventPriority.LOW) return;
|
||||
this.selectState(event);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onFishLOWEST(PlayerFishEvent event) {
|
||||
if (CFConfig.eventPriority != EventPriority.LOWEST) return;
|
||||
this.selectState(event);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onQuit(PlayerQuitEvent event) {
|
||||
final Player player = event.getPlayer();
|
||||
final UUID uuid = player.getUniqueId();
|
||||
this.removeHook(uuid);
|
||||
this.removeTempFishingState(player);
|
||||
this.removeHookCheckTask(player);
|
||||
this.vanillaLootMap.remove(uuid);
|
||||
GamingPlayer gamingPlayer = gamingPlayerMap.remove(player.getUniqueId());
|
||||
if (gamingPlayer != null) {
|
||||
gamingPlayer.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Known bug: This is a Minecraft packet limitation
|
||||
* When you fish, both left click air and right click air
|
||||
* are triggered. And you can't cancel the left click event.
|
||||
*/
|
||||
@EventHandler (ignoreCancelled = false)
|
||||
public void onLeftClick(PlayerInteractEvent event) {
|
||||
if (event.getAction() != Action.LEFT_CLICK_AIR)
|
||||
return;
|
||||
if (event.getMaterial() != Material.FISHING_ROD)
|
||||
return;
|
||||
if (event.getHand() != EquipmentSlot.HAND)
|
||||
return;
|
||||
GamingPlayer gamingPlayer = gamingPlayerMap.get(event.getPlayer().getUniqueId());
|
||||
if (gamingPlayer != null) {
|
||||
if (gamingPlayer.onLeftClick())
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler (ignoreCancelled = true)
|
||||
public void onSwapHand(PlayerSwapHandItemsEvent event) {
|
||||
GamingPlayer gamingPlayer = gamingPlayerMap.get(event.getPlayer().getUniqueId());
|
||||
if (gamingPlayer != null) {
|
||||
if (gamingPlayer.onSwapHand())
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onJump(PlayerJumpEvent event) {
|
||||
if (event.isCancelled()) return;
|
||||
GamingPlayer gamingPlayer = gamingPlayerMap.get(event.getPlayer().getUniqueId());
|
||||
if (gamingPlayer != null) {
|
||||
if (gamingPlayer.onJump())
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onSneak(PlayerToggleSneakEvent event) {
|
||||
if (event.isCancelled()) return;
|
||||
if (!event.isSneaking()) return;
|
||||
GamingPlayer gamingPlayer = gamingPlayerMap.get(event.getPlayer().getUniqueId());
|
||||
if (gamingPlayer != null) {
|
||||
if (gamingPlayer.onSneak())
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onChat(AsyncPlayerChatEvent event) {
|
||||
if (event.isCancelled()) return;
|
||||
GamingPlayer gamingPlayer = gamingPlayerMap.get(event.getPlayer().getUniqueId());
|
||||
if (gamingPlayer != null) {
|
||||
if (gamingPlayer.onChat(event.getMessage()))
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a fishing hook entity associated with a given UUID.
|
||||
*
|
||||
* @param uuid The UUID of the fishing hook entity to be removed.
|
||||
* @return {@code true} if the fishing hook was successfully removed, {@code false} otherwise.
|
||||
*/
|
||||
@Override
|
||||
public boolean removeHook(UUID uuid) {
|
||||
FishHook hook = hookCacheMap.remove(uuid);
|
||||
if (hook != null && hook.isValid()) {
|
||||
plugin.getScheduler().runTaskSync(hook::remove, hook.getLocation());
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a FishHook object associated with the provided player's UUID
|
||||
*
|
||||
* @param uuid The UUID of the player
|
||||
* @return fishhook entity, null if not exists
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public FishHook getHook(UUID uuid) {
|
||||
FishHook fishHook = hookCacheMap.get(uuid);
|
||||
if (fishHook != null) {
|
||||
if (!fishHook.isValid()) {
|
||||
hookCacheMap.remove(uuid);
|
||||
return null;
|
||||
} else {
|
||||
return fishHook;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects the appropriate fishing state based on the provided PlayerFishEvent and triggers the corresponding action.
|
||||
*
|
||||
* @param event The PlayerFishEvent that represents the fishing action.
|
||||
*/
|
||||
public void selectState(PlayerFishEvent event) {
|
||||
if (event.isCancelled()) return;
|
||||
switch (event.getState()) {
|
||||
case FISHING -> onCastRod(event);
|
||||
case REEL_IN -> onReelIn(event);
|
||||
case CAUGHT_ENTITY -> onCaughtEntity(event);
|
||||
case CAUGHT_FISH -> onCaughtFish(event);
|
||||
case BITE -> onBite(event);
|
||||
case IN_GROUND -> onInGround(event);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the event when the fishing hook lands on the ground.
|
||||
*
|
||||
* @param event The PlayerFishEvent that occurred.
|
||||
*/
|
||||
private void onInGround(PlayerFishEvent event) {
|
||||
final Player player = event.getPlayer();
|
||||
FishHook hook = event.getHook();
|
||||
if (player.getGameMode() != GameMode.CREATIVE) {
|
||||
ItemStack itemStack = player.getInventory().getItemInMainHand();
|
||||
if (itemStack.getType() != Material.FISHING_ROD) itemStack = player.getInventory().getItemInOffHand();
|
||||
if (itemStack.getType() == Material.FISHING_ROD) {
|
||||
NBTItem nbtItem = new NBTItem(itemStack);
|
||||
NBTCompound compound = nbtItem.getCompound("CustomFishing");
|
||||
if (compound != null && compound.hasTag("max_dur")) {
|
||||
event.setCancelled(true);
|
||||
hook.remove();
|
||||
ItemUtils.decreaseDurability(player, itemStack, 2, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the event when a player casts a fishing rod.
|
||||
*
|
||||
* @param event The PlayerFishEvent that occurred.
|
||||
*/
|
||||
public void onCastRod(PlayerFishEvent event) {
|
||||
var player = event.getPlayer();
|
||||
var fishingPreparation = new FishingPreparationImpl(player, plugin);
|
||||
if (!fishingPreparation.canFish()) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
// Check mechanic requirements
|
||||
if (!RequirementManager.isRequirementMet(
|
||||
fishingPreparation, RequirementManagerImpl.mechanicRequirements
|
||||
)) {
|
||||
this.removeTempFishingState(player);
|
||||
return;
|
||||
}
|
||||
FishingEffect initialEffect = plugin.getEffectManager().getInitialEffect();
|
||||
// Merge totem effects
|
||||
EffectCarrier totemEffect = plugin.getTotemManager().getTotemEffect(player.getLocation());
|
||||
if (totemEffect != null)
|
||||
for (EffectModifier modifier : totemEffect.getEffectModifiers()) {
|
||||
modifier.modify(initialEffect, fishingPreparation);
|
||||
}
|
||||
|
||||
// Call custom event
|
||||
RodCastEvent rodCastEvent = new RodCastEvent(event, fishingPreparation, initialEffect);
|
||||
Bukkit.getPluginManager().callEvent(rodCastEvent);
|
||||
if (rodCastEvent.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Store fishhook entity and apply the effects
|
||||
final FishHook fishHook = event.getHook();
|
||||
this.hookCacheMap.put(player.getUniqueId(), fishHook);
|
||||
|
||||
// Reduce amount & Send animation
|
||||
var baitItem = fishingPreparation.getBaitItemStack();
|
||||
if (baitItem != null) {
|
||||
ItemStack cloned = baitItem.clone();
|
||||
cloned.setAmount(1);
|
||||
new BaitAnimationTask(plugin, player, fishHook, cloned);
|
||||
baitItem.setAmount(baitItem.getAmount() - 1);
|
||||
}
|
||||
|
||||
// Arrange hook check task
|
||||
this.hookCheckMap.put(player.getUniqueId(), new HookCheckTimerTask(this, fishHook, fishingPreparation, initialEffect));
|
||||
// trigger actions
|
||||
fishingPreparation.triggerActions(ActionTrigger.CAST);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the event when a player catches an entity.
|
||||
*
|
||||
* @param event The PlayerFishEvent that occurred.
|
||||
*/
|
||||
private void onCaughtEntity(PlayerFishEvent event) {
|
||||
final Player player = event.getPlayer();
|
||||
final UUID uuid = player.getUniqueId();
|
||||
|
||||
Entity entity = event.getCaught();
|
||||
if ((entity instanceof ArmorStand armorStand)
|
||||
&& armorStand.getPersistentDataContainer().get(
|
||||
Objects.requireNonNull(NamespacedKey.fromString("lavafishing", plugin)),
|
||||
PersistentDataType.STRING
|
||||
) != null) {
|
||||
// The hook is hooked into the temp entity
|
||||
// This might be called both not in game and in game
|
||||
LavaFishingEvent lavaFishingEvent = new LavaFishingEvent(player, LavaFishingEvent.State.REEL_IN, event.getHook());
|
||||
Bukkit.getPluginManager().callEvent(lavaFishingEvent);
|
||||
if (lavaFishingEvent.isCancelled()) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
GamingPlayer gamingPlayer = gamingPlayerMap.get(uuid);
|
||||
if (gamingPlayer != null) {
|
||||
// in game
|
||||
if (gamingPlayer.onRightClick())
|
||||
event.setCancelled(true);
|
||||
} else {
|
||||
// not in game
|
||||
HookCheckTimerTask task = hookCheckMap.get(uuid);
|
||||
if (task != null)
|
||||
task.destroy();
|
||||
else
|
||||
// should not reach this but in case
|
||||
entity.remove();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.getGameMode() != GameMode.CREATIVE) {
|
||||
ItemStack itemStack = player.getInventory().getItemInMainHand();
|
||||
if (itemStack.getType() != Material.FISHING_ROD) itemStack = player.getInventory().getItemInOffHand();
|
||||
NBTItem nbtItem = new NBTItem(itemStack);
|
||||
NBTCompound nbtCompound = nbtItem.getCompound("CustomFishing");
|
||||
if (nbtCompound != null && nbtCompound.hasTag("max_dur")) {
|
||||
event.getHook().remove();
|
||||
event.setCancelled(true);
|
||||
ItemUtils.decreaseDurability(player, itemStack, 5, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the event when a player catches a fish.
|
||||
*
|
||||
* @param event The PlayerFishEvent that occurred.
|
||||
*/
|
||||
private void onCaughtFish(PlayerFishEvent event) {
|
||||
final Player player = event.getPlayer();
|
||||
final UUID uuid = player.getUniqueId();
|
||||
if (!(event.getCaught() instanceof Item item))
|
||||
return;
|
||||
|
||||
// If player is playing the game
|
||||
GamingPlayer gamingPlayer = gamingPlayerMap.get(uuid);
|
||||
if (gamingPlayer != null) {
|
||||
if (gamingPlayer.onRightClick())
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// If player is not playing the game
|
||||
var temp = this.getTempFishingState(uuid);
|
||||
if (temp != null) {
|
||||
var loot = temp.getLoot();
|
||||
if (loot.getID().equals("vanilla")) {
|
||||
// put vanilla loot in map
|
||||
this.vanillaLootMap.put(uuid, Pair.of(item.getItemStack(), event.getExpToDrop()));
|
||||
}
|
||||
var fishingPreparation = temp.getPreparation();
|
||||
loot.triggerActions(ActionTrigger.HOOK, fishingPreparation);
|
||||
fishingPreparation.triggerActions(ActionTrigger.HOOK);
|
||||
if (!loot.disableGame()) {
|
||||
// start the game if the loot has a game
|
||||
if (startFishingGame(player, fishingPreparation, temp.getEffect())) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
} else {
|
||||
// remove temp state if fishing game not exists
|
||||
this.removeTempFishingState(player);
|
||||
var hook = event.getHook();
|
||||
// If the game is disabled, then do success actions
|
||||
success(temp, hook);
|
||||
// Cancel the event because loots can be multiple and unique
|
||||
event.setCancelled(true);
|
||||
hook.remove();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the event when a player receives a bite on their fishing hook.
|
||||
*
|
||||
* @param event The PlayerFishEvent that occurred.
|
||||
*/
|
||||
private void onBite(PlayerFishEvent event) {
|
||||
final Player player = event.getPlayer();
|
||||
final UUID uuid = player.getUniqueId();
|
||||
|
||||
// If player is already in game
|
||||
// then ignore the event
|
||||
GamingPlayer gamingPlayer = getGamingPlayer(uuid);
|
||||
if (gamingPlayer != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the loot's game is instant
|
||||
TempFishingState temp = getTempFishingState(uuid);
|
||||
if (temp != null) {
|
||||
var loot = temp.getLoot();
|
||||
var fishingPreparation = temp.getPreparation();
|
||||
fishingPreparation.setLocation(event.getHook().getLocation());
|
||||
|
||||
if (!loot.disableGlobalAction())
|
||||
GlobalSettings.triggerLootActions(ActionTrigger.BITE, fishingPreparation);
|
||||
loot.triggerActions(ActionTrigger.BITE, fishingPreparation);
|
||||
fishingPreparation.triggerActions(ActionTrigger.BITE);
|
||||
|
||||
if (loot.instantGame() && !loot.disableGame()) {
|
||||
if (!loot.disableGlobalAction())
|
||||
GlobalSettings.triggerLootActions(ActionTrigger.HOOK, fishingPreparation);
|
||||
loot.triggerActions(ActionTrigger.HOOK, fishingPreparation);
|
||||
fishingPreparation.triggerActions(ActionTrigger.HOOK);
|
||||
startFishingGame(player, fishingPreparation, temp.getEffect());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the event when a player reels in their fishing line.
|
||||
*
|
||||
* @param event The PlayerFishEvent that occurred.
|
||||
*/
|
||||
private void onReelIn(PlayerFishEvent event) {
|
||||
final Player player = event.getPlayer();
|
||||
final UUID uuid = player.getUniqueId();
|
||||
|
||||
// If player is in game
|
||||
GamingPlayer gamingPlayer = getGamingPlayer(uuid);
|
||||
if (gamingPlayer != null) {
|
||||
if (gamingPlayer.onRightClick())
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// If player is lava fishing
|
||||
HookCheckTimerTask hookTask = hookCheckMap.get(uuid);
|
||||
if (hookTask != null && hookTask.isFishHooked()) {
|
||||
LavaFishingEvent lavaFishingEvent = new LavaFishingEvent(player, LavaFishingEvent.State.CAUGHT_FISH, event.getHook());
|
||||
Bukkit.getPluginManager().callEvent(lavaFishingEvent);
|
||||
if (lavaFishingEvent.isCancelled()) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
var temp = getTempFishingState(uuid);
|
||||
if (temp != null ) {
|
||||
Loot loot = temp.getLoot();
|
||||
var fishingPreparation = temp.getPreparation();
|
||||
if (!loot.disableGlobalAction())
|
||||
GlobalSettings.triggerLootActions(ActionTrigger.HOOK, fishingPreparation);
|
||||
loot.triggerActions(ActionTrigger.HOOK, fishingPreparation);
|
||||
fishingPreparation.triggerActions(ActionTrigger.HOOK);
|
||||
if (!loot.disableGame()) {
|
||||
event.setCancelled(true);
|
||||
startFishingGame(player, fishingPreparation, temp.getEffect());
|
||||
} else {
|
||||
success(temp, event.getHook());
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the temporary fishing state associated with a player.
|
||||
*
|
||||
* @param player The player whose temporary fishing state should be removed.
|
||||
*/
|
||||
@Override
|
||||
public TempFishingState removeTempFishingState(Player player) {
|
||||
return this.tempFishingStateMap.remove(player.getUniqueId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the game result for a gaming player
|
||||
*
|
||||
* @param gamingPlayer The gaming player whose game result should be processed.
|
||||
*/
|
||||
@Override
|
||||
public void processGameResult(GamingPlayer gamingPlayer) {
|
||||
final Player player = gamingPlayer.getPlayer();
|
||||
final UUID uuid = player.getUniqueId();
|
||||
FishHook fishHook = hookCacheMap.remove(uuid);
|
||||
if (fishHook == null) {
|
||||
LogUtils.warn("Unexpected situation: Can't get player's fish hook when processing game results.");
|
||||
return;
|
||||
}
|
||||
TempFishingState tempFishingState = removeTempFishingState(player);
|
||||
if (tempFishingState == null) {
|
||||
LogUtils.warn("Unexpected situation: Can't get player's fishing state when processing game results.");
|
||||
return;
|
||||
}
|
||||
Effect bonus = gamingPlayer.getEffectReward();
|
||||
if (bonus != null)
|
||||
tempFishingState.getEffect().merge(bonus);
|
||||
|
||||
gamingPlayer.cancel();
|
||||
gamingPlayerMap.remove(uuid);
|
||||
plugin.getScheduler().runTaskSync(() -> {
|
||||
|
||||
if (gamingPlayer.isSuccessful()) {
|
||||
success(tempFishingState, fishHook);
|
||||
} else {
|
||||
fail(tempFishingState, fishHook);
|
||||
}
|
||||
|
||||
fishHook.remove();
|
||||
|
||||
}, fishHook.getLocation());
|
||||
}
|
||||
|
||||
public void fail(TempFishingState state, FishHook hook) {
|
||||
var loot = state.getLoot();
|
||||
var fishingPreparation = state.getPreparation();
|
||||
|
||||
if (loot.getID().equals("vanilla")) {
|
||||
Pair<ItemStack, Integer> pair = this.vanillaLootMap.remove(fishingPreparation.getPlayer().getUniqueId());
|
||||
if (pair != null) {
|
||||
fishingPreparation.insertArg("{nick}", "<lang:item.minecraft." + pair.left().getType().toString().toLowerCase() + ">");
|
||||
fishingPreparation.insertArg("{loot}", pair.left().getType().toString());
|
||||
}
|
||||
}
|
||||
|
||||
// call event
|
||||
FishingResultEvent fishingResultEvent = new FishingResultEvent(
|
||||
fishingPreparation.getPlayer(),
|
||||
FishingResultEvent.Result.FAILURE,
|
||||
hook,
|
||||
loot,
|
||||
fishingPreparation.getArgs()
|
||||
);
|
||||
Bukkit.getPluginManager().callEvent(fishingResultEvent);
|
||||
if (fishingResultEvent.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!loot.disableGlobalAction())
|
||||
GlobalSettings.triggerLootActions(ActionTrigger.FAILURE, fishingPreparation);
|
||||
loot.triggerActions(ActionTrigger.FAILURE, fishingPreparation);
|
||||
fishingPreparation.triggerActions(ActionTrigger.FAILURE);
|
||||
|
||||
if (state.getPreparation().getPlayer().getGameMode() != GameMode.CREATIVE) {
|
||||
ItemUtils.decreaseHookDurability(fishingPreparation.getRodItemStack(), 1, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the success of a fishing attempt, including spawning loot, calling events, and executing success actions.
|
||||
*
|
||||
* @param state The temporary fishing state containing information about the loot and effect.
|
||||
* @param hook The FishHook entity associated with the fishing attempt.
|
||||
*/
|
||||
public void success(TempFishingState state, FishHook hook) {
|
||||
var loot = state.getLoot();
|
||||
var effect = state.getEffect();
|
||||
var fishingPreparation = state.getPreparation();
|
||||
var player = fishingPreparation.getPlayer();
|
||||
fishingPreparation.insertArg("{size-multiplier}", String.valueOf(effect.sizeMultiplier()));
|
||||
fishingPreparation.insertArg("{size-fixed}", String.valueOf(effect.sizeAdder()));
|
||||
int amount;
|
||||
if (loot.getType() == LootType.ITEM) {
|
||||
amount = (int) effect.multipleLootChance();
|
||||
amount += Math.random() < (effect.multipleLootChance() - amount) ? 2 : 1;
|
||||
} else {
|
||||
amount = 1;
|
||||
}
|
||||
fishingPreparation.insertArg("{amount}", String.valueOf(amount));
|
||||
|
||||
// call event
|
||||
FishingResultEvent fishingResultEvent = new FishingResultEvent(
|
||||
player,
|
||||
FishingResultEvent.Result.SUCCESS,
|
||||
hook,
|
||||
loot,
|
||||
fishingPreparation.getArgs()
|
||||
);
|
||||
Bukkit.getPluginManager().callEvent(fishingResultEvent);
|
||||
if (fishingResultEvent.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (loot.getType()) {
|
||||
case ITEM -> {
|
||||
// build the items for multiple times instead of using setAmount() to make sure that each item is unique
|
||||
if (loot.getID().equals("vanilla")) {
|
||||
Pair<ItemStack, Integer> pair = vanillaLootMap.remove(player.getUniqueId());
|
||||
if (pair != null) {
|
||||
fishingPreparation.insertArg("{nick}", "<lang:item.minecraft." + pair.left().getType().toString().toLowerCase() + ">");
|
||||
for (int i = 0; i < amount; i++) {
|
||||
plugin.getScheduler().runTaskSyncLater(() -> {
|
||||
plugin.getItemManager().dropItem(player, hook.getLocation(), player.getLocation(), pair.left().clone(), fishingPreparation);
|
||||
doSuccessActions(loot, effect, fishingPreparation, player);
|
||||
if (pair.right() > 0) {
|
||||
player.giveExp(pair.right(), true);
|
||||
AdventureHelper.getInstance().sendSound(player, Sound.Source.PLAYER, Key.key("minecraft:entity.experience_orb.pickup"), 1, 1);
|
||||
}
|
||||
}, hook.getLocation(), (long) CFConfig.multipleLootSpawnDelay * i);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < amount; i++) {
|
||||
plugin.getScheduler().runTaskSyncLater(() -> {
|
||||
ItemStack item = plugin.getItemManager().buildInternal(player, "item", loot.getID(), fishingPreparation.getArgs());
|
||||
if (item == null) {
|
||||
LogUtils.warn(String.format("Item %s not exists", loot.getID()));
|
||||
return;
|
||||
}
|
||||
plugin.getItemManager().dropItem(player, hook.getLocation(), player.getLocation(), item, fishingPreparation);
|
||||
doSuccessActions(loot, effect, fishingPreparation, player);
|
||||
}, hook.getLocation(), (long) CFConfig.multipleLootSpawnDelay * i);
|
||||
}
|
||||
}
|
||||
}
|
||||
case ENTITY -> {
|
||||
plugin.getEntityManager().summonEntity(hook.getLocation(), player.getLocation(), loot);
|
||||
doSuccessActions(loot, effect, fishingPreparation, player);
|
||||
}
|
||||
case BLOCK -> {
|
||||
plugin.getBlockManager().summonBlock(player, hook.getLocation(), player.getLocation(), loot);
|
||||
doSuccessActions(loot, effect, fishingPreparation, player);
|
||||
}
|
||||
}
|
||||
|
||||
if (player.getGameMode() != GameMode.CREATIVE) {
|
||||
ItemStack rod = state.getPreparation().getRodItemStack();
|
||||
ItemUtils.decreaseHookDurability(rod, 1, false);
|
||||
ItemUtils.decreaseDurability(player, rod, 1, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute success-related actions after a successful fishing attempt, including updating competition data, triggering events and actions, and updating player statistics.
|
||||
*
|
||||
* @param loot The loot that was successfully caught.
|
||||
* @param effect The effect applied during fishing.
|
||||
* @param fishingPreparation The fishing preparation containing preparation data.
|
||||
* @param player The player who successfully caught the loot.
|
||||
*/
|
||||
private void doSuccessActions(Loot loot, Effect effect, FishingPreparation fishingPreparation, Player player) {
|
||||
FishingCompetition competition = plugin.getCompetitionManager().getOnGoingCompetition();
|
||||
if (competition != null && RequirementManager.isRequirementMet(fishingPreparation, competition.getConfig().getJoinRequirements())) {
|
||||
String scoreStr = fishingPreparation.getArg("{CUSTOM_SCORE}");
|
||||
if (scoreStr != null) {
|
||||
competition.refreshData(player, Double.parseDouble(scoreStr));
|
||||
} else {
|
||||
double score = 0;
|
||||
switch (competition.getGoal()) {
|
||||
case CATCH_AMOUNT -> {
|
||||
score = 1;
|
||||
competition.refreshData(player, score);
|
||||
}
|
||||
case MAX_SIZE, TOTAL_SIZE -> {
|
||||
String size = fishingPreparation.getArg("{SIZE}");
|
||||
if (size != null) {
|
||||
score = Double.parseDouble(size);
|
||||
competition.refreshData(player, score);
|
||||
} else {
|
||||
score = 0;
|
||||
}
|
||||
}
|
||||
case TOTAL_SCORE -> {
|
||||
score = loot.getScore();
|
||||
if (score > 0) {
|
||||
score = score * effect.scoreMultiplier() + effect.scoreAdder();
|
||||
competition.refreshData(player, score);
|
||||
} else {
|
||||
score = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
fishingPreparation.insertArg("{score}", String.format("%.2f", score));
|
||||
fishingPreparation.insertArg("{SCORE}", String.valueOf(score));
|
||||
}
|
||||
}
|
||||
|
||||
// events and actions
|
||||
if (!loot.disableGlobalAction())
|
||||
GlobalSettings.triggerLootActions(ActionTrigger.SUCCESS, fishingPreparation);
|
||||
loot.triggerActions(ActionTrigger.SUCCESS, fishingPreparation);
|
||||
fishingPreparation.triggerActions(ActionTrigger.SUCCESS);
|
||||
|
||||
player.setStatistic(
|
||||
Statistic.FISH_CAUGHT,
|
||||
player.getStatistic(Statistic.FISH_CAUGHT) + 1
|
||||
);
|
||||
|
||||
if (!loot.disableStats())
|
||||
Optional.ofNullable(
|
||||
plugin.getStatisticsManager()
|
||||
.getStatistics(player.getUniqueId())
|
||||
).ifPresent(it -> {
|
||||
it.addLootAmount(loot, fishingPreparation, 1);
|
||||
String size = fishingPreparation.getArg("{SIZE}");
|
||||
if (size != null)
|
||||
if (it.setSizeIfHigher(loot.getStatisticKey().sizeKey(), Float.parseFloat(size))) {
|
||||
if (!loot.disableGlobalAction())
|
||||
GlobalSettings.triggerLootActions(ActionTrigger.NEW_SIZE_RECORD, fishingPreparation);
|
||||
loot.triggerActions(ActionTrigger.NEW_SIZE_RECORD, fishingPreparation);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a fishing game for the specified player with the given condition and effect.
|
||||
*
|
||||
* @param player The player starting the fishing game.
|
||||
* @param playerContext The condition used to determine the game.
|
||||
* @param effect The effect applied to the game.
|
||||
*/
|
||||
@Override
|
||||
public boolean startFishingGame(Player player, PlayerContext playerContext, Effect effect) {
|
||||
Map<String, Double> gameWithWeight = plugin.getGameManager().getGameWithWeight(playerContext);
|
||||
String random = WeightUtils.getRandom(gameWithWeight);
|
||||
Pair<BasicGameConfig, GameInstance> gamePair = plugin.getGameManager().getGameInstance(random);
|
||||
if (random == null) {
|
||||
LogUtils.warn("No game is available for player:" + player.getName() + " location:" + playerContext.getLocation());
|
||||
return false;
|
||||
}
|
||||
if (gamePair == null) {
|
||||
LogUtils.warn(String.format("Game %s doesn't exist.", random));
|
||||
return false;
|
||||
}
|
||||
plugin.debug("Game: " + random);
|
||||
return startFishingGame(player, Objects.requireNonNull(gamePair.left().getGameSetting(effect)), gamePair.right());
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a fishing game for the specified player with the given settings and game instance.
|
||||
*
|
||||
* @param player The player starting the fishing game.
|
||||
* @param settings The game settings for the fishing game.
|
||||
* @param gameInstance The instance of the fishing game to start.
|
||||
*/
|
||||
@Override
|
||||
public boolean startFishingGame(Player player, GameSettings settings, GameInstance gameInstance) {
|
||||
plugin.debug("Difficulty:" + settings.difficulty());
|
||||
plugin.debug("Time:" + settings.time());
|
||||
FishHook hook = getHook(player.getUniqueId());
|
||||
if (hook != null) {
|
||||
this.gamingPlayerMap.put(player.getUniqueId(), gameInstance.start(player, hook, settings));
|
||||
return true;
|
||||
} else {
|
||||
LogUtils.warn("It seems that player " + player.getName() + " is not fishing. Fishing game failed to start.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a player with the given UUID has cast their fishing hook.
|
||||
*
|
||||
* @param uuid The UUID of the player to check.
|
||||
* @return {@code true} if the player has cast their fishing hook, {@code false} otherwise.
|
||||
*/
|
||||
@Override
|
||||
public boolean hasPlayerCastHook(UUID uuid) {
|
||||
FishHook fishHook = hookCacheMap.get(uuid);
|
||||
if (fishHook == null) return false;
|
||||
if (!fishHook.isValid()) {
|
||||
hookCacheMap.remove(uuid);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the temporary fishing state for a player.
|
||||
*
|
||||
* @param player The player for whom to set the temporary fishing state.
|
||||
* @param tempFishingState The temporary fishing state to set for the player.
|
||||
*/
|
||||
@Override
|
||||
public void setTempFishingState(Player player, TempFishingState tempFishingState) {
|
||||
tempFishingStateMap.put(player.getUniqueId(), tempFishingState);
|
||||
}
|
||||
|
||||
public void removeHookCheckTask(Player player) {
|
||||
hookCheckMap.remove(player.getUniqueId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link GamingPlayer} object associated with the given UUID.
|
||||
*
|
||||
* @param uuid The UUID of the player.
|
||||
* @return The {@link GamingPlayer} object if found, or {@code null} if not found.
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public GamingPlayer getGamingPlayer(UUID uuid) {
|
||||
return gamingPlayerMap.get(uuid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link TempFishingState} object associated with the given UUID.
|
||||
*
|
||||
* @param uuid The UUID of the player.
|
||||
* @return The {@link TempFishingState} object if found, or {@code null} if not found.
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public TempFishingState getTempFishingState(UUID uuid) {
|
||||
return tempFishingStateMap.get(uuid);
|
||||
}
|
||||
}
|
||||
@@ -1,188 +0,0 @@
|
||||
/*
|
||||
* 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.fishing;
|
||||
|
||||
import de.tr7zw.changeme.nbtapi.NBTCompound;
|
||||
import de.tr7zw.changeme.nbtapi.NBTItem;
|
||||
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
|
||||
import net.momirealms.customfishing.api.mechanic.action.Action;
|
||||
import net.momirealms.customfishing.api.mechanic.action.ActionTrigger;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.PlayerInventory;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
public class FishingPreparationImpl extends FishingPreparation {
|
||||
|
||||
private boolean hasBait = false;
|
||||
private boolean hasHook = false;
|
||||
private @Nullable ItemStack baitItemStack;
|
||||
private final @NotNull ItemStack rodItemStack;
|
||||
private final List<EffectCarrier> effects;
|
||||
private boolean canFish = true;
|
||||
|
||||
public FishingPreparationImpl(Player player, BukkitCustomFishingPlugin plugin) {
|
||||
super(player);
|
||||
|
||||
PlayerInventory playerInventory = player.getInventory();
|
||||
ItemStack mainHandItem = playerInventory.getItemInMainHand();
|
||||
ItemStack offHandItem = playerInventory.getItemInOffHand();
|
||||
|
||||
this.effects = new ArrayList<>();
|
||||
boolean rodOnMainHand = mainHandItem.getType() == Material.FISHING_ROD;
|
||||
this.rodItemStack = rodOnMainHand ? mainHandItem : offHandItem;
|
||||
String rodItemID = plugin.getItemManager().getAnyPluginItemID(this.rodItemStack);
|
||||
EffectCarrier rodEffect = plugin.getEffectManager().getEffectCarrier("rod", rodItemID);
|
||||
if (rodEffect != null) effects.add(rodEffect);
|
||||
super.insertArg("{rod}", rodItemID);
|
||||
|
||||
NBTItem nbtItem = new NBTItem(rodItemStack);
|
||||
NBTCompound cfCompound = nbtItem.getCompound("CustomFishing");
|
||||
if (cfCompound != null && cfCompound.hasTag("hook_id")) {
|
||||
String hookID = cfCompound.getString("hook_id");
|
||||
super.insertArg("{hook}", hookID);
|
||||
this.hasHook = true;
|
||||
EffectCarrier carrier = plugin.getEffectManager().getEffectCarrier("hook", hookID);
|
||||
if (carrier != null) {
|
||||
this.effects.add(carrier);
|
||||
}
|
||||
}
|
||||
|
||||
String baitItemID = plugin.getItemManager().getAnyPluginItemID(rodOnMainHand ? offHandItem : mainHandItem);
|
||||
EffectCarrier baitEffect = plugin.getEffectManager().getEffectCarrier("bait", baitItemID);
|
||||
|
||||
if (baitEffect != null) {
|
||||
this.baitItemStack = rodOnMainHand ? offHandItem : mainHandItem;
|
||||
this.effects.add(baitEffect);
|
||||
this.hasBait = true;
|
||||
super.insertArg("{bait}", baitItemID);
|
||||
}
|
||||
|
||||
if (plugin.getBagManager().isEnabled()) {
|
||||
Inventory fishingBag = plugin.getBagManager().getOnlineBagInventory(player.getUniqueId());
|
||||
HashSet<String> uniqueUtils = new HashSet<>(4);
|
||||
if (fishingBag != null) {
|
||||
this.insertArg("{in-bag}", "true");
|
||||
for (int i = 0; i < fishingBag.getSize(); i++) {
|
||||
ItemStack itemInBag = fishingBag.getItem(i);
|
||||
String bagItemID = plugin.getItemManager().getAnyPluginItemID(itemInBag);
|
||||
if (!hasBait) {
|
||||
EffectCarrier effect = plugin.getEffectManager().getEffectCarrier("bait", bagItemID);
|
||||
if (effect != null) {
|
||||
this.hasBait = true;
|
||||
this.baitItemStack = itemInBag;
|
||||
this.effects.add(effect);
|
||||
super.insertArg("{bait}", bagItemID);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
EffectCarrier utilEffect = plugin.getEffectManager().getEffectCarrier("util", bagItemID);
|
||||
if (utilEffect != null && !uniqueUtils.contains(bagItemID)) {
|
||||
effects.add(utilEffect);
|
||||
uniqueUtils.add(bagItemID);
|
||||
}
|
||||
}
|
||||
this.delArg("{in-bag}");
|
||||
}
|
||||
}
|
||||
|
||||
for (String enchant : plugin.getIntegrationManager().getEnchantments(rodItemStack)) {
|
||||
EffectCarrier enchantEffect = plugin.getEffectManager().getEffectCarrier("enchant", enchant);
|
||||
if (enchantEffect != null) {
|
||||
this.effects.add(enchantEffect);
|
||||
}
|
||||
}
|
||||
|
||||
for (EffectCarrier effectCarrier : effects) {
|
||||
if (!effectCarrier.isConditionMet(this)) {
|
||||
this.canFish = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the ItemStack representing the fishing rod.
|
||||
*
|
||||
* @return The ItemStack representing the fishing rod.
|
||||
*/
|
||||
@NotNull
|
||||
public ItemStack getRodItemStack() {
|
||||
return rodItemStack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the ItemStack representing the bait (if available).
|
||||
*
|
||||
* @return The ItemStack representing the bait, or null if no bait is set.
|
||||
*/
|
||||
@Nullable
|
||||
public ItemStack getBaitItemStack() {
|
||||
return baitItemStack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if player meet the requirements for fishing gears
|
||||
*
|
||||
* @return True if can fish, false otherwise.
|
||||
*/
|
||||
public boolean canFish() {
|
||||
return this.canFish;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges a FishingEffect into this fishing rod, applying effect modifiers.
|
||||
*
|
||||
* @param effect The FishingEffect to merge into this rod.
|
||||
*/
|
||||
public void mergeEffect(FishingEffect effect) {
|
||||
for (EffectModifier modifier : GlobalSettings.getEffectModifiers()) {
|
||||
modifier.modify(effect, this);
|
||||
}
|
||||
for (EffectCarrier effectCarrier : effects) {
|
||||
for (EffectModifier modifier : effectCarrier.getEffectModifiers()) {
|
||||
modifier.modify(effect, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers actions associated with a specific action trigger.
|
||||
*
|
||||
* @param actionTrigger The action trigger that initiates the actions.
|
||||
*/
|
||||
public void triggerActions(ActionTrigger actionTrigger) {
|
||||
GlobalSettings.triggerRodActions(actionTrigger, this);
|
||||
if (hasBait) GlobalSettings.triggerBaitActions(actionTrigger, this);
|
||||
if (hasHook) GlobalSettings.triggerHookActions(actionTrigger, this);
|
||||
for (EffectCarrier effectCarrier : effects) {
|
||||
Action[] actions = effectCarrier.getActions(actionTrigger);
|
||||
if (actions != null)
|
||||
for (Action action : actions) {
|
||||
action.trigger(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,353 +0,0 @@
|
||||
/*
|
||||
* 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.fishing;
|
||||
|
||||
import net.kyori.adventure.key.Key;
|
||||
import net.kyori.adventure.sound.Sound;
|
||||
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
|
||||
import net.momirealms.customfishing.api.event.FishHookLandEvent;
|
||||
import net.momirealms.customfishing.api.event.LavaFishingEvent;
|
||||
import net.momirealms.customfishing.api.mechanic.action.ActionTrigger;
|
||||
import net.momirealms.customfishing.api.mechanic.effect.Effect;
|
||||
import net.momirealms.customfishing.api.mechanic.loot.Loot;
|
||||
import net.momirealms.customfishing.api.scheduler.CancellableTask;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.entity.ArmorStand;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.FishHook;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* A task responsible for checking the state of a fishing hook and handling lava fishing mechanics.
|
||||
*/
|
||||
public class HookCheckTimerTask implements Runnable {
|
||||
|
||||
private final BukkitFishingManager manager;
|
||||
private final CancellableTask hookMovementTask;
|
||||
private LavaEffectTask lavaFishingTask;
|
||||
private final FishHook fishHook;
|
||||
private final FishingPreparation fishingPreparation;
|
||||
private final FishingEffect initialEffect;
|
||||
private Effect tempEffect;
|
||||
private final int lureLevel;
|
||||
private boolean firstTime;
|
||||
private boolean fishHooked;
|
||||
private boolean reserve;
|
||||
private int jumpTimer;
|
||||
private Entity hookedEntity;
|
||||
private Loot loot;
|
||||
private boolean inWater;
|
||||
|
||||
/**
|
||||
* Constructs a new HookCheckTimerTask.
|
||||
*
|
||||
* @param manager The FishingManagerImpl instance.
|
||||
* @param fishHook The FishHook entity being checked.
|
||||
* @param fishingPreparation The FishingPreparation instance.
|
||||
* @param initialEffect The initial fishing effect.
|
||||
*/
|
||||
public HookCheckTimerTask(
|
||||
BukkitFishingManager manager,
|
||||
FishHook fishHook,
|
||||
FishingPreparation fishingPreparation,
|
||||
FishingEffect initialEffect
|
||||
) {
|
||||
this.inWater = false;
|
||||
this.manager = manager;
|
||||
this.fishHook = fishHook;
|
||||
this.initialEffect = initialEffect;
|
||||
this.fishingPreparation = fishingPreparation;
|
||||
this.hookMovementTask = BukkitCustomFishingPlugin.get().getScheduler().runTaskSyncTimer(this, fishHook.getLocation(), 1, 1);
|
||||
this.lureLevel = fishingPreparation.getRodItemStack().getEnchantmentLevel(Enchantment.LURE);
|
||||
this.firstTime = true;
|
||||
this.tempEffect = new FishingEffect();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (
|
||||
!this.fishHook.isValid()
|
||||
//|| (fishHook.getHookedEntity() != null && fishHook.getHookedEntity().getType() != EntityType.ARMOR_STAND)
|
||||
) {
|
||||
// This task would be cancelled when hook is removed
|
||||
this.destroy();
|
||||
return;
|
||||
}
|
||||
if (this.fishHook.isOnGround()) {
|
||||
this.inWater = false;
|
||||
return;
|
||||
}
|
||||
if (this.fishHook.getLocation().getBlock().getType() == Material.LAVA) {
|
||||
this.inWater = false;
|
||||
// if player can fish in lava
|
||||
if (firstTime) {
|
||||
this.firstTime = false;
|
||||
|
||||
this.fishingPreparation.setLocation(this.fishHook.getLocation());
|
||||
this.fishingPreparation.mergeEffect(this.initialEffect);
|
||||
if (!initialEffect.allowLavaFishing()) {
|
||||
this.destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
FishHookLandEvent event = new FishHookLandEvent(this.fishingPreparation.getPlayer(), FishHookLandEvent.Target.LAVA, this.fishHook, true, this.initialEffect);
|
||||
Bukkit.getPluginManager().callEvent(event);
|
||||
|
||||
this.fishingPreparation.insertArg("{lava}", "true");
|
||||
this.fishingPreparation.triggerActions(ActionTrigger.LAND);
|
||||
}
|
||||
|
||||
// simulate fishing mechanic
|
||||
if (this.fishHooked) {
|
||||
this.jumpTimer++;
|
||||
if (this.jumpTimer < 4)
|
||||
return;
|
||||
this.jumpTimer = 0;
|
||||
this.fishHook.setVelocity(new Vector(0,0.24,0));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.reserve) {
|
||||
// jump
|
||||
if (this.jumpTimer < 5) {
|
||||
this.jumpTimer++;
|
||||
this.fishHook.setVelocity(new Vector(0,0.2 - this.jumpTimer * 0.02,0));
|
||||
return;
|
||||
}
|
||||
|
||||
this.reserve = true;
|
||||
|
||||
this.setNextLoot();
|
||||
if (this.loot != null) {
|
||||
this.tempEffect = this.loot.baseEffect().build(fishingPreparation.getPlayer(), fishingPreparation.getArgs());
|
||||
this.tempEffect.merge(this.initialEffect);
|
||||
this.setTempState();
|
||||
this.startLavaFishingMechanic();
|
||||
} else {
|
||||
this.tempEffect = new FishingEffect();
|
||||
this.tempEffect.merge(this.initialEffect);
|
||||
this.manager.removeTempFishingState(fishingPreparation.getPlayer());
|
||||
BukkitCustomFishingPlugin.get().debug("No loot available for " + fishingPreparation.getPlayer().getName() + " at " + fishingPreparation.getLocation());
|
||||
}
|
||||
|
||||
this.makeHookStatic(this.fishHook.getLocation());
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!this.inWater && this.fishHook.isInWater()) {
|
||||
this.inWater = true;
|
||||
|
||||
this.fishingPreparation.setLocation(this.fishHook.getLocation());
|
||||
this.fishingPreparation.insertArg("{lava}", "false");
|
||||
this.fishingPreparation.insertArg("{open-water}", String.valueOf(this.fishHook.isInOpenWater()));
|
||||
|
||||
if (this.firstTime) {
|
||||
this.firstTime = false;
|
||||
this.fishingPreparation.mergeEffect(this.initialEffect);
|
||||
|
||||
FishHookLandEvent event = new FishHookLandEvent(this.fishingPreparation.getPlayer(), FishHookLandEvent.Target.WATER, this.fishHook, false, this.initialEffect);
|
||||
Bukkit.getPluginManager().callEvent(event);
|
||||
|
||||
this.fishingPreparation.triggerActions(ActionTrigger.LAND);
|
||||
|
||||
} else {
|
||||
FishHookLandEvent event = new FishHookLandEvent(this.fishingPreparation.getPlayer(), FishHookLandEvent.Target.WATER, this.fishHook, true, this.initialEffect);
|
||||
Bukkit.getPluginManager().callEvent(event);
|
||||
}
|
||||
|
||||
this.setNextLoot();
|
||||
if (this.loot == null) {
|
||||
// prevent players from getting vanilla loots
|
||||
this.fishHook.setWaitTime(Integer.MAX_VALUE);
|
||||
this.tempEffect = new FishingEffect();
|
||||
this.tempEffect.merge(this.initialEffect);
|
||||
this.manager.removeTempFishingState(fishingPreparation.getPlayer());
|
||||
BukkitCustomFishingPlugin.get().debug("No loot available for " + fishingPreparation.getPlayer().getName() + " at " + fishingPreparation.getLocation());
|
||||
} else {
|
||||
this.tempEffect = this.loot.baseEffect().build(fishingPreparation.getPlayer(), fishingPreparation.getArgs());
|
||||
this.tempEffect.merge(this.initialEffect);
|
||||
this.setWaitTime();
|
||||
this.setTempState();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys the task and associated entities.
|
||||
*/
|
||||
public void destroy() {
|
||||
this.cancelSubTask();
|
||||
this.removeTempEntity();
|
||||
this.hookMovementTask.cancel();
|
||||
this.manager.removeHookCheckTask(fishingPreparation.getPlayer());
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels the lava fishing subtask if it's active.
|
||||
*/
|
||||
public void cancelSubTask() {
|
||||
if (lavaFishingTask != null && !lavaFishingTask.isCancelled()) {
|
||||
lavaFishingTask.cancel();
|
||||
lavaFishingTask = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void setNextLoot() {
|
||||
Loot nextLoot = BukkitCustomFishingPlugin.get().getLootManager().getNextLoot(initialEffect, fishingPreparation);
|
||||
if (nextLoot == null) {
|
||||
this.loot = null;
|
||||
return;
|
||||
}
|
||||
this.loot = nextLoot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets temporary state and prepares for the next loot.
|
||||
*/
|
||||
private void setTempState() {
|
||||
fishingPreparation.insertArg("{nick}", loot.getNick());
|
||||
fishingPreparation.insertArg("{loot}", loot.getID());
|
||||
if (!loot.disableStats()) {
|
||||
fishingPreparation.insertArg("{statistics_size}", loot.getStatisticKey().sizeKey());
|
||||
fishingPreparation.insertArg("{statistics_amount}", loot.getStatisticKey().amountKey());
|
||||
}
|
||||
manager.setTempFishingState(fishingPreparation.getPlayer(), new TempFishingState(
|
||||
tempEffect,
|
||||
fishingPreparation,
|
||||
loot
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the temporary hooked entity.
|
||||
*/
|
||||
public void removeTempEntity() {
|
||||
if (hookedEntity != null && !hookedEntity.isDead())
|
||||
hookedEntity.remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the lava fishing mechanic.
|
||||
*/
|
||||
private void startLavaFishingMechanic() {
|
||||
// get random time
|
||||
int random;
|
||||
if (CFConfig.overrideVanilla) {
|
||||
random = ThreadLocalRandom.current().nextInt(CFConfig.lavaMinTime, CFConfig.lavaMaxTime);
|
||||
random *= tempEffect.waitTimeMultiplier();
|
||||
random += tempEffect.waitTimeAdder();
|
||||
random = Math.max(1, random);
|
||||
} else {
|
||||
random = ThreadLocalRandom.current().nextInt(CFConfig.lavaMinTime, CFConfig.lavaMaxTime);
|
||||
random -= lureLevel * 100;
|
||||
random = Math.max(CFConfig.lavaMinTime, random);
|
||||
random *= tempEffect.waitTimeMultiplier();
|
||||
random += tempEffect.waitTimeAdder();
|
||||
random = Math.max(1, random);
|
||||
}
|
||||
|
||||
// lava effect task (Three seconds in advance)
|
||||
this.lavaFishingTask = new LavaEffectTask(
|
||||
this,
|
||||
fishHook.getLocation(),
|
||||
random - 3 * 20
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the hook state of the fish hook.
|
||||
*/
|
||||
public void getHooked() {
|
||||
LavaFishingEvent lavaFishingEvent = new LavaFishingEvent(fishingPreparation.getPlayer(), LavaFishingEvent.State.BITE, fishHook);
|
||||
Bukkit.getPluginManager().callEvent(lavaFishingEvent);
|
||||
if (lavaFishingEvent.isCancelled()) {
|
||||
this.startLavaFishingMechanic();
|
||||
return;
|
||||
}
|
||||
|
||||
this.loot.triggerActions(ActionTrigger.BITE, fishingPreparation);
|
||||
this.fishingPreparation.triggerActions(ActionTrigger.BITE);
|
||||
|
||||
this.fishHooked = true;
|
||||
this.removeTempEntity();
|
||||
|
||||
AdventureHelper.getInstance().sendSound(
|
||||
fishingPreparation.getPlayer(),
|
||||
Sound.Source.NEUTRAL,
|
||||
Key.key("minecraft:block.pointed_dripstone.drip_lava_into_cauldron"),
|
||||
1,
|
||||
1
|
||||
);
|
||||
|
||||
BukkitCustomFishingPlugin.get().getScheduler().runTaskAsyncLater(() -> {
|
||||
fishHooked = false;
|
||||
reserve = false;
|
||||
}, (2 * 20) * 50L, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
private void makeHookStatic(Location armorLoc) {
|
||||
armorLoc.setY(armorLoc.getBlockY() + 0.2);
|
||||
if (hookedEntity != null && !hookedEntity.isDead())
|
||||
hookedEntity.remove();
|
||||
hookedEntity = armorLoc.getWorld().spawn(armorLoc, ArmorStand.class, a -> {
|
||||
a.setInvisible(true);
|
||||
a.setCollidable(false);
|
||||
a.setInvulnerable(true);
|
||||
a.setVisible(false);
|
||||
a.setCustomNameVisible(false);
|
||||
a.setSmall(true);
|
||||
a.setGravity(false);
|
||||
a.getPersistentDataContainer().set(
|
||||
Objects.requireNonNull(NamespacedKey.fromString("lavafishing", BukkitCustomFishingPlugin.get())),
|
||||
PersistentDataType.STRING,
|
||||
"temp"
|
||||
);
|
||||
});
|
||||
fishHook.setHookedEntity(hookedEntity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the fish hook is currently hooked.
|
||||
*
|
||||
* @return True if the fish hook is hooked, false otherwise.
|
||||
*/
|
||||
public boolean isFishHooked() {
|
||||
return fishHooked;
|
||||
}
|
||||
|
||||
private void setWaitTime() {
|
||||
if (CFConfig.overrideVanilla) {
|
||||
double initialTime = ThreadLocalRandom.current().nextInt(CFConfig.waterMaxTime - CFConfig.waterMinTime + 1) + CFConfig.waterMinTime;
|
||||
fishHook.setWaitTime(Math.max(1, (int) (initialTime * tempEffect.waitTimeMultiplier() + tempEffect.waitTimeAdder())));
|
||||
} else {
|
||||
fishHook.setMinWaitTime(Math.max(1, (int) (fishHook.getMinWaitTime() * tempEffect.waitTimeMultiplier() + tempEffect.waitTimeAdder())));
|
||||
fishHook.setMaxWaitTime(Math.max(2, (int) (fishHook.getMaxWaitTime() * tempEffect.waitTimeMultiplier() + tempEffect.waitTimeAdder())));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
/*
|
||||
* 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.fishing;
|
||||
|
||||
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
|
||||
import net.momirealms.customfishing.api.scheduler.CancellableTask;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Particle;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* A task responsible for creating a lava effect animation between two points.
|
||||
*/
|
||||
public class LavaEffectTask implements Runnable {
|
||||
|
||||
private final Location startLoc;
|
||||
private final Location endLoc;
|
||||
private final Location controlLoc;
|
||||
private int timer;
|
||||
private final CancellableTask lavaTask;
|
||||
private final HookCheckTimerTask hookCheckTimerTask;
|
||||
|
||||
/**
|
||||
* Constructs a new LavaEffectTask.
|
||||
*
|
||||
* @param hookCheckTimerTask The HookCheckTimerTask instance.
|
||||
* @param location The starting location for the lava effect.
|
||||
* @param delay The delay before starting the task.
|
||||
*/
|
||||
public LavaEffectTask(HookCheckTimerTask hookCheckTimerTask, Location location, int delay) {
|
||||
this.hookCheckTimerTask = hookCheckTimerTask;
|
||||
this.startLoc = location.clone().add(0,0.3,0);
|
||||
this.endLoc = this.startLoc.clone().add((Math.random() * 16 - 8), startLoc.getY(), (Math.random() * 16 - 8));
|
||||
this.controlLoc = new Location(
|
||||
startLoc.getWorld(),
|
||||
(startLoc.getX() + endLoc.getX())/2 + Math.random() * 12 - 6,
|
||||
startLoc.getY(),
|
||||
(startLoc.getZ() + endLoc.getZ())/2 + Math.random() * 12 - 6
|
||||
);
|
||||
this.lavaTask = BukkitCustomFishingPlugin.get().getScheduler().runTaskAsyncTimer(this, delay * 50L, 50, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
timer++;
|
||||
if (timer > 60) {
|
||||
lavaTask.cancel();
|
||||
BukkitCustomFishingPlugin.get().getScheduler().runTaskSync(hookCheckTimerTask::getHooked, startLoc);
|
||||
} else {
|
||||
double t = (double) timer / 60;
|
||||
Location particleLoc = endLoc.clone().multiply(Math.pow((1 - t), 2)).add(controlLoc.clone().multiply(2 * t * (1 - t))).add(startLoc.clone().multiply(Math.pow(t, 2)));
|
||||
particleLoc.setY(startLoc.getY());
|
||||
startLoc.getWorld().spawnParticle(Particle.FLAME, particleLoc,1,0,0,0,0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels the lava effect task.
|
||||
*/
|
||||
public void cancel() {
|
||||
if (lavaTask != null && !lavaTask.isCancelled())
|
||||
lavaTask.cancel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the lava effect task is cancelled.
|
||||
*
|
||||
* @return True if the task is cancelled, false otherwise.
|
||||
*/
|
||||
public boolean isCancelled() {
|
||||
return lavaTask.isCancelled();
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -17,7 +17,6 @@
|
||||
|
||||
package net.momirealms.customfishing.bukkit.gui.icon.property.item;
|
||||
|
||||
import net.momirealms.customfishing.bukkit.BukkitCustomFishingPluginImpl;
|
||||
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
|
||||
import net.momirealms.customfishing.bukkit.adventure.ShadedAdventureComponentWrapper;
|
||||
import net.momirealms.customfishing.bukkit.gui.SectionPage;
|
||||
|
||||
@@ -21,7 +21,6 @@ import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
|
||||
import net.momirealms.customfishing.bukkit.adventure.ShadedAdventureComponentWrapper;
|
||||
import net.momirealms.customfishing.bukkit.gui.SectionPage;
|
||||
import net.momirealms.customfishing.bukkit.gui.icon.BackGroundItem;
|
||||
import net.momirealms.customfishing.bukkit.item.ItemManagerImpl;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
@@ -1,331 +0,0 @@
|
||||
/*
|
||||
* 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.hook;
|
||||
|
||||
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
|
||||
import net.momirealms.customfishing.api.mechanic.hook.HookManager;
|
||||
import net.momirealms.customfishing.api.mechanic.hook.HookSetting;
|
||||
import net.momirealms.customfishing.api.mechanic.requirement.RequirementManager;
|
||||
import net.momirealms.customfishing.bukkit.item.ItemManagerImpl;
|
||||
import net.momirealms.customfishing.bukkit.util.ItemUtils;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
|
||||
public class BukkitHookManager implements Listener, HookManager {
|
||||
|
||||
private final BukkitCustomFishingPlugin plugin;
|
||||
private final HashMap<String, HookSetting> hookSettingMap;
|
||||
|
||||
public BukkitHookManager(BukkitCustomFishingPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
this.hookSettingMap = new HashMap<>();
|
||||
}
|
||||
|
||||
public void load() {
|
||||
Bukkit.getPluginManager().registerEvents(this, plugin);
|
||||
loadConfig();
|
||||
}
|
||||
|
||||
public void unload() {
|
||||
HandlerList.unregisterAll(this);
|
||||
hookSettingMap.clear();
|
||||
}
|
||||
|
||||
public void disable() {
|
||||
unload();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads configuration files for the specified types.
|
||||
*/
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
private void loadConfig() {
|
||||
Deque<File> fileDeque = new ArrayDeque<>();
|
||||
for (String type : List.of("hook")) {
|
||||
File typeFolder = new File(plugin.getDataFolder() + File.separator + "contents" + File.separator + type);
|
||||
if (!typeFolder.exists()) {
|
||||
if (!typeFolder.mkdirs()) return;
|
||||
plugin.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads data from a single configuration file.
|
||||
*
|
||||
* @param file The configuration file to load.
|
||||
*/
|
||||
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) {
|
||||
if (!section.contains("max-durability")) {
|
||||
LogUtils.warn("Please set max-durability to hook: " + entry.getKey());
|
||||
continue;
|
||||
}
|
||||
var setting = new HookSetting.Builder(entry.getKey())
|
||||
.durability(section.getInt("max-durability", 16))
|
||||
.lore(section.getStringList("lore-on-rod").stream().map(it -> "<!i>" + it).toList())
|
||||
.build();
|
||||
hookSettingMap.put(entry.getKey(), setting);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the hook setting by its ID.
|
||||
*
|
||||
* @param id The ID of the hook setting to retrieve.
|
||||
* @return The hook setting with the given ID, or null if not found.
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
public HookSetting getHookSetting(String id) {
|
||||
return hookSettingMap.get(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decreases the durability of a fishing hook by a specified amount and optionally updates its lore.
|
||||
*
|
||||
* @param rod The fishing rod ItemStack to modify.
|
||||
* @param amount The amount by which to decrease the durability.
|
||||
* @param updateLore Whether to update the lore of the fishing rod.
|
||||
*/
|
||||
@Override
|
||||
public void decreaseHookDurability(ItemStack rod, int amount, boolean updateLore) {
|
||||
ItemUtils.decreaseHookDurability(rod, amount, updateLore);
|
||||
}
|
||||
|
||||
/**
|
||||
* Increases the durability of a fishing hook by a specified amount and optionally updates its lore.
|
||||
*
|
||||
* @param rod The fishing rod ItemStack to modify.
|
||||
* @param amount The amount by which to increase the durability.
|
||||
* @param updateLore Whether to update the lore of the fishing rod.
|
||||
*/
|
||||
@Override
|
||||
public void increaseHookDurability(ItemStack rod, int amount, boolean updateLore) {
|
||||
ItemUtils.increaseHookDurability(rod, amount, updateLore);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the durability of a fishing hook to a specific amount and optionally updates its lore.
|
||||
*
|
||||
* @param rod The fishing rod ItemStack to modify.
|
||||
* @param amount The new durability value to set.
|
||||
* @param updateLore Whether to update the lore of the fishing rod.
|
||||
*/
|
||||
@Override
|
||||
public void setHookDurability(ItemStack rod, int amount, boolean updateLore) {
|
||||
ItemUtils.setHookDurability(rod, amount, updateLore);
|
||||
}
|
||||
|
||||
/**
|
||||
* Equips a fishing hook on a fishing rod.
|
||||
*
|
||||
* @param rod The fishing rod ItemStack.
|
||||
* @param hook The fishing hook ItemStack.
|
||||
* @return True if the hook was successfully equipped, false otherwise.
|
||||
*/
|
||||
@Override
|
||||
public boolean equipHookOnRod(ItemStack rod, ItemStack hook) {
|
||||
if (rod == null || hook == null || hook.getType() == Material.AIR || hook.getAmount() != 1)
|
||||
return false;
|
||||
if (rod.getType() != Material.FISHING_ROD)
|
||||
return false;
|
||||
|
||||
String hookID = plugin.getItemManager().getAnyPluginItemID(hook);
|
||||
HookSetting setting = getHookSetting(hookID);
|
||||
if (setting == null)
|
||||
return false;
|
||||
|
||||
var curDurability = ItemUtils.getCustomDurability(hook);
|
||||
if (curDurability.left() == 0)
|
||||
return false;
|
||||
|
||||
NBTItem rodNBTItem = new NBTItem(rod);
|
||||
NBTCompound cfCompound = rodNBTItem.getOrCreateCompound("CustomFishing");
|
||||
|
||||
cfCompound.setString("hook_id", hookID);
|
||||
cfCompound.setItemStack("hook_item", hook);
|
||||
cfCompound.setInteger("hook_dur", curDurability.right());
|
||||
|
||||
ItemUtils.updateNBTItemLore(rodNBTItem);
|
||||
rod.setItemMeta(rodNBTItem.getItem().getItemMeta());
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the fishing hook from a fishing rod.
|
||||
*
|
||||
* @param rod The fishing rod ItemStack.
|
||||
* @return The removed fishing hook ItemStack, or null if no hook was found.
|
||||
*/
|
||||
@Override
|
||||
public ItemStack removeHookFromRod(ItemStack rod) {
|
||||
if (rod == null || rod.getType() != Material.FISHING_ROD)
|
||||
return null;
|
||||
|
||||
NBTItem rodNBTItem = new NBTItem(rod);
|
||||
NBTCompound cfCompound = rodNBTItem.getCompound("CustomFishing");
|
||||
if (cfCompound == null)
|
||||
return null;
|
||||
|
||||
ItemStack hook = cfCompound.getItemStack("hook_item");
|
||||
if (hook != null) {
|
||||
cfCompound.removeKey("hook_item");
|
||||
cfCompound.removeKey("hook_id");
|
||||
cfCompound.removeKey("hook_dur");
|
||||
ItemUtils.updateNBTItemLore(rodNBTItem);
|
||||
rod.setItemMeta(rodNBTItem.getItem().getItemMeta());
|
||||
}
|
||||
|
||||
return hook;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the event when a player clicks on a fishing rod in their inventory.
|
||||
*
|
||||
* @param event The InventoryClickEvent to handle.
|
||||
*/
|
||||
@EventHandler
|
||||
@SuppressWarnings("deprecation")
|
||||
public void onDragDrop(InventoryClickEvent event) {
|
||||
if (event.isCancelled())
|
||||
return;
|
||||
final Player player = (Player) event.getWhoClicked();
|
||||
if (event.getClickedInventory() != player.getInventory())
|
||||
return;
|
||||
ItemStack clicked = event.getCurrentItem();
|
||||
if (clicked == null || clicked.getType() != Material.FISHING_ROD)
|
||||
return;
|
||||
if (player.getGameMode() != GameMode.SURVIVAL)
|
||||
return;
|
||||
if (plugin.getFishingManager().hasPlayerCastHook(player.getUniqueId()))
|
||||
return;
|
||||
|
||||
ItemStack cursor = event.getCursor();
|
||||
if (cursor == null || cursor.getType() == Material.AIR) {
|
||||
if (event.getClick() == ClickType.RIGHT) {
|
||||
NBTItem nbtItem = new NBTItem(clicked);
|
||||
NBTCompound cfCompound = nbtItem.getCompound("CustomFishing");
|
||||
if (cfCompound == null)
|
||||
return;
|
||||
if (cfCompound.hasTag("hook_id")) {
|
||||
event.setCancelled(true);
|
||||
ItemStack hook = cfCompound.getItemStack("hook_item");
|
||||
ItemUtils.setDurability(hook, cfCompound.getInteger("hook_dur"), true);
|
||||
cfCompound.removeKey("hook_id");
|
||||
cfCompound.removeKey("hook_item");
|
||||
cfCompound.removeKey("hook_dur");
|
||||
event.setCursor(hook);
|
||||
ItemUtils.updateNBTItemLore(nbtItem);
|
||||
clicked.setItemMeta(nbtItem.getItem().getItemMeta());
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
String hookID = plugin.getItemManager().getAnyPluginItemID(cursor);
|
||||
HookSetting setting = getHookSetting(hookID);
|
||||
if (setting == null)
|
||||
return;
|
||||
|
||||
var cursorDurability = ItemUtils.getCustomDurability(cursor);
|
||||
if (cursorDurability.left() == 0) {
|
||||
if (plugin.getItemManager().getBuildableItem("hook", hookID) instanceof ItemManagerImpl.CFBuilder cfBuilder) {
|
||||
ItemStack itemStack = cfBuilder.build(player, new HashMap<>());
|
||||
var pair = ItemUtils.getCustomDurability(itemStack);
|
||||
cursorDurability = pair;
|
||||
NBTItem nbtItem = new NBTItem(cursor);
|
||||
NBTCompound compound = nbtItem.getOrCreateCompound("CustomFishing");
|
||||
compound.setInteger("max_dur", pair.left());
|
||||
compound.setInteger("cur_dur", pair.right());
|
||||
compound.setString("type", "hook");
|
||||
compound.setString("id", hookID);
|
||||
cursor.setItemMeta(nbtItem.getItem().getItemMeta());
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
PlayerContext playerContext = new PlayerContext(player, new HashMap<>());
|
||||
playerContext.insertArg("{rod}", plugin.getItemManager().getAnyPluginItemID(clicked));
|
||||
EffectCarrier effectCarrier = plugin.getEffectManager().getEffectCarrier("hook", hookID);
|
||||
if (effectCarrier != null) {
|
||||
if (!RequirementManager.isRequirementMet(playerContext, effectCarrier.getRequirements())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
event.setCancelled(true);
|
||||
|
||||
NBTItem rodNBTItem = new NBTItem(clicked);
|
||||
NBTCompound cfCompound = rodNBTItem.getOrCreateCompound("CustomFishing");
|
||||
String previousHookID = cfCompound.getString("hook_id");
|
||||
|
||||
ItemStack clonedHook = cursor.clone();
|
||||
clonedHook.setAmount(1);
|
||||
cursor.setAmount(cursor.getAmount() - 1);
|
||||
|
||||
if (previousHookID != null && !previousHookID.equals("")) {
|
||||
int previousHookDurability = cfCompound.getInteger("hook_dur");
|
||||
ItemStack previousItemStack = cfCompound.getItemStack("hook_item");
|
||||
ItemUtils.setDurability(previousItemStack, previousHookDurability, true);
|
||||
if (cursor.getAmount() == 0) {
|
||||
event.setCursor(previousItemStack);
|
||||
} else {
|
||||
ItemUtils.giveItem(player, previousItemStack, 1);
|
||||
}
|
||||
}
|
||||
|
||||
cfCompound.setString("hook_id", hookID);
|
||||
cfCompound.setItemStack("hook_item", clonedHook);
|
||||
cfCompound.setInteger("hook_dur", cursorDurability.right());
|
||||
|
||||
ItemUtils.updateNBTItemLore(rodNBTItem);
|
||||
clicked.setItemMeta(rodNBTItem.getItem().getItemMeta());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,244 @@
|
||||
/*
|
||||
* 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.integration;
|
||||
|
||||
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
|
||||
import net.momirealms.customfishing.api.integration.*;
|
||||
import net.momirealms.customfishing.bukkit.block.BukkitBlockManager;
|
||||
import net.momirealms.customfishing.bukkit.entity.BukkitEntityManager;
|
||||
import net.momirealms.customfishing.bukkit.integration.block.ItemsAdderBlockProvider;
|
||||
import net.momirealms.customfishing.bukkit.integration.block.OraxenBlockProvider;
|
||||
import net.momirealms.customfishing.bukkit.integration.enchant.AdvancedEnchantmentsProvider;
|
||||
import net.momirealms.customfishing.bukkit.integration.entity.ItemsAdderEntityProvider;
|
||||
import net.momirealms.customfishing.bukkit.integration.entity.MythicEntityProvider;
|
||||
import net.momirealms.customfishing.bukkit.integration.item.*;
|
||||
import net.momirealms.customfishing.bukkit.integration.level.*;
|
||||
import net.momirealms.customfishing.bukkit.integration.quest.BattlePassQuest;
|
||||
import net.momirealms.customfishing.bukkit.integration.quest.BetonQuestQuest;
|
||||
import net.momirealms.customfishing.bukkit.integration.quest.ClueScrollsQuest;
|
||||
import net.momirealms.customfishing.bukkit.integration.season.AdvancedSeasonsProvider;
|
||||
import net.momirealms.customfishing.bukkit.integration.season.CustomCropsSeasonProvider;
|
||||
import net.momirealms.customfishing.bukkit.integration.season.RealisticSeasonsProvider;
|
||||
import net.momirealms.customfishing.bukkit.item.BukkitItemManager;
|
||||
import net.momirealms.customfishing.common.util.Pair;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
public class BukkitIntegrationManager implements IntegrationManager {
|
||||
|
||||
private final BukkitCustomFishingPlugin plugin;
|
||||
private final HashMap<String, LevelerProvider> levelerProviders;
|
||||
private final HashMap<String, EnchantmentProvider> enchantmentProviders;
|
||||
private SeasonProvider seasonProvider;
|
||||
|
||||
public BukkitIntegrationManager(BukkitCustomFishingPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
this.levelerProviders = new HashMap<>();
|
||||
this.enchantmentProviders = new HashMap<>();
|
||||
this.load();
|
||||
}
|
||||
|
||||
public void disable() {
|
||||
this.enchantmentProviders.clear();
|
||||
this.levelerProviders.clear();
|
||||
}
|
||||
|
||||
public void load() {
|
||||
if (isHooked("ItemsAdder")) {
|
||||
registerItemProvider(new ItemsAdderItemProvider());
|
||||
registerBlockProvider(new ItemsAdderBlockProvider());
|
||||
registerEntityProvider(new ItemsAdderEntityProvider());
|
||||
}
|
||||
if (isHooked("MMOItems")) {
|
||||
registerItemProvider(new MMOItemsItemProvider());
|
||||
}
|
||||
if (isHooked("Oraxen")) {
|
||||
registerItemProvider(new OraxenItemProvider());
|
||||
registerBlockProvider(new OraxenBlockProvider());
|
||||
}
|
||||
if (isHooked("Zaphkiel")) {
|
||||
registerItemProvider(new ZaphkielItemProvider());
|
||||
}
|
||||
if (isHooked("NeigeItems")) {
|
||||
registerItemProvider(new NeigeItemsItemProvider());
|
||||
}
|
||||
if (isHooked("MythicMobs")) {
|
||||
registerItemProvider(new MythicMobsItemProvider());
|
||||
registerEntityProvider(new MythicEntityProvider());
|
||||
}
|
||||
if (isHooked("EcoJobs")) {
|
||||
registerLevelerProvider(new EcoJobsLevelerProvider());
|
||||
}
|
||||
if (isHooked("EcoSkills")) {
|
||||
registerLevelerProvider(new EcoSkillsLevelerProvider());
|
||||
}
|
||||
if (isHooked("Jobs")) {
|
||||
registerLevelerProvider(new JobsRebornLevelerProvider());
|
||||
}
|
||||
if (isHooked("MMOCore")) {
|
||||
registerLevelerProvider(new MMOCoreLevelerProvider());
|
||||
}
|
||||
if (isHooked("mcMMO")) {
|
||||
try {
|
||||
registerItemProvider(new McMMOTreasureProvider());
|
||||
} catch (ClassNotFoundException | NoSuchMethodException e) {
|
||||
plugin.getPluginLogger().warn("Failed to initialize mcMMO Treasure");
|
||||
}
|
||||
registerLevelerProvider(new McMMOLevelerProvider());
|
||||
}
|
||||
if (isHooked("AureliumSkills")) {
|
||||
registerLevelerProvider(new AureliumSkillsProvider());
|
||||
}
|
||||
if (isHooked("AuraSkills")) {
|
||||
registerLevelerProvider(new AuraSkillsLevelerProvider());
|
||||
}
|
||||
if (isHooked("AdvancedEnchantments")) {
|
||||
registerEnchantmentProvider(new AdvancedEnchantmentsProvider());
|
||||
}
|
||||
if (isHooked("RealisticSeasons")) {
|
||||
registerSeasonProvider(new RealisticSeasonsProvider());
|
||||
} else if (isHooked("AdvancedSeasons")) {
|
||||
registerSeasonProvider(new AdvancedSeasonsProvider());
|
||||
} else if (isHooked("CustomCrops")) {
|
||||
registerSeasonProvider(new CustomCropsSeasonProvider());
|
||||
}
|
||||
if (isHooked("Vault")) {
|
||||
VaultHook.initialize();
|
||||
}
|
||||
if (isHooked("BattlePass")){
|
||||
BattlePassQuest battlePassQuest = new BattlePassQuest();
|
||||
battlePassQuest.register();
|
||||
}
|
||||
if (isHooked("ClueScrolls")) {
|
||||
ClueScrollsQuest clueScrollsQuest = new ClueScrollsQuest();
|
||||
clueScrollsQuest.register();
|
||||
}
|
||||
if (isHooked("BetonQuest")) {
|
||||
BetonQuestQuest.register();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isHooked(String hooked) {
|
||||
if (Bukkit.getPluginManager().getPlugin(hooked) != null) {
|
||||
plugin.getPluginLogger().info(hooked + " hooked!");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean registerLevelerProvider(@NotNull LevelerProvider leveler) {
|
||||
if (levelerProviders.containsKey(leveler.identifier())) return false;
|
||||
levelerProviders.put(leveler.identifier(), leveler);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean unregisterLevelerProvider(@NotNull String id) {
|
||||
return levelerProviders.remove(id) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean registerEnchantmentProvider(@NotNull EnchantmentProvider enchantment) {
|
||||
if (enchantmentProviders.containsKey(enchantment.identifier())) return false;
|
||||
enchantmentProviders.put(enchantment.identifier(), enchantment);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean unregisterEnchantmentProvider(@NotNull String id) {
|
||||
return enchantmentProviders.remove(id) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public LevelerProvider getLevelerProvider(String plugin) {
|
||||
return levelerProviders.get(plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public EnchantmentProvider getEnchantmentProvider(String id) {
|
||||
return enchantmentProviders.get(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Pair<String, Short>> getEnchantments(ItemStack itemStack) {
|
||||
ArrayList<Pair<String, Short>> list = new ArrayList<>();
|
||||
for (EnchantmentProvider enchantmentProvider : enchantmentProviders.values()) {
|
||||
list.addAll(enchantmentProvider.getEnchants(itemStack));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public SeasonProvider getSeasonProvider() {
|
||||
return seasonProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean registerSeasonProvider(@NotNull SeasonProvider season) {
|
||||
if (this.seasonProvider != null) return false;
|
||||
this.seasonProvider = season;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean unregisterSeasonProvider() {
|
||||
if (this.seasonProvider == null) return false;
|
||||
this.seasonProvider = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean registerEntityProvider(@NotNull EntityProvider entity) {
|
||||
return ((BukkitEntityManager) plugin.getEntityManager()).registerEntityProvider(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean unregisterEntityProvider(@NotNull String id) {
|
||||
return ((BukkitEntityManager) plugin.getEntityManager()).unregisterEntityProvider(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean registerItemProvider(@NotNull ItemProvider item) {
|
||||
return ((BukkitItemManager) plugin.getItemManager()).registerItemProvider(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean unregisterItemProvider(@NotNull String id) {
|
||||
return ((BukkitItemManager) plugin.getItemManager()).unregisterItemProvider(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean registerBlockProvider(@NotNull BlockProvider block) {
|
||||
return ((BukkitBlockManager) plugin.getBlockManager()).registerBlockProvider(block);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean unregisterBlockProvider(@NotNull String id) {
|
||||
return ((BukkitBlockManager) plugin.getBlockManager()).unregisterBlockProvider(id);
|
||||
}
|
||||
}
|
||||
@@ -48,6 +48,16 @@ public abstract class BukkitItemFactory extends ItemFactory<CustomFishingPlugin,
|
||||
return Optional.ofNullable(item.get(path));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean hasTag(RtagItem item, Object... path) {
|
||||
return item.hasTag(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean removeTag(RtagItem item, Object... path) {
|
||||
return item.remove(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void update(RtagItem item) {
|
||||
item.update();
|
||||
|
||||
@@ -2,38 +2,59 @@ package net.momirealms.customfishing.bukkit.item;
|
||||
|
||||
import net.kyori.adventure.key.Key;
|
||||
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
|
||||
import net.momirealms.customfishing.api.event.FishingLootPreSpawnEvent;
|
||||
import net.momirealms.customfishing.api.event.FishingLootSpawnEvent;
|
||||
import net.momirealms.customfishing.api.integration.ItemProvider;
|
||||
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.item.CustomFishingItem;
|
||||
import net.momirealms.customfishing.api.mechanic.item.ItemManager;
|
||||
import net.momirealms.customfishing.bukkit.util.ItemUtils;
|
||||
import net.momirealms.customfishing.bukkit.util.LocationUtils;
|
||||
import net.momirealms.customfishing.common.item.Item;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.Skull;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.*;
|
||||
import org.bukkit.event.entity.EntityExplodeEvent;
|
||||
import org.bukkit.event.inventory.InventoryPickupItemEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.persistence.PersistentDataContainer;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
import org.bukkit.util.Vector;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
public class BukkitItemManager implements ItemManager {
|
||||
public class BukkitItemManager implements ItemManager, Listener {
|
||||
|
||||
private final BukkitCustomFishingPlugin plugin;
|
||||
private final HashMap<String, ItemProvider> itemProviders = new HashMap<>();
|
||||
private final HashMap<Key, CustomFishingItem> itemMap = new HashMap<>();
|
||||
private final HashMap<Key, CustomFishingItem> items = new HashMap<>();
|
||||
private final BukkitItemFactory factory;
|
||||
private ItemProvider[] itemDetectArray;
|
||||
|
||||
public BukkitItemManager(BukkitCustomFishingPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
this.factory = BukkitItemFactory.create(plugin);
|
||||
this.registerVanilla();
|
||||
}
|
||||
|
||||
private void registerVanilla() {
|
||||
this.itemProviders.put("vanilla", new ItemProvider() {
|
||||
this.registerItemProvider(new ItemProvider() {
|
||||
@NotNull
|
||||
@Override
|
||||
public ItemStack buildItem(@NotNull Player player, @NotNull String id) {
|
||||
@@ -51,10 +72,27 @@ public class BukkitItemManager implements ItemManager {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unload() {
|
||||
HandlerList.unregisterAll(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
Bukkit.getPluginManager().registerEvents(this, plugin.getBoostrap());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean registerItem(@NotNull Key key, @NotNull CustomFishingItem item) {
|
||||
if (items.containsKey(key)) return false;
|
||||
items.put(key, item);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ItemStack buildInternal(Context<Player> context, Key key) {
|
||||
CustomFishingItem item = requireNonNull(itemMap.get(key), () -> "No item found for " + key);
|
||||
public ItemStack buildInternal(@NotNull Context<Player> context, @NotNull Key key) {
|
||||
CustomFishingItem item = requireNonNull(items.get(key), () -> "No item found for " + key);
|
||||
ItemStack itemStack = getOriginalStack(context.getHolder(), item.material());
|
||||
Item<ItemStack> wrappedItemStack = factory.wrap(itemStack);
|
||||
for (BiConsumer<Item<ItemStack>, Context<Player>> consumer : item.tagConsumers()) {
|
||||
@@ -63,8 +101,70 @@ public class BukkitItemManager implements ItemManager {
|
||||
return wrappedItemStack.getItem();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack buildAny(@NotNull Context<Player> context, @NotNull String item) {
|
||||
return getOriginalStack(context.getHolder(), item);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getItemID(@NotNull ItemStack itemStack) {
|
||||
if (itemStack.getType() == Material.AIR)
|
||||
return "AIR";
|
||||
for (ItemProvider library : itemDetectArray) {
|
||||
String id = library.itemID(itemStack);
|
||||
if (id != null)
|
||||
return id;
|
||||
}
|
||||
// should not reach this because vanilla library would always work
|
||||
return "AIR";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCustomFishingItemID(@NotNull ItemStack itemStack) {
|
||||
return (String) factory.wrap(itemStack).getTag("CustomFishing", "id").orElse(null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
@SuppressWarnings("all")
|
||||
public org.bukkit.entity.Item dropItemLoot(@NotNull Context<Player> context) {
|
||||
String id = requireNonNull(context.arg(ContextKeys.ID));
|
||||
ItemStack itemStack = requireNonNull(buildInternal(context, Key.key("item", id)));
|
||||
Player player = context.getHolder();
|
||||
Location playerLocation = player.getLocation();
|
||||
Location hookLocation = requireNonNull(context.arg(ContextKeys.HOOK_LOCATION));
|
||||
|
||||
FishingLootPreSpawnEvent preSpawnEvent = new FishingLootPreSpawnEvent(player, hookLocation, itemStack);
|
||||
Bukkit.getPluginManager().callEvent(preSpawnEvent);
|
||||
if (preSpawnEvent.isCancelled()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
org.bukkit.entity.Item itemEntity = hookLocation.getWorld().dropItem(hookLocation, itemStack);
|
||||
FishingLootSpawnEvent spawnEvent = new FishingLootSpawnEvent(player, hookLocation, itemEntity);
|
||||
Bukkit.getPluginManager().callEvent(spawnEvent);
|
||||
if (spawnEvent.isCancelled()) {
|
||||
itemEntity.remove();
|
||||
return null;
|
||||
}
|
||||
|
||||
itemEntity.setInvulnerable(true);
|
||||
// prevent from being killed by lava
|
||||
plugin.getScheduler().asyncLater(() -> {
|
||||
if (itemEntity.isValid())
|
||||
itemEntity.setInvulnerable(false);
|
||||
}, 1, TimeUnit.SECONDS);
|
||||
|
||||
Vector vector = playerLocation.subtract(hookLocation).toVector().multiply(0.105);
|
||||
vector = vector.setY((vector.getY() + 0.22) * 1.18);
|
||||
itemEntity.setVelocity(vector);
|
||||
|
||||
return itemEntity;
|
||||
}
|
||||
|
||||
private ItemStack getOriginalStack(Player player, String material) {
|
||||
if (material.contains(":")) {
|
||||
if (!material.contains(":")) {
|
||||
try {
|
||||
return new ItemStack(Material.valueOf(material.toUpperCase(Locale.ENGLISH)));
|
||||
} catch (IllegalArgumentException e) {
|
||||
@@ -73,8 +173,132 @@ public class BukkitItemManager implements ItemManager {
|
||||
}
|
||||
} else {
|
||||
String[] split = material.split(":", 2);
|
||||
ItemProvider provider = requireNonNull(itemProviders.get(split[0]), "item provider " + split[0] + " not found");
|
||||
return requireNonNull(provider.buildItem(player, split[0]), "item " + split[0] + " not found");
|
||||
ItemProvider provider = requireNonNull(itemProviders.get(split[0]), "Item provider: " + split[0] + " not found");
|
||||
return requireNonNull(provider.buildItem(player, split[0]), "Item: " + split[0] + " not found");
|
||||
}
|
||||
}
|
||||
|
||||
private void resetItemDetectionOrder() {
|
||||
ArrayList<ItemProvider> list = new ArrayList<>();
|
||||
for (String plugin : ConfigManager.itemDetectOrder()) {
|
||||
ItemProvider provider = itemProviders.get(plugin);
|
||||
if (provider != null)
|
||||
list.add(provider);
|
||||
}
|
||||
this.itemDetectArray = list.toArray(new ItemProvider[0]);
|
||||
}
|
||||
|
||||
public boolean registerItemProvider(ItemProvider item) {
|
||||
if (itemProviders.containsKey(item.identifier())) return false;
|
||||
itemProviders.put(item.identifier(), item);
|
||||
this.resetItemDetectionOrder();
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean unregisterItemProvider(String id) {
|
||||
boolean success = itemProviders.remove(id) != null;
|
||||
if (success)
|
||||
this.resetItemDetectionOrder();
|
||||
return success;
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onInvPickItem(InventoryPickupItemEvent event) {
|
||||
ItemStack itemStack = event.getItem().getItemStack();
|
||||
Item<ItemStack> wrapped = factory.wrap(itemStack);
|
||||
if (wrapped.hasTag("owner")) {
|
||||
wrapped.removeTag("owner");
|
||||
itemStack.setItemMeta(wrapped.getItem().getItemMeta());
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler (ignoreCancelled = true)
|
||||
public void onPlaceBlock(BlockPlaceEvent event) {
|
||||
ItemStack itemStack = event.getItemInHand();
|
||||
if (itemStack.getType() == Material.AIR || itemStack.getAmount() == 0 || !itemStack.hasItemMeta()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Item<ItemStack> wrapped = factory.wrap(itemStack);
|
||||
if (wrapped.hasTag("CustomFishing")) {
|
||||
if (!wrapped.hasTag("CustomFishing", "placeable")) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
Block block = event.getBlock();
|
||||
if (block.getState() instanceof Skull) {
|
||||
PersistentDataContainer pdc = block.getChunk().getPersistentDataContainer();
|
||||
ItemStack cloned = itemStack.clone();
|
||||
cloned.setAmount(1);
|
||||
pdc.set(new NamespacedKey(plugin.getBoostrap(), LocationUtils.toChunkPosString(block.getLocation())), PersistentDataType.STRING, ItemUtils.toBase64(cloned));
|
||||
} else {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler (ignoreCancelled = true)
|
||||
public void onBreakBlock(BlockBreakEvent event) {
|
||||
final Block block = event.getBlock();
|
||||
if (block.getState() instanceof Skull) {
|
||||
PersistentDataContainer pdc = block.getChunk().getPersistentDataContainer();
|
||||
String base64 = pdc.get(new NamespacedKey(plugin.getBoostrap(), LocationUtils.toChunkPosString(block.getLocation())), PersistentDataType.STRING);
|
||||
if (base64 != null) {
|
||||
ItemStack itemStack = ItemUtils.fromBase64(base64);
|
||||
event.setDropItems(false);
|
||||
block.getLocation().getWorld().dropItemNaturally(block.getLocation(), itemStack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler (ignoreCancelled = true)
|
||||
public void onPiston(BlockPistonExtendEvent event) {
|
||||
handlePiston(event, event.getBlocks());
|
||||
}
|
||||
|
||||
@EventHandler (ignoreCancelled = true)
|
||||
public void onPiston(BlockPistonRetractEvent event) {
|
||||
handlePiston(event, event.getBlocks());
|
||||
}
|
||||
|
||||
private void handlePiston(Cancellable event, List<Block> blockList) {
|
||||
for (Block block : blockList) {
|
||||
if (block.getState() instanceof Skull) {
|
||||
PersistentDataContainer pdc = block.getChunk().getPersistentDataContainer();
|
||||
if (pdc.has(new NamespacedKey(plugin.getBoostrap(), LocationUtils.toChunkPosString(block.getLocation())), PersistentDataType.STRING)) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler (ignoreCancelled = true)
|
||||
public void onExplosion(BlockExplodeEvent event) {
|
||||
handleExplosion(event.blockList());
|
||||
}
|
||||
|
||||
@EventHandler (ignoreCancelled = true)
|
||||
public void onExplosion(EntityExplodeEvent event) {
|
||||
handleExplosion(event.blockList());
|
||||
}
|
||||
|
||||
private void handleExplosion(List<Block> blocks) {
|
||||
ArrayList<Block> blockToRemove = new ArrayList<>();
|
||||
for (Block block : blocks) {
|
||||
if (block.getState() instanceof Skull) {
|
||||
PersistentDataContainer pdc = block.getChunk().getPersistentDataContainer();
|
||||
var nk = new NamespacedKey(plugin.getBoostrap(), LocationUtils.toChunkPosString(block.getLocation()));
|
||||
String base64 = pdc.get(nk, PersistentDataType.STRING);
|
||||
if (base64 != null) {
|
||||
ItemStack itemStack = ItemUtils.fromBase64(base64);
|
||||
block.getLocation().getWorld().dropItemNaturally(block.getLocation(), itemStack);
|
||||
blockToRemove.add(block);
|
||||
block.setType(Material.AIR);
|
||||
pdc.remove(nk);
|
||||
}
|
||||
}
|
||||
}
|
||||
blocks.removeAll(blockToRemove);
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -11,8 +11,6 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
public class BukkitLootManager implements LootManager {
|
||||
|
||||
private final BukkitCustomFishingPlugin plugin;
|
||||
@@ -23,13 +21,8 @@ public class BukkitLootManager implements LootManager {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
private void loadConfig() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerLoot(@NotNull final Loot loot) {
|
||||
requireNonNull(loot, "loot cannot be null");
|
||||
public void registerLoot(@NotNull Loot loot) {
|
||||
this.lootMap.put(loot.getID(), loot);
|
||||
for (String group : loot.lootGroup()) {
|
||||
addGroupMember(group, loot.getID());
|
||||
|
||||
@@ -20,13 +20,17 @@ package net.momirealms.customfishing.bukkit.market;
|
||||
import de.tr7zw.changeme.nbtapi.NBTItem;
|
||||
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
|
||||
import net.momirealms.customfishing.api.mechanic.action.Action;
|
||||
import net.momirealms.customfishing.api.mechanic.context.Context;
|
||||
import net.momirealms.customfishing.api.mechanic.market.MarketGUIHolder;
|
||||
import net.momirealms.customfishing.api.mechanic.market.MarketManager;
|
||||
import net.momirealms.customfishing.api.mechanic.misc.placeholder.BukkitPlaceholderManager;
|
||||
import net.momirealms.customfishing.api.mechanic.misc.value.TextValue;
|
||||
import net.momirealms.customfishing.api.scheduler.CancellableTask;
|
||||
import net.momirealms.customfishing.api.storage.data.EarningData;
|
||||
import net.momirealms.customfishing.bukkit.util.ConfigUtils;
|
||||
import net.momirealms.customfishing.bukkit.util.NumberUtils;
|
||||
import net.momirealms.customfishing.common.helper.ExpressionHelper;
|
||||
import net.momirealms.customfishing.common.plugin.scheduler.SchedulerTask;
|
||||
import net.objecthunter.exp4j.ExpressionBuilder;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
@@ -76,7 +80,7 @@ public class BukkitMarketManager implements MarketManager, Listener {
|
||||
private boolean sellFishingBag;
|
||||
private final ConcurrentHashMap<UUID, MarketGUI> marketGUIMap;
|
||||
private boolean enable;
|
||||
private CancellableTask resetEarningsTask;
|
||||
private SchedulerTask resetEarningsTask;
|
||||
private int date;
|
||||
|
||||
public BukkitMarketManager(BukkitCustomFishingPlugin plugin) {
|
||||
@@ -91,7 +95,7 @@ public class BukkitMarketManager implements MarketManager, Listener {
|
||||
this.loadConfig();
|
||||
Bukkit.getPluginManager().registerEvents(this, plugin);
|
||||
if (!enable) return;
|
||||
this.resetEarningsTask = plugin.getScheduler().runTaskAsyncTimer(() -> {
|
||||
this.resetEarningsTask = plugin.getScheduler().asyncRepeating(() -> {
|
||||
int now = getRealTimeDate();
|
||||
if (this.date != now) {
|
||||
this.date = now;
|
||||
@@ -491,18 +495,19 @@ public class BukkitMarketManager implements MarketManager, Listener {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFormula() {
|
||||
public TextValue<Player> getFormula() {
|
||||
return formula;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getFishPrice(Player player, Map<String, String> vars) {
|
||||
String temp = BukkitPlaceholderManager.getInstance().parse(player, formula, vars);
|
||||
public double getFishPrice(Context<Player> context) {
|
||||
formula.
|
||||
String temp = plugin.getPlaceholderManager().parse(player, formula, vars);
|
||||
var placeholders = BukkitPlaceholderManager.getInstance().resolvePlaceholders(temp);
|
||||
for (String placeholder : placeholders) {
|
||||
temp = temp.replace(placeholder, "0");
|
||||
}
|
||||
return new ExpressionBuilder(temp).build().evaluate();
|
||||
return ExpressionHelper.evaluate(temp);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -15,7 +15,7 @@ import net.momirealms.customfishing.api.mechanic.misc.value.MathValue;
|
||||
import net.momirealms.customfishing.api.mechanic.misc.value.TextValue;
|
||||
import net.momirealms.customfishing.api.mechanic.requirement.*;
|
||||
import net.momirealms.customfishing.api.util.MoonPhase;
|
||||
import net.momirealms.customfishing.bukkit.compatibility.VaultHook;
|
||||
import net.momirealms.customfishing.bukkit.integration.VaultHook;
|
||||
import net.momirealms.customfishing.common.util.ClassUtils;
|
||||
import net.momirealms.customfishing.common.util.ListUtils;
|
||||
import net.momirealms.customfishing.common.util.Pair;
|
||||
@@ -599,7 +599,7 @@ public class BukkitRequirementManager implements RequirementManager<Player> {
|
||||
registerRequirement("ice-fishing", (args, actions, advanced) -> {
|
||||
boolean iceFishing = (boolean) args;
|
||||
return context -> {
|
||||
Location location = requireNonNull(context.arg(ContextKeys.LOCATION));
|
||||
Location location = requireNonNull(context.arg(ContextKeys.HOOK_LOCATION));
|
||||
int water = 0, ice = 0;
|
||||
for (int i = -2; i <= 2; i++)
|
||||
for (int j = -1; j <= 2; j++)
|
||||
@@ -661,7 +661,7 @@ public class BukkitRequirementManager implements RequirementManager<Player> {
|
||||
registerRequirement("biome", (args, actions, advanced) -> {
|
||||
HashSet<String> biomes = new HashSet<>(ListUtils.toList(args));
|
||||
return context -> {
|
||||
Location location = requireNonNull(context.arg(ContextKeys.LOCATION));
|
||||
Location location = requireNonNull(Optional.ofNullable(context.arg(ContextKeys.HOOK_LOCATION)).orElse(context.arg(ContextKeys.LOCATION)));
|
||||
String currentBiome = SparrowHeart.getInstance().getBiomeResourceLocation(location);
|
||||
if (biomes.contains(currentBiome))
|
||||
return true;
|
||||
@@ -672,7 +672,7 @@ public class BukkitRequirementManager implements RequirementManager<Player> {
|
||||
registerRequirement("!biome", (args, actions, advanced) -> {
|
||||
HashSet<String> biomes = new HashSet<>(ListUtils.toList(args));
|
||||
return context -> {
|
||||
Location location = requireNonNull(context.arg(ContextKeys.LOCATION));
|
||||
Location location = requireNonNull(Optional.ofNullable(context.arg(ContextKeys.HOOK_LOCATION)).orElse(context.arg(ContextKeys.LOCATION)));
|
||||
String currentBiome = SparrowHeart.getInstance().getBiomeResourceLocation(location);
|
||||
if (!biomes.contains(currentBiome))
|
||||
return true;
|
||||
@@ -749,7 +749,19 @@ public class BukkitRequirementManager implements RequirementManager<Player> {
|
||||
|
||||
private void registerCoolDownRequirement() {
|
||||
registerRequirement("cooldown", (args, actions, advanced) -> {
|
||||
return null;
|
||||
if (args instanceof Section section) {
|
||||
String key = section.getString("key");
|
||||
int time = section.getInt("time");
|
||||
return context -> {
|
||||
if (!plugin.getCoolDownManager().isCoolDown(context.getHolder().getUniqueId(), key, time))
|
||||
return true;
|
||||
if (advanced) ActionManager.trigger(context, actions);
|
||||
return false;
|
||||
};
|
||||
} else {
|
||||
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at cooldown requirement which should be Section");
|
||||
return EmptyRequirement.INSTANCE;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ package net.momirealms.customfishing.bukkit.statistic;
|
||||
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
|
||||
import net.momirealms.customfishing.api.mechanic.statistic.StatisticsManager;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
@@ -28,39 +29,22 @@ import java.util.*;
|
||||
public class BukkitStatisticsManager implements StatisticsManager {
|
||||
|
||||
private final BukkitCustomFishingPlugin plugin;
|
||||
private final HashMap<String, List<String>> categoryMap;
|
||||
private final Map<String, List<String>> categoryMap = new HashMap<>();
|
||||
|
||||
public BukkitStatisticsManager(BukkitCustomFishingPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
this.categoryMap = new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
this.loadCategoriesFromPluginFolder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unload() {
|
||||
this.categoryMap.clear();
|
||||
}
|
||||
|
||||
public void disable() {
|
||||
unload();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the statistics for a player with the given UUID.
|
||||
*
|
||||
* @param uuid The UUID of the player for whom statistics are retrieved.
|
||||
* @return The player's statistics or null if the player is not found.
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public Statistics getStatistics(UUID uuid) {
|
||||
OnlineUserData onlineUser = plugin.getStorageManager().getOnlineUser(uuid);
|
||||
if (onlineUser == null) return null;
|
||||
return onlineUser.getStatistics();
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
public void loadCategoriesFromPluginFolder() {
|
||||
Deque<File> fileDeque = new ArrayDeque<>();
|
||||
@@ -68,7 +52,7 @@ public class BukkitStatisticsManager implements StatisticsManager {
|
||||
File typeFolder = new File(plugin.getDataFolder() + File.separator + "contents" + File.separator + type);
|
||||
if (!typeFolder.exists()) {
|
||||
if (!typeFolder.mkdirs()) return;
|
||||
plugin.saveResource("contents" + File.separator + type + File.separator + "default.yml", false);
|
||||
plugin.getBoostrap().saveResource("contents" + File.separator + type + File.separator + "default.yml", false);
|
||||
}
|
||||
fileDeque.push(typeFolder);
|
||||
while (!fileDeque.isEmpty()) {
|
||||
@@ -93,15 +77,9 @@ public class BukkitStatisticsManager implements StatisticsManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of strings associated with a specific key in a category map.
|
||||
*
|
||||
* @param key The key to look up in the category map.
|
||||
* @return A list of strings associated with the key or null if the key is not found.
|
||||
*/
|
||||
@NotNull
|
||||
@Override
|
||||
@Nullable
|
||||
public List<String> getCategory(String key) {
|
||||
return categoryMap.get(key);
|
||||
public List<String> getCategoryMembers(String key) {
|
||||
return categoryMap.getOrDefault(key, List.of());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ package net.momirealms.customfishing.bukkit.storage;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import net.momirealms.customfishing.bukkit.BukkitCustomFishingPluginImpl;
|
||||
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
|
||||
import net.momirealms.customfishing.api.scheduler.CancellableTask;
|
||||
import net.momirealms.customfishing.api.storage.DataStorageProvider;
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
|
||||
package net.momirealms.customfishing.bukkit.storage.method.database.sql;
|
||||
|
||||
import net.momirealms.customfishing.bukkit.BukkitCustomFishingPluginImpl;
|
||||
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
|
||||
import net.momirealms.customfishing.api.storage.StorageType;
|
||||
import net.momirealms.customfishing.libraries.dependencies.Dependency;
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
|
||||
package net.momirealms.customfishing.bukkit.storage.method.database.sql;
|
||||
|
||||
import net.momirealms.customfishing.bukkit.BukkitCustomFishingPluginImpl;
|
||||
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
|
||||
import net.momirealms.customfishing.api.storage.StorageType;
|
||||
import net.momirealms.customfishing.api.storage.data.PlayerData;
|
||||
|
||||
@@ -23,7 +23,6 @@ import com.comphenix.protocol.wrappers.*;
|
||||
import com.google.common.collect.Lists;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import net.momirealms.customfishing.bukkit.BukkitCustomFishingPluginImpl;
|
||||
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.EntityType;
|
||||
|
||||
Reference in New Issue
Block a user