9
0
mirror of https://github.com/Xiao-MoMi/Custom-Fishing.git synced 2025-12-26 18:39:11 +00:00

checkpoint - 10

This commit is contained in:
XiaoMoMi
2024-05-27 22:45:43 +08:00
parent eb0cb7173a
commit 32ea035d83
86 changed files with 2861 additions and 2950 deletions

View File

@@ -47,6 +47,8 @@ dependencies {
compileOnly("org.incendo:cloud-core:${rootProject.properties["cloud_core_version"]}")
compileOnly("org.incendo:cloud-minecraft-extras:${rootProject.properties["cloud_minecraft_extras_version"]}")
compileOnly("org.incendo:cloud-paper:${rootProject.properties["cloud_paper_version"]}")
// expression
compileOnly("net.objecthunter:exp4j:${rootProject.properties["exp4j_version"]}")
}
tasks {

View File

@@ -0,0 +1,191 @@
package net.momirealms.customfishing.bukkit;
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
import net.momirealms.customfishing.api.mechanic.config.ConfigManager;
import net.momirealms.customfishing.api.mechanic.misc.cooldown.CoolDownManager;
import net.momirealms.customfishing.api.mechanic.misc.placeholder.BukkitPlaceholderManager;
import net.momirealms.customfishing.bukkit.action.BukkitActionManager;
import net.momirealms.customfishing.bukkit.bag.BukkitBagManager;
import net.momirealms.customfishing.bukkit.block.BukkitBlockManager;
import net.momirealms.customfishing.bukkit.competition.BukkitCompetitionManager;
import net.momirealms.customfishing.bukkit.config.BukkitConfigManager;
import net.momirealms.customfishing.bukkit.effect.BukkitEffectManager;
import net.momirealms.customfishing.bukkit.entity.BukkitEntityManager;
import net.momirealms.customfishing.bukkit.event.BukkitEventManager;
import net.momirealms.customfishing.bukkit.hook.BukkitHookManager;
import net.momirealms.customfishing.bukkit.integration.BukkitIntegrationManager;
import net.momirealms.customfishing.bukkit.item.BukkitItemManager;
import net.momirealms.customfishing.bukkit.loot.BukkitLootManager;
import net.momirealms.customfishing.bukkit.market.BukkitMarketManager;
import net.momirealms.customfishing.bukkit.requirement.BukkitRequirementManager;
import net.momirealms.customfishing.bukkit.sender.BukkitSenderFactory;
import net.momirealms.customfishing.bukkit.statistic.BukkitStatisticsManager;
import net.momirealms.customfishing.bukkit.storage.BukkitStorageManager;
import net.momirealms.customfishing.common.dependency.Dependency;
import net.momirealms.customfishing.common.dependency.DependencyManagerImpl;
import net.momirealms.customfishing.common.helper.VersionHelper;
import net.momirealms.customfishing.common.locale.TranslationManager;
import net.momirealms.customfishing.common.plugin.classpath.ClassPathAppender;
import net.momirealms.customfishing.common.plugin.classpath.ReflectionClassPathAppender;
import net.momirealms.customfishing.common.plugin.logging.JavaPluginLogger;
import net.momirealms.customfishing.common.plugin.logging.PluginLogger;
import org.bstats.bukkit.Metrics;
import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin;
import java.io.InputStream;
import java.nio.file.Path;
import java.util.List;
public class BukkitCustomFishingPluginImpl extends BukkitCustomFishingPlugin {
private final ClassPathAppender classPathAppender;
private final PluginLogger logger;
public BukkitCustomFishingPluginImpl(Plugin boostrap) {
super(boostrap);
VersionHelper.init(getServerVersion());
this.classPathAppender = new ReflectionClassPathAppender(this);
this.logger = new JavaPluginLogger(getBoostrap().getLogger());
this.eventManager = new BukkitEventManager(this);
this.configManager = new BukkitConfigManager(this);
this.requirementManager = new BukkitRequirementManager(this);
this.actionManager = new BukkitActionManager(this);
this.senderFactory = new BukkitSenderFactory(this);
this.placeholderManager = new BukkitPlaceholderManager(this);
this.itemManager = new BukkitItemManager(this);
this.integrationManager = new BukkitIntegrationManager(this);
this.competitionManager = new BukkitCompetitionManager(this);
this.marketManager = new BukkitMarketManager(this);
this.storageManager = new BukkitStorageManager(this);
this.lootManager = new BukkitLootManager(this);
this.coolDownManager = new CoolDownManager(this);
this.entityManager = new BukkitEntityManager(this);
this.blockManager = new BukkitBlockManager(this);
this.statisticsManager = new BukkitStatisticsManager(this);
this.effectManager = new BukkitEffectManager(this);
this.hookManager = new BukkitHookManager(this);
this.bagManager = new BukkitBagManager(this);
this.dependencyManager = new DependencyManagerImpl(this);
this.translationManager = new TranslationManager(this);
}
@Override
public void load() {
this.dependencyManager.loadDependencies(
List.of(Dependency.BOOSTED_YAML,
Dependency.BSTATS_BASE,
Dependency.BSTATS_BUKKIT,
Dependency.CAFFEINE,
Dependency.CLOUD_CORE,
Dependency.CLOUD_SERVICES,
Dependency.CLOUD_BUKKIT,
Dependency.CLOUD_PAPER,
Dependency.CLOUD_BRIGADIER,
Dependency.CLOUD_MINECRAFT_EXTRAS,
Dependency.GSON,
Dependency.COMMONS_POOL_2,
Dependency.JEDIS,
Dependency.EXP4J,
Dependency.MYSQL_DRIVER,
Dependency.MARIADB_DRIVER,
Dependency.SQLITE_DRIVER,
Dependency.H2_DRIVER,
Dependency.MONGODB_DRIVER_CORE,
Dependency.MONGODB_DRIVER_SYNC,
Dependency.MONGODB_DRIVER_BSON,
Dependency.HIKARI_CP)
);
}
@Override
public void enable() {
this.reload();
if (ConfigManager.metrics()) new Metrics((JavaPlugin) getBoostrap(), 16648);
if (ConfigManager.checkUpdate()) {
VersionHelper.UPDATE_CHECKER.apply(this).thenAccept(result -> {
if (!result) this.getPluginLogger().info("You are using the latest version.");
else this.getPluginLogger().warn("Update is available: https://polymart.org/resource/2723");
});
}
this.integrationManager.load();
this.initialized = true;
}
@Override
public void reload() {
this.eventManager.reload();
this.configManager.reload();
this.requirementManager.reload();
this.actionManager.reload();
this.placeholderManager.reload();
this.itemManager.reload();
this.competitionManager.reload();
this.marketManager.reload();
this.storageManager.reload();
this.lootManager.reload();
this.coolDownManager.reload();
this.entityManager.reload();
this.blockManager.reload();
this.statisticsManager.reload();
this.effectManager.reload();
this.hookManager.reload();
this.bagManager.reload();
this.translationManager.reload();
}
@Override
public void disable() {
this.eventManager.disable();
this.configManager.disable();
this.requirementManager.disable();
this.actionManager.disable();
this.placeholderManager.disable();
this.itemManager.disable();
this.competitionManager.disable();
this.marketManager.disable();
this.storageManager.disable();
this.lootManager.disable();
this.coolDownManager.disable();
this.entityManager.disable();
this.blockManager.disable();
this.statisticsManager.disable();
this.effectManager.disable();
this.hookManager.disable();
this.bagManager.disable();
this.integrationManager.disable();
this.initialized = false;
}
@Override
public InputStream getResourceStream(String filePath) {
return getBoostrap().getResource(filePath);
}
@Override
public PluginLogger getPluginLogger() {
return logger;
}
@Override
public ClassPathAppender getClassPathAppender() {
return classPathAppender;
}
@Override
public Path getDataDirectory() {
return getBoostrap().getDataFolder().toPath().toAbsolutePath();
}
@Override
public String getServerVersion() {
return Bukkit.getServer().getBukkitVersion().split("-")[0];
}
@SuppressWarnings("deprecation")
@Override
public String getPluginVersion() {
return getBoostrap().getDescription().getVersion();
}
}

View File

@@ -13,7 +13,6 @@ 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.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;
@@ -52,6 +51,16 @@ public class BukkitActionManager implements ActionManager<Player> {
public BukkitActionManager(BukkitCustomFishingPlugin plugin) {
this.plugin = plugin;
this.registerBuiltInActions();
}
@Override
public void disable() {
this.actionFactoryMap.clear();
}
@Override
public void reload() {
this.loadExpansions();
}
@@ -393,11 +402,11 @@ public class BukkitActionManager implements ActionManager<Player> {
if (Math.random() > chance) return;
Player player = context.getHolder();
ItemStack itemStack = player.getInventory().getItem(slot);
if (amount > 0) {
ItemUtils.increaseDurability(itemStack, amount, true);
} else {
ItemUtils.decreaseDurability(context.getHolder(), itemStack, -amount, true);
}
// if (amount > 0) {
// ItemUtils.increaseDurability(itemStack, amount, true);
// } else {
// ItemUtils.decreaseDurability(context.getHolder(), itemStack, -amount, true);
// }
};
} else {
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at durability action which should be Section");

View File

@@ -65,7 +65,7 @@ public class BukkitBlockManager implements BlockManager, Listener {
private final HashMap<String, BlockStateModifierFactory> stateFactories = new HashMap<>();
private BlockProvider[] blockDetectArray;
public BukkitBlockManager(BukkitCustomFishingPluginImpl plugin) {
public BukkitBlockManager(BukkitCustomFishingPlugin plugin) {
this.plugin = plugin;
this.registerInbuiltProperties();
this.registerBlockProvider(new BlockProvider() {
@@ -88,13 +88,6 @@ public class BukkitBlockManager implements BlockManager, Listener {
});
}
@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() {
Bukkit.getPluginManager().registerEvents(this, plugin.getBoostrap());
@@ -122,6 +115,13 @@ public class BukkitBlockManager implements BlockManager, Listener {
this.blockDetectArray = list.toArray(new BlockProvider[0]);
}
@Override
public boolean registerBlock(@NotNull BlockConfig block) {
if (blocks.containsKey(block.id())) return false;
blocks.put(block.id(), block);
return true;
}
/**
* Event handler for the EntityChangeBlockEvent.
* This method is triggered when an entity changes a block, typically when a block falls or lands.
@@ -230,8 +230,8 @@ public class BukkitBlockManager implements BlockManager, Listener {
PersistentDataType.STRING,
id + ";" + context.getHolder().getName()
);
Vector vector = playerLocation.subtract(hookLocation).toVector().multiply((config.horizontalVector().evaluate(context)) - 1);
vector = vector.setY((vector.getY() + 0.2) * config.verticalVector().evaluate(context));
Vector vector = playerLocation.subtract(hookLocation).toVector().multiply(1.2 - 1);
vector = vector.setY((vector.getY() + 0.2) * 1.2);
fallingBlock.setVelocity(vector);
return fallingBlock;
}

View File

@@ -20,7 +20,7 @@ public class ReloadCommand extends BukkitCommandFeature<CommandSender> {
.flag(manager.flagBuilder("silent"))
.handler(context -> {
BukkitCustomFishingPlugin.getInstance().reload();
handleFeedback(context.sender(), MessageConstants.COMMAND_RELOAD);
handleFeedback(context.sender(), MessageConstants.COMMAND_RELOAD_SUCCESS);
});
}

View File

@@ -27,9 +27,9 @@ import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
public class BukkitConfigLoader extends ConfigManager {
public class BukkitConfigManager extends ConfigManager {
public BukkitConfigLoader(BukkitCustomFishingPlugin plugin) {
public BukkitConfigManager(BukkitCustomFishingPlugin plugin) {
super(plugin);
this.registerBuiltInItemProperties();
this.registerBuiltInBaseEffectParser();
@@ -438,4 +438,11 @@ public class BukkitConfigLoader extends ConfigManager {
return builder -> builder.statisticsKeys(keys);
}, "statistics");
}
@Override
public void saveResource(String filePath) {
if (!new File(plugin.getDataFolder(), filePath).exists()) {
plugin.getBoostrap().saveResource(filePath, false);
}
}
}

View File

@@ -76,9 +76,9 @@ public class BukkitEntityManager implements EntityManager {
}
@Override
public boolean registerEntity(String id, EntityConfig entity) {
if (entities.containsKey(id)) return false;
this.entities.put(id, entity);
public boolean registerEntity(EntityConfig entity) {
if (entities.containsKey(entity.id())) return false;
this.entities.put(entity.id(), entity);
return true;
}
@@ -99,17 +99,17 @@ public class BukkitEntityManager implements EntityManager {
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();
String entityID = config.entityID();
Entity entity;
if (entityID.contains(":")) {
String[] split = entityID.split(":", 2);
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");
entity = requireNonNull(provider.spawn(hookLocation, split[1], config.propertyMap()), "Entity " + entityID + " doesn't exist");
} else {
entity = entityProviders.get("vanilla").spawn(hookLocation, entityID, config.getPropertyMap());
entity = entityProviders.get("vanilla").spawn(hookLocation, entityID, config.propertyMap());
}
Vector vector = playerLocation.subtract(hookLocation).toVector().multiply((config.getHorizontalVector()) - 1);
vector = vector.setY((vector.getY() + 0.2) * config.getVerticalVector());
Vector vector = playerLocation.subtract(hookLocation).toVector().multiply(config.horizontalVector().evaluate(context) - 1);
vector = vector.setY((vector.getY() + 0.2) * config.verticalVector().evaluate(context));
entity.setVelocity(vector);
return entity;
}

View File

@@ -20,6 +20,9 @@ package net.momirealms.customfishing.bukkit.gui.icon;
import net.momirealms.customfishing.bukkit.adventure.ShadedAdventureComponentWrapper;
import net.momirealms.customfishing.bukkit.gui.Icon;
import net.momirealms.customfishing.bukkit.gui.page.file.FileSelector;
import net.momirealms.customfishing.common.helper.AdventureHelper;
import net.momirealms.customfishing.common.locale.MessageConstants;
import net.momirealms.customfishing.common.locale.TranslationManager;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
@@ -44,10 +47,8 @@ public class BackToFolderItem extends AbstractItem implements Icon {
public ItemProvider getItemProvider() {
if (file != null && (file.getPath().startsWith("plugins\\CustomFishing\\contents") || file.getPath().startsWith("plugins/CustomFishing/contents"))) {
return new ItemBuilder(Material.ORANGE_STAINED_GLASS_PANE)
.setDisplayName(new ShadedAdventureComponentWrapper(AdventureHelper.getInstance().getComponentFromMiniMessage(
CFLocale.GUI_BACK_TO_PARENT_FOLDER
)))
.setLore(List.of(new ShadedAdventureComponentWrapper(AdventureHelper.getInstance().getComponentFromMiniMessage(
.setDisplayName(new ShadedAdventureComponentWrapper(TranslationManager.render(MessageConstants.GUI_BACK_TO_PARENT_FOLDER.build())))
.setLore(List.of(new ShadedAdventureComponentWrapper(AdventureHelper.miniMessage(
"<#FFA500>-> " + file.getName()
))));
} else {

View File

@@ -19,6 +19,8 @@ package net.momirealms.customfishing.bukkit.gui.icon;
import net.momirealms.customfishing.bukkit.adventure.ShadedAdventureComponentWrapper;
import net.momirealms.customfishing.bukkit.gui.ParentPage;
import net.momirealms.customfishing.common.locale.MessageConstants;
import net.momirealms.customfishing.common.locale.TranslationManager;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
@@ -39,9 +41,7 @@ public class BackToPageItem extends AbstractItem {
@Override
public ItemProvider getItemProvider() {
return new ItemBuilder(Material.ORANGE_STAINED_GLASS_PANE)
.setDisplayName(new ShadedAdventureComponentWrapper(AdventureHelper.getInstance().getComponentFromMiniMessage(
CFLocale.GUI_BACK_TO_PARENT_PAGE
)));
.setDisplayName(new ShadedAdventureComponentWrapper(TranslationManager.render(MessageConstants.GUI_BACK_TO_PARENT_PAGE.build())));
}
@Override

View File

@@ -17,8 +17,11 @@
package net.momirealms.customfishing.bukkit.gui.icon;
import net.kyori.adventure.text.Component;
import net.momirealms.customfishing.bukkit.adventure.ShadedAdventureComponentWrapper;
import net.momirealms.customfishing.bukkit.gui.Icon;
import net.momirealms.customfishing.common.locale.MessageConstants;
import net.momirealms.customfishing.common.locale.TranslationManager;
import org.bukkit.Material;
import xyz.xenondevs.invui.gui.PagedGui;
import xyz.xenondevs.invui.item.ItemProvider;
@@ -34,15 +37,13 @@ public class NextPageItem extends PageItem implements Icon {
@Override
public ItemProvider getItemProvider(PagedGui<?> gui) {
ItemBuilder builder = new ItemBuilder(Material.GREEN_STAINED_GLASS_PANE);
builder.setDisplayName(new ShadedAdventureComponentWrapper(AdventureHelper.getInstance().getComponentFromMiniMessage(
CFLocale.GUI_NEXT_PAGE
)))
.addLoreLines(new ShadedAdventureComponentWrapper(AdventureHelper.getInstance().getComponentFromMiniMessage(
gui.hasNextPage()
? CFLocale.GUI_GOTO_NEXT_PAGE
.replace("{0}", String.valueOf(gui.getCurrentPage() + 2))
.replace("{1}", String.valueOf(gui.getPageAmount()))
: CFLocale.GUI_CANNOT_GOTO_NEXT_PAGE
builder.setDisplayName(new ShadedAdventureComponentWrapper(TranslationManager.render(MessageConstants.GUI_NEXT_PAGE.build())))
.addLoreLines(new ShadedAdventureComponentWrapper(TranslationManager.render( gui.hasNextPage()
? MessageConstants.GUI_GOTO_NEXT_PAGE.arguments(
Component.text(gui.getCurrentPage() + 2),
Component.text(gui.getPageAmount())
).build() :
MessageConstants.GUI_CANNOT_GOTO_NEXT_PAGE.build()
)));
return builder;
}

View File

@@ -17,8 +17,11 @@
package net.momirealms.customfishing.bukkit.gui.icon;
import net.kyori.adventure.text.Component;
import net.momirealms.customfishing.bukkit.adventure.ShadedAdventureComponentWrapper;
import net.momirealms.customfishing.bukkit.gui.Icon;
import net.momirealms.customfishing.common.locale.MessageConstants;
import net.momirealms.customfishing.common.locale.TranslationManager;
import org.bukkit.Material;
import xyz.xenondevs.invui.gui.PagedGui;
import xyz.xenondevs.invui.item.ItemProvider;
@@ -34,16 +37,13 @@ public class PreviousPageItem extends PageItem implements Icon {
@Override
public ItemProvider getItemProvider(PagedGui<?> gui) {
ItemBuilder builder = new ItemBuilder(Material.RED_STAINED_GLASS_PANE);
builder.setDisplayName(new ShadedAdventureComponentWrapper(AdventureHelper.getInstance().getComponentFromMiniMessage(
CFLocale.GUI_PREVIOUS_PAGE
)))
.addLoreLines(new ShadedAdventureComponentWrapper(AdventureHelper.getInstance().getComponentFromMiniMessage(
gui.hasPreviousPage()
? CFLocale.GUI_GOTO_PREVIOUS_PAGE
.replace("{0}", String.valueOf(gui.getCurrentPage()))
.replace("{1}", String.valueOf(gui.getPageAmount()))
: CFLocale.GUI_CANNOT_GOTO_PREVIOUS_PAGE
)));
builder.setDisplayName(new ShadedAdventureComponentWrapper(TranslationManager.render(MessageConstants.GUI_PREVIOUS_PAGE.build())))
.addLoreLines(new ShadedAdventureComponentWrapper(TranslationManager.render( gui.hasPreviousPage()
? MessageConstants.GUI_GOTO_PREVIOUS_PAGE.arguments(
Component.text(gui.getCurrentPage()),
Component.text(gui.getPageAmount())
).build()
: MessageConstants.GUI_CANNOT_GOTO_PREVIOUS_PAGE.build())));
return builder;
}
}

View File

@@ -17,9 +17,12 @@
package net.momirealms.customfishing.bukkit.gui.icon.property.item;
import net.kyori.adventure.text.Component;
import net.momirealms.customfishing.bukkit.adventure.ShadedAdventureComponentWrapper;
import net.momirealms.customfishing.bukkit.gui.SectionPage;
import net.momirealms.customfishing.bukkit.gui.page.property.AmountEditor;
import net.momirealms.customfishing.common.locale.MessageConstants;
import net.momirealms.customfishing.common.locale.TranslationManager;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
@@ -40,24 +43,19 @@ public class AmountItem extends AbstractItem {
@Override
public ItemProvider getItemProvider() {
ItemBuilder itemBuilder = new ItemBuilder(Material.IRON_NUGGET)
.setDisplayName(new ShadedAdventureComponentWrapper(AdventureHelper.getComponentFromMiniMessage(
CFLocale.GUI_ITEM_AMOUNT
)))
.setDisplayName(new ShadedAdventureComponentWrapper(TranslationManager.render(MessageConstants.GUI_ITEM_AMOUNT.build())))
.setAmount(itemPage.getSection().getInt("amount", 1));
if (itemPage.getSection().contains("amount")) {
itemBuilder.addLoreLines(new ShadedAdventureComponentWrapper(AdventureHelper.getInstance().getComponentFromMiniMessage(
CFLocale.GUI_CURRENT_VALUE + itemPage.getSection().getInt("amount")
itemBuilder.addLoreLines(new ShadedAdventureComponentWrapper(TranslationManager.render(
MessageConstants.GUI_CURRENT_VALUE.arguments(
Component.text(itemPage.getSection().getInt("amount"))
).build()
)))
.addLoreLines("");
itemBuilder.addLoreLines(new ShadedAdventureComponentWrapper(AdventureHelper.getInstance().getComponentFromMiniMessage(
CFLocale.GUI_LEFT_CLICK_EDIT
))).addLoreLines(new ShadedAdventureComponentWrapper(AdventureHelper.getInstance().getComponentFromMiniMessage(
CFLocale.GUI_RIGHT_CLICK_RESET
)));
itemBuilder.addLoreLines(new ShadedAdventureComponentWrapper(TranslationManager.render(MessageConstants.GUI_LEFT_CLICK_EDIT.build())))
.addLoreLines(new ShadedAdventureComponentWrapper(TranslationManager.render(MessageConstants.GUI_RIGHT_CLICK_RESET.build())));
} else {
itemBuilder.addLoreLines(new ShadedAdventureComponentWrapper(AdventureHelper.getInstance().getComponentFromMiniMessage(
CFLocale.GUI_LEFT_CLICK_EDIT
)));
itemBuilder.addLoreLines(new ShadedAdventureComponentWrapper(TranslationManager.render(MessageConstants.GUI_LEFT_CLICK_EDIT.build())));
}
return itemBuilder;
}

View File

@@ -17,9 +17,12 @@
package net.momirealms.customfishing.bukkit.gui.icon.property.item;
import net.kyori.adventure.text.Component;
import net.momirealms.customfishing.bukkit.adventure.ShadedAdventureComponentWrapper;
import net.momirealms.customfishing.bukkit.gui.SectionPage;
import net.momirealms.customfishing.bukkit.gui.page.property.CustomModelDataEditor;
import net.momirealms.customfishing.common.locale.MessageConstants;
import net.momirealms.customfishing.common.locale.TranslationManager;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
@@ -40,23 +43,20 @@ public class CMDItem extends AbstractItem {
@Override
public ItemProvider getItemProvider() {
ItemBuilder itemBuilder = new ItemBuilder(Material.GLOW_INK_SAC)
.setDisplayName(new ShadedAdventureComponentWrapper(AdventureHelper.getInstance().getComponentFromMiniMessage(
CFLocale.GUI_ITEM_MODEL_DATA
.setDisplayName(new ShadedAdventureComponentWrapper(TranslationManager.render(
MessageConstants.GUI_ITEM_CUSTOM_MODEL_DATA.build()
)));
if (itemPage.getSection().contains("custom-model-data")) {
itemBuilder.addLoreLines(new ShadedAdventureComponentWrapper(AdventureHelper.getInstance().getComponentFromMiniMessage(
CFLocale.GUI_CURRENT_VALUE + itemPage.getSection().getInt("custom-model-data")
itemBuilder.addLoreLines(new ShadedAdventureComponentWrapper(TranslationManager.render(
MessageConstants.GUI_CURRENT_VALUE.arguments(
Component.text(itemPage.getSection().getInt("custom-model-data"))
).build()
)))
.addLoreLines("");
itemBuilder.addLoreLines(new ShadedAdventureComponentWrapper(AdventureHelper.getInstance().getComponentFromMiniMessage(
CFLocale.GUI_LEFT_CLICK_EDIT
))).addLoreLines(new ShadedAdventureComponentWrapper(AdventureHelper.getInstance().getComponentFromMiniMessage(
CFLocale.GUI_RIGHT_CLICK_RESET
)));
itemBuilder.addLoreLines(new ShadedAdventureComponentWrapper(TranslationManager.render(MessageConstants.GUI_LEFT_CLICK_EDIT.build())))
.addLoreLines(new ShadedAdventureComponentWrapper(TranslationManager.render(MessageConstants.GUI_RIGHT_CLICK_RESET.build())));
} else {
itemBuilder.addLoreLines(new ShadedAdventureComponentWrapper(AdventureHelper.getInstance().getComponentFromMiniMessage(
CFLocale.GUI_LEFT_CLICK_EDIT
)));
itemBuilder.addLoreLines(new ShadedAdventureComponentWrapper(TranslationManager.render(MessageConstants.GUI_LEFT_CLICK_EDIT.build())));
}
return itemBuilder;
}

View File

@@ -20,7 +20,6 @@ package net.momirealms.customfishing.bukkit.gui.icon.property.item;
import net.momirealms.customfishing.bukkit.adventure.ShadedAdventureComponentWrapper;
import net.momirealms.customfishing.bukkit.gui.SectionPage;
import net.momirealms.customfishing.bukkit.gui.page.property.NBTEditor;
import net.momirealms.customfishing.bukkit.util.ConfigUtils;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;

View File

@@ -23,6 +23,8 @@ import net.momirealms.customfishing.bukkit.gui.icon.BackToFolderItem;
import net.momirealms.customfishing.bukkit.gui.icon.ScrollDownItem;
import net.momirealms.customfishing.bukkit.gui.icon.ScrollUpItem;
import net.momirealms.customfishing.bukkit.gui.page.item.ItemSelector;
import net.momirealms.customfishing.common.locale.MessageConstants;
import net.momirealms.customfishing.common.locale.TranslationManager;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
@@ -79,19 +81,10 @@ public class FileSelector {
Window window = Window.single()
.setViewer(player)
.setTitle(new ShadedAdventureComponentWrapper(AdventureHelper.getInstance().getComponentFromMiniMessage(
CFLocale.GUI_SELECT_FILE
)))
.setTitle(new ShadedAdventureComponentWrapper(TranslationManager.render(MessageConstants.GUI_SELECT_FILE.build())))
.setGui(gui)
.build();
// gui.playAnimation(new SequentialAnimation(1, true), slotElement -> {
// if (slotElement instanceof SlotElement.ItemSlotElement itemSlotElement) {
// return !(itemSlotElement.getItem() instanceof Icon);
// }
// return true;
// });
window.open();
}

View File

@@ -20,7 +20,6 @@ package net.momirealms.customfishing.bukkit.gui.page.property;
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.util.ConfigUtils;
import org.bukkit.Material;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Player;

View File

@@ -0,0 +1,28 @@
package net.momirealms.customfishing.bukkit.hook;
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
import net.momirealms.customfishing.api.mechanic.hook.HookConfig;
import net.momirealms.customfishing.api.mechanic.hook.HookManager;
import org.jetbrains.annotations.NotNull;
import java.util.Optional;
public class BukkitHookManager implements HookManager {
private BukkitCustomFishingPlugin plugin;
public BukkitHookManager(BukkitCustomFishingPlugin plugin) {
this.plugin = plugin;
}
@Override
public boolean registerHook(HookConfig hook) {
return false;
}
@NotNull
@Override
public Optional<HookConfig> getHook(String id) {
return Optional.empty();
}
}

View File

@@ -9,7 +9,6 @@ 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;

View File

@@ -47,9 +47,18 @@ public class BukkitRequirementManager implements RequirementManager<Player> {
public BukkitRequirementManager(BukkitCustomFishingPlugin plugin) {
this.plugin = plugin;
this.registerBuiltInRequirements();
}
@Override
public void reload() {
this.loadExpansions();
}
@Override
public void disable() {
this.requirementFactoryMap.clear();
}
@Override
public boolean registerRequirement(@NotNull String type, @NotNull RequirementFactory<Player> requirementFactory) {
if (this.requirementFactoryMap.containsKey(type)) return false;

View File

@@ -1,63 +1,62 @@
/*
* 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.requirement;
import net.momirealms.customfishing.api.common.Pair;
import net.momirealms.customfishing.api.mechanic.requirement.Requirement;
import org.bukkit.entity.Player;
import java.util.HashMap;
import java.util.List;
public class ConditionalElement {
private final List<Pair<String, WeightModifier>> modifierList;
private final HashMap<String, ConditionalElement> subLoots;
private final Requirement[] requirements;
public ConditionalElement(
Requirement[] requirements,
List<Pair<String, WeightModifier>> modifierList,
HashMap<String, ConditionalElement> subElements
) {
this.modifierList = modifierList;
this.requirements = requirements;
this.subLoots = subElements;
}
/**
* Combines the weight modifiers for this element.
*
* @param player The player for whom the modifiers are applied.
* @param weightMap The map of weight modifiers.
*/
synchronized public void combine(Player player, HashMap<String, Double> weightMap) {
for (Pair<String, WeightModifier> modifierPair : this.modifierList) {
double previous = weightMap.getOrDefault(modifierPair.left(), 0d);
weightMap.put(modifierPair.left(), modifierPair.right().modify(player, previous));
}
}
public Requirement[] getRequirements() {
return requirements;
}
public HashMap<String, ConditionalElement> getSubElements() {
return subLoots;
}
}
///*
// * 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.requirement;
//
//import net.momirealms.customfishing.api.mechanic.requirement.Requirement;
//import org.bukkit.entity.Player;
//
//import java.util.HashMap;
//import java.util.List;
//
//public class ConditionalElement {
//
// private final List<Pair<String, WeightModifier>> modifierList;
// private final HashMap<String, ConditionalElement> subLoots;
// private final Requirement[] requirements;
//
// public ConditionalElement(
// Requirement[] requirements,
// List<Pair<String, WeightModifier>> modifierList,
// HashMap<String, ConditionalElement> subElements
// ) {
// this.modifierList = modifierList;
// this.requirements = requirements;
// this.subLoots = subElements;
// }
//
// /**
// * Combines the weight modifiers for this element.
// *
// * @param player The player for whom the modifiers are applied.
// * @param weightMap The map of weight modifiers.
// */
// synchronized public void combine(Player player, HashMap<String, Double> weightMap) {
// for (Pair<String, WeightModifier> modifierPair : this.modifierList) {
// double previous = weightMap.getOrDefault(modifierPair.left(), 0d);
// weightMap.put(modifierPair.left(), modifierPair.right().modify(player, previous));
// }
// }
//
// public Requirement[] getRequirements() {
// return requirements;
// }
//
// public HashMap<String, ConditionalElement> getSubElements() {
// return subLoots;
// }
//}

View File

@@ -74,6 +74,7 @@ public class BukkitStorageManager implements StorageManager, Listener {
Bukkit.getPluginManager().registerEvents(this, plugin.getBoostrap());
}
@Override
public void reload() {
YamlDocument config = plugin.getConfigManager().loadConfig("database.yml");
this.serverID = config.getString("unique-server-id", "default");
@@ -132,6 +133,7 @@ public class BukkitStorageManager implements StorageManager, Listener {
/**
* Disables the storage manager and cleans up resources.
*/
@Override
public void disable() {
HandlerList.unregisterAll(this);
this.dataSource.updateManyPlayersData(onlineUserMap.values(), true);

View File

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

View File

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

View File

@@ -18,8 +18,8 @@
package net.momirealms.customfishing.bukkit.totem.particle;
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
import net.momirealms.customfishing.api.common.Pair;
import net.momirealms.customfishing.api.scheduler.CancellableTask;
import net.momirealms.customfishing.common.plugin.scheduler.SchedulerTask;
import net.momirealms.customfishing.common.util.Pair;
import org.bukkit.Location;
import org.bukkit.Particle;
import org.bukkit.World;
@@ -46,7 +46,7 @@ public class DustParticleSetting extends ParticleSetting {
}
@SuppressWarnings("DuplicatedCode")
public CancellableTask start(Location location, double radius) {
public SchedulerTask start(Location location, double radius) {
World world = location.getWorld();
return BukkitCustomFishingPlugin.get().getScheduler().runTaskAsyncTimer(() -> {
for (Pair<Double, Double> range : ranges) {

View File

@@ -18,9 +18,9 @@
package net.momirealms.customfishing.bukkit.totem.particle;
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
import net.momirealms.customfishing.api.common.Pair;
import net.momirealms.customfishing.api.mechanic.totem.TotemParticle;
import net.momirealms.customfishing.api.scheduler.CancellableTask;
import net.momirealms.customfishing.common.plugin.scheduler.SchedulerTask;
import net.momirealms.customfishing.common.util.Pair;
import net.objecthunter.exp4j.Expression;
import net.objecthunter.exp4j.ExpressionBuilder;
import org.bukkit.Location;
@@ -63,9 +63,9 @@ public class ParticleSetting implements TotemParticle {
}
@SuppressWarnings("DuplicatedCode")
public CancellableTask start(Location location, double radius) {
public SchedulerTask start(Location location, double radius) {
World world = location.getWorld();
return BukkitCustomFishingPlugin.get().getScheduler().runTaskAsyncTimer(() -> {
return BukkitCustomFishingPlugin.getInstance().getScheduler().asyncRepeating(() -> {
for (Pair<Double, Double> range : ranges) {
for (double theta = range.left(); theta <= range.right(); theta += interval) {
double r = expressionHorizontal.setVariable("theta", theta).setVariable("radius", radius).evaluate();

View File

@@ -1,221 +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.util;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.PacketContainer;
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.api.BukkitCustomFishingPlugin;
import org.bukkit.Location;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
* Utility class for managing armor stands and sending related packets.
*/
public class ArmorStandUtils {
private ArmorStandUtils() {}
/**
* Creates a destroy packet for removing an armor stand entity.
*
* @param id The ID of the armor stand entity to destroy
* @return The PacketContainer representing the destroy packet
*/
public static PacketContainer getDestroyPacket(int id) {
PacketContainer destroyPacket = new PacketContainer(PacketType.Play.Server.ENTITY_DESTROY);
destroyPacket.getIntLists().write(0, List.of(id));
return destroyPacket;
}
/**
* Creates a spawn packet for an armor stand entity at the specified location.
*
* @param id The ID of the armor stand entity to spawn
* @param location The location where the armor stand entity should be spawned
* @return The PacketContainer representing the spawn packet
*/
public static PacketContainer getSpawnPacket(int id, Location location) {
PacketContainer entityPacket = new PacketContainer(PacketType.Play.Server.SPAWN_ENTITY);
try {
entityPacket.getModifier().write(0, id);
entityPacket.getModifier().write(1, UUID.randomUUID());
entityPacket.getEntityTypeModifier().write(0, EntityType.ARMOR_STAND);
entityPacket.getDoubles().write(0, location.getX());
entityPacket.getDoubles().write(1, location.getY());
entityPacket.getDoubles().write(2, location.getZ());
if (BukkitCustomFishingPlugin.get().getVersionManager().isVersionNewerThan1_19()) {
entityPacket.getBytes().write(0, (byte) ((location.getYaw() % 360) * 128 / 180));
} else {
entityPacket.getIntegers().write(5, (int) ((location.getYaw() % 360) * 128 / 180));
}
} catch (Exception e) {
e.printStackTrace();
}
return entityPacket;
}
/**
* Creates a metadata packet for updating the metadata of an armor stand entity.
*
* @param id The ID of the armor stand entity
* @return The PacketContainer representing the metadata packet
*/
public static PacketContainer getMetaPacket(int id) {
PacketContainer metaPacket = new PacketContainer(PacketType.Play.Server.ENTITY_METADATA);
metaPacket.getIntegers().write(0, id);
if (BukkitCustomFishingPlugin.get().getVersionManager().isVersionNewerThan1_19_3()) {
WrappedDataWatcher wrappedDataWatcher = createDataWatcher();
setValueList(metaPacket, wrappedDataWatcher);
} else {
metaPacket.getWatchableCollectionModifier().write(0, createDataWatcher().getWatchableObjects());
}
return metaPacket;
}
/**
* Sets the value list in a PacketContainer's DataWatcher from a WrappedDataWatcher.
*
* @param metaPacket The PacketContainer representing the metadata packet
* @param wrappedDataWatcher The WrappedDataWatcher containing the value list
*/
@SuppressWarnings("DuplicatedCode")
private static void setValueList(PacketContainer metaPacket, WrappedDataWatcher wrappedDataWatcher) {
List<WrappedDataValue> wrappedDataValueList = Lists.newArrayList();
wrappedDataWatcher.getWatchableObjects().stream().filter(Objects::nonNull).forEach(entry -> {
final WrappedDataWatcher.WrappedDataWatcherObject dataWatcherObject = entry.getWatcherObject();
wrappedDataValueList.add(new WrappedDataValue(dataWatcherObject.getIndex(), dataWatcherObject.getSerializer(), entry.getRawValue()));
});
metaPacket.getDataValueCollectionModifier().write(0, wrappedDataValueList);
}
/**
* Creates a metadata packet for updating the metadata of an armor stand entity with a custom Component.
*
* @param id The ID of the armor stand entity
* @param component The Component to set as metadata
* @return The PacketContainer representing the metadata packet
*/
public static PacketContainer getMetaPacket(int id, Component component) {
PacketContainer metaPacket = new PacketContainer(PacketType.Play.Server.ENTITY_METADATA);
metaPacket.getIntegers().write(0, id);
if (BukkitCustomFishingPlugin.get().getVersionManager().isVersionNewerThan1_19_3()) {
WrappedDataWatcher wrappedDataWatcher = createDataWatcher(component);
setValueList(metaPacket, wrappedDataWatcher);
} else {
metaPacket.getWatchableCollectionModifier().write(0, createDataWatcher(component).getWatchableObjects());
}
return metaPacket;
}
/**
* Creates a DataWatcher for an invisible armor stand entity.
*
* @return The created DataWatcher
*/
public static WrappedDataWatcher createDataWatcher() {
WrappedDataWatcher wrappedDataWatcher = new WrappedDataWatcher();
WrappedDataWatcher.Serializer serializer1 = WrappedDataWatcher.Registry.get(Boolean.class);
WrappedDataWatcher.Serializer serializer2 = WrappedDataWatcher.Registry.get(Byte.class);
wrappedDataWatcher.setObject(new WrappedDataWatcher.WrappedDataWatcherObject(3, serializer1), false);
byte flag = 0x20;
wrappedDataWatcher.setObject(new WrappedDataWatcher.WrappedDataWatcherObject(0, serializer2), flag);
return wrappedDataWatcher;
}
/**
* Creates a DataWatcher for an invisible armor stand entity with a custom Component.
*
* @param component The Component to set in the DataWatcher
* @return The created DataWatcher
*/
public static WrappedDataWatcher createDataWatcher(Component component) {
WrappedDataWatcher wrappedDataWatcher = new WrappedDataWatcher();
WrappedDataWatcher.Serializer serializer1 = WrappedDataWatcher.Registry.get(Boolean.class);
WrappedDataWatcher.Serializer serializer2 = WrappedDataWatcher.Registry.get(Byte.class);
wrappedDataWatcher.setObject(new WrappedDataWatcher.WrappedDataWatcherObject(2, WrappedDataWatcher.Registry.getChatComponentSerializer(true)), Optional.of(WrappedChatComponent.fromJson(GsonComponentSerializer.gson().serialize(component)).getHandle()));
wrappedDataWatcher.setObject(new WrappedDataWatcher.WrappedDataWatcherObject(3, serializer1), true);
wrappedDataWatcher.setObject(new WrappedDataWatcher.WrappedDataWatcherObject(15, serializer2), (byte) 0x01);
byte flag = 0x20;
wrappedDataWatcher.setObject(new WrappedDataWatcher.WrappedDataWatcherObject(0, serializer2), flag);
return wrappedDataWatcher;
}
/**
* Creates an equipment packet for equipping an armor stand with an ItemStack.
*
* @param id The ID of the armor stand entity
* @param itemStack The ItemStack to equip
* @return The PacketContainer representing the equipment packet
*/
public static PacketContainer getEquipPacket(int id, ItemStack itemStack) {
PacketContainer equipPacket = new PacketContainer(PacketType.Play.Server.ENTITY_EQUIPMENT);
equipPacket.getIntegers().write(0, id);
List<Pair<EnumWrappers.ItemSlot, ItemStack>> pairs = new ArrayList<>();
pairs.add(new Pair<>(EnumWrappers.ItemSlot.HEAD, itemStack));
equipPacket.getSlotStackPairLists().write(0, pairs);
return equipPacket;
}
/**
* Sends a fake armor stand entity with item on head to a player at the specified location.
*
* @param player The player to send the entity to
* @param location The location where the entity should appear
* @param itemStack The ItemStack to represent the entity
* @param seconds The duration (in seconds) the entity should be displayed
*/
public static void sendFakeItem(Player player, Location location, ItemStack itemStack, int seconds) {
int id = new Random().nextInt(Integer.MAX_VALUE);
if (BukkitCustomFishingPlugin.get().getVersionManager().isVersionNewerThan1_19_4()) {
BukkitCustomFishingPluginImpl.sendPackets(player, getSpawnPacket(id, location.clone().subtract(0,1,0)), getMetaPacket(id), getEquipPacket(id, itemStack));
} else {
BukkitCustomFishingPluginImpl.sendPacket(player, getSpawnPacket(id, location.clone().subtract(0,1,0)));
BukkitCustomFishingPluginImpl.sendPacket(player, getMetaPacket(id));
BukkitCustomFishingPluginImpl.sendPacket(player, getEquipPacket(id, itemStack));
}
BukkitCustomFishingPlugin.get().getScheduler().runTaskAsyncLater(() -> BukkitCustomFishingPluginImpl.getProtocolManager().sendServerPacket(player, getDestroyPacket(id)), seconds * 50L, TimeUnit.MILLISECONDS);
}
/**
* Sends a hologram (armor stand with custom text) to a player at the specified location.
*
* @param player The player to send the hologram to
* @param location The location where the hologram should appear
* @param component The Component representing the hologram's text
* @param seconds The duration (in seconds) the hologram should be displayed
*/
public static void sendHologram(Player player, Location location, Component component, int seconds) {
int id = new Random().nextInt(Integer.MAX_VALUE);
if (BukkitCustomFishingPlugin.get().getVersionManager().isVersionNewerThan1_19_4()) {
BukkitCustomFishingPluginImpl.sendPackets(player, getSpawnPacket(id, location.clone().subtract(0,1,0)), getMetaPacket(id, component));
} else {
BukkitCustomFishingPluginImpl.sendPacket(player, getSpawnPacket(id, location.clone().subtract(0,1,0)));
BukkitCustomFishingPluginImpl.sendPacket(player, getMetaPacket(id, component));
}
BukkitCustomFishingPlugin.get().getScheduler().runTaskAsyncLater(() -> BukkitCustomFishingPluginImpl.getProtocolManager().sendServerPacket(player, getDestroyPacket(id)), seconds * 50L, TimeUnit.MILLISECONDS);
}
}

View File

@@ -1,256 +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.util;
import net.momirealms.customfishing.api.mechanic.misc.placeholder.BukkitPlaceholderManager;
import net.momirealms.customfishing.api.mechanic.misc.value.MathValue;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Utility class for configuration-related operations.
*/
public class ConfigUtils {
private ConfigUtils() {}
/**
* Splits a string into a pair of integers using the "~" delimiter.
*
* @param value The input string
* @return A Pair of integers
*/
public static Pair<Integer, Integer> splitStringIntegerArgs(String value, String regex) {
String[] split = value.split(regex);
return Pair.of(Integer.parseInt(split[0]), Integer.parseInt(split[1]));
}
/**
* Converts a list of strings in the format "key:value" into a list of Pairs with keys and doubles.
*
* @param list The input list of strings
* @return A list of Pairs containing keys and doubles
*/
public static List<Pair<String, Double>> getWeights(List<String> list) {
List<Pair<String, Double>> result = new ArrayList<>(list.size());
for (String member : list) {
String[] split = member.split(":",2);
String key = split[0];
result.add(Pair.of(key, Double.parseDouble(split[1])));
}
return result;
}
/**
* Retrieves a list of enchantment pairs from a configuration section.
*
* @param section The configuration section to extract enchantment data from.
* @return A list of enchantment pairs.
*/
@NotNull
public static List<Pair<String, Short>> getEnchantmentPair(ConfigurationSection section) {
List<Pair<String, Short>> list = new ArrayList<>();
if (section == null) return list;
for (Map.Entry<String, Object> entry : section.getValues(false).entrySet()) {
if (entry.getValue() instanceof Integer integer) {
list.add(Pair.of(entry.getKey(), Short.parseShort(String.valueOf(Math.max(1, Math.min(Short.MAX_VALUE, integer))))));
}
}
return list;
}
public static List<Pair<Integer, MathValue>> getEnchantAmountPair(ConfigurationSection section) {
List<Pair<Integer, MathValue>> list = new ArrayList<>();
if (section == null) return list;
for (Map.Entry<String, Object> entry : section.getValues(false).entrySet()) {
list.add(Pair.of(Integer.parseInt(entry.getKey()), getValue(entry.getValue())));
}
return list;
}
public static List<Pair<Pair<String, Short>, MathValue>> getEnchantPoolPair(ConfigurationSection section) {
List<Pair<Pair<String, Short>, MathValue>> list = new ArrayList<>();
if (section == null) return list;
for (Map.Entry<String, Object> entry : section.getValues(false).entrySet()) {
list.add(Pair.of(getEnchantmentPair(entry.getKey()), getValue(entry.getValue())));
}
return list;
}
public static Pair<String, Short> getEnchantmentPair(String value) {
int last = value.lastIndexOf(":");
if (last == -1 || last == 0 || last == value.length() - 1) {
throw new IllegalArgumentException("Invalid format of the input enchantment");
}
return Pair.of(value.substring(0, last), Short.parseShort(value.substring(last + 1)));
}
/**
* Retrieves a list of enchantment tuples from a configuration section.
*
* @param section The configuration section to extract enchantment data from.
* @return A list of enchantment tuples.
*/
@NotNull
public static List<Tuple<Double, String, Short>> getEnchantmentTuple(ConfigurationSection section) {
List<Tuple<Double, String, Short>> list = new ArrayList<>();
if (section == null) return list;
for (Map.Entry<String, Object> entry : section.getValues(false).entrySet()) {
if (entry.getValue() instanceof ConfigurationSection inner) {
Tuple<Double, String, Short> tuple = Tuple.of(
inner.getDouble("chance"),
inner.getString("enchant"),
Short.valueOf(String.valueOf(inner.getInt("level")))
);
list.add(tuple);
}
}
return list;
}
public static String getString(Object o) {
if (o instanceof String s) {
return s;
} else if (o instanceof Integer i) {
return String.valueOf(i);
} else if (o instanceof Double d) {
return String.valueOf(d);
}
throw new IllegalArgumentException("Illegal string format: " + o);
}
/**
* Reads data from a YAML configuration file and creates it if it doesn't exist.
*
* @param file The file path
* @return The YamlConfiguration
*/
@SuppressWarnings("ResultOfMethodCallIgnored")
public static YamlConfiguration readData(File file) {
if (!file.exists()) {
try {
file.getParentFile().mkdirs();
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
LogUtils.warn("Failed to generate data files!</red>");
}
}
return YamlConfiguration.loadConfiguration(file);
}
/**
* Parses a WeightModifier from a string representation.
*
* @param text The input string
* @return A WeightModifier based on the provided text
* @throws IllegalArgumentException if the weight format is invalid
*/
public static WeightModifier getModifier(String text) {
if (text.length() == 0) {
throw new IllegalArgumentException("Weight format is invalid.");
}
switch (text.charAt(0)) {
case '/' -> {
double arg = Double.parseDouble(text.substring(1));
return (player, weight) -> weight / arg;
}
case '*' -> {
double arg = Double.parseDouble(text.substring(1));
return (player, weight) -> weight * arg;
}
case '-' -> {
double arg = Double.parseDouble(text.substring(1));
return (player, weight) -> weight - arg;
}
case '%' -> {
double arg = Double.parseDouble(text.substring(1));
return (player, weight) -> weight % arg;
}
case '+' -> {
double arg = Double.parseDouble(text.substring(1));
return (player, weight) -> weight + arg;
}
case '=' -> {
String formula = text.substring(1);
return (player, weight) -> getExpressionValue(player, formula, Map.of("{0}", String.valueOf(weight)));
}
default -> throw new IllegalArgumentException("Invalid weight: " + text);
}
}
public static double getExpressionValue(Player player, String formula, Map<String, String> vars) {
formula = BukkitPlaceholderManager.getInstance().parse(player, formula, vars);
return new ExpressionBuilder(formula).build().evaluate();
}
public static ArrayList<String> getReadableSection(Map<String, Object> map) {
ArrayList<String> list = new ArrayList<>();
mapToReadableStringList(map, list, 0, false);
return list;
}
@SuppressWarnings("unchecked")
public static void mapToReadableStringList(Map<String, Object> map, List<String> readableList, int loop_times, boolean isMapList) {
boolean first = true;
for (Map.Entry<String, Object> entry : map.entrySet()) {
Object nbt = entry.getValue();
if (nbt instanceof List<?> list) {
if (isMapList && first) {
first = false;
readableList.add(" ".repeat(loop_times - 1) + "<white>- <gold>" + entry.getKey() + ":");
} else {
readableList.add(" ".repeat(loop_times) + "<gold>" + entry.getKey() + ":");
}
for (Object value : list) {
if (value instanceof Map<?,?> nbtMap) {
mapToReadableStringList((Map<String, Object>) nbtMap, readableList, loop_times + 2, true);
} else {
readableList.add(" ".repeat(loop_times + 1) + "<white>- " + value);
}
}
} else if (nbt instanceof Map<?,?> innerMap) {
if (isMapList && first) {
first = false;
readableList.add(" ".repeat(loop_times - 1) + "<white>- <gold>" + entry.getKey() + ":");
} else {
readableList.add(" ".repeat(loop_times) + "<gold>" + entry.getKey() + ":");
}
mapToReadableStringList((Map<String, Object>) innerMap, readableList, loop_times + 1, false);
} else {
if (isMapList && first) {
first = false;
readableList.add(" ".repeat(loop_times - 1) + "<white>- <gold>" + entry.getKey() + ": <white>" + nbt.toString());
} else {
readableList.add(" ".repeat(loop_times) + "<gold>" + entry.getKey() + ": <white>" + nbt.toString());
}
}
}
}
}

View File

@@ -1,151 +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.util;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.wrappers.WrappedDataValue;
import com.comphenix.protocol.wrappers.WrappedDataWatcher;
import com.google.common.collect.Lists;
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
import org.bukkit.Location;
import org.bukkit.entity.EntityType;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
/**
* Utility class for managing fake item entities using PacketContainers.
*/
public class FakeItemUtils {
private FakeItemUtils() {}
/**
* Creates a destroy packet for removing a fake item entity.
*
* @param id The ID of the fake item entity to destroy
* @return The PacketContainer representing the destroy packet
*/
public static PacketContainer getDestroyPacket(int id) {
PacketContainer destroyPacket = new PacketContainer(PacketType.Play.Server.ENTITY_DESTROY);
destroyPacket.getIntLists().write(0, List.of(id));
return destroyPacket;
}
/**
* Creates a spawn packet for a fake item entity at the specified location.
*
* @param id The ID of the fake item entity to spawn
* @param location The location where the fake item entity should be spawned
* @return The PacketContainer representing the spawn packet
*/
public static PacketContainer getSpawnPacket(int id, Location location) {
PacketContainer entityPacket = new PacketContainer(PacketType.Play.Server.SPAWN_ENTITY);
entityPacket.getModifier().write(0, id);
entityPacket.getModifier().write(1, UUID.randomUUID());
entityPacket.getEntityTypeModifier().write(0, EntityType.DROPPED_ITEM);
entityPacket.getDoubles().write(0, location.getX());
entityPacket.getDoubles().write(1, location.getY() - 0.5);
entityPacket.getDoubles().write(2, location.getZ());
return entityPacket;
}
/**
* Creates a metadata packet for updating the metadata of a fake item entity.
*
* @param id The ID of the fake item entity
* @param itemStack The ItemStack to update the metadata with
* @return The PacketContainer representing the metadata packet
*/
public static PacketContainer getMetaPacket(int id, ItemStack itemStack) {
PacketContainer metaPacket = new PacketContainer(PacketType.Play.Server.ENTITY_METADATA);
metaPacket.getIntegers().write(0, id);
if (BukkitCustomFishingPlugin.getInstance().getVersionManager().isVersionNewerThan1_19_3()) {
WrappedDataWatcher wrappedDataWatcher = createDataWatcher(itemStack);
setValueList(metaPacket, wrappedDataWatcher);
} else {
metaPacket.getWatchableCollectionModifier().write(0, createDataWatcher(itemStack).getWatchableObjects());
}
return metaPacket;
}
/**
* Creates a teleport packet for moving a fake item entity to the specified location.
*
* @param id The ID of the fake item entity to teleport
* @param location The location to teleport the fake item entity to
* @return The PacketContainer representing the teleport packet
*/
public static PacketContainer getTpPacket(int id, Location location) {
PacketContainer tpPacket = new PacketContainer(PacketType.Play.Server.ENTITY_TELEPORT);
tpPacket.getModifier().write(0, id);
tpPacket.getDoubles().write(0, location.getX());
tpPacket.getDoubles().write(1, location.getY() - 0.5);
tpPacket.getDoubles().write(2, location.getZ());
return tpPacket;
}
/**
* Creates a velocity packet for applying velocity to a fake item entity.
*
* @param id The ID of the fake item entity
* @param vector The velocity vector to apply
* @return The PacketContainer representing the velocity packet
*/
public static PacketContainer getVelocityPacket(int id, Vector vector) {
PacketContainer entityPacket = new PacketContainer(PacketType.Play.Server.ENTITY_VELOCITY);
entityPacket.getModifier().write(0, id);
entityPacket.getIntegers().write(1, (int) (vector.getX() * 8000));
entityPacket.getIntegers().write(2, (int) (vector.getY() * 8000));
entityPacket.getIntegers().write(3, (int) (vector.getZ() * 8000));
return entityPacket;
}
/**
* Creates a DataWatcher for a given ItemStack.
*
* @param itemStack The ItemStack to create the DataWatcher for
* @return The created DataWatcher
*/
public static WrappedDataWatcher createDataWatcher(ItemStack itemStack) {
WrappedDataWatcher wrappedDataWatcher = new WrappedDataWatcher();
wrappedDataWatcher.setObject(new WrappedDataWatcher.WrappedDataWatcherObject(8, WrappedDataWatcher.Registry.getItemStackSerializer(false)), itemStack);
wrappedDataWatcher.setObject(new WrappedDataWatcher.WrappedDataWatcherObject(5, WrappedDataWatcher.Registry.get(Boolean.class)), true);
return wrappedDataWatcher;
}
/**
* Sets the value list in a PacketContainer's DataWatcher from a WrappedDataWatcher.
*
* @param metaPacket The PacketContainer representing the metadata packet
* @param wrappedDataWatcher The WrappedDataWatcher containing the value list
*/
@SuppressWarnings("DuplicatedCode")
private static void setValueList(PacketContainer metaPacket, WrappedDataWatcher wrappedDataWatcher) {
List<WrappedDataValue> wrappedDataValueList = Lists.newArrayList();
wrappedDataWatcher.getWatchableObjects().stream().filter(Objects::nonNull).forEach(entry -> {
final WrappedDataWatcher.WrappedDataWatcherObject dataWatcherObject = entry.getWatcherObject();
wrappedDataValueList.add(new WrappedDataValue(dataWatcherObject.getIndex(), dataWatcherObject.getSerializer(), entry.getRawValue()));
});
metaPacket.getDataValueCollectionModifier().write(0, wrappedDataValueList);
}
}

View File

@@ -1,502 +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.util;
import de.tr7zw.changeme.nbtapi.NBTCompound;
import de.tr7zw.changeme.nbtapi.NBTItem;
import de.tr7zw.changeme.nbtapi.NBTList;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.ScoreComponent;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
import net.momirealms.customfishing.api.common.Pair;
import net.momirealms.customfishing.api.mechanic.hook.HookConfigImpl;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerItemDamageEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.bukkit.inventory.meta.Damageable;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.util.io.BukkitObjectInputStream;
import org.bukkit.util.io.BukkitObjectOutputStream;
import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
/**
* Utility class for various item-related operations.
*/
public class ItemUtils {
private ItemUtils() {}
/**
* Updates the lore of an NBTItem based on its custom NBT tags.
*
* @param nbtItem The NBTItem to update
* @return The updated NBTItem
*/
public static NBTItem updateNBTItemLore(NBTItem nbtItem) {
NBTCompound cfCompound = nbtItem.getCompound("CustomFishing");
if (cfCompound == null)
return nbtItem;
NBTCompound displayCompound = nbtItem.getOrCreateCompound("display");
NBTList<String> lore = displayCompound.getStringList("Lore");
lore.removeIf(it -> GsonComponentSerializer.gson().deserialize(it) instanceof ScoreComponent scoreComponent && scoreComponent.name().equals("cf"));
if (cfCompound.hasTag("hook_id")) {
String hookID = cfCompound.getString("hook_id");
HookConfigImpl setting = BukkitCustomFishingPlugin.get().getHookManager().getHookSetting(hookID);
if (setting == null) {
cfCompound.removeKey("hook_id");
cfCompound.removeKey("hook_item");
cfCompound.removeKey("hook_dur");
} else {
for (String newLore : setting.lore()) {
ScoreComponent.Builder builder = Component.score().name("cf").objective("hook");
builder.append(AdventureHelper.getInstance().getComponentFromMiniMessage(
newLore.replace("{dur}", String.valueOf(cfCompound.getInteger("hook_dur")))
.replace("{max}", String.valueOf(setting.maxDurability()))
));
lore.add(GsonComponentSerializer.gson().serialize(builder.build()));
}
}
}
if (cfCompound.hasTag("max_dur")) {
int max = cfCompound.getInteger("max_dur");
int current = cfCompound.getInteger("cur_dur");
for (String newLore : CFConfig.durabilityLore) {
ScoreComponent.Builder builder = Component.score().name("cf").objective("durability");
builder.append(AdventureHelper.getInstance().getComponentFromMiniMessage(
newLore.replace("{dur}", String.valueOf(current))
.replace("{max}", String.valueOf(max))
));
lore.add(GsonComponentSerializer.gson().serialize(builder.build()));
}
}
return nbtItem;
}
/**
* Updates the lore of an ItemStack based on its custom NBT tags.
*
* @param itemStack The ItemStack to update
*/
public static void updateItemLore(ItemStack itemStack) {
if (itemStack == null || itemStack.getType() == Material.AIR)
return;
NBTItem nbtItem = updateNBTItemLore(new NBTItem(itemStack));
itemStack.setItemMeta(nbtItem.getItem().getItemMeta());
}
/**
* Reduces the durability of a fishing hook item.
*
* @param rod The fishing rod ItemStack
* @param updateLore Whether to update the lore after reducing durability
*/
public static void decreaseHookDurability(ItemStack rod, int amount, boolean updateLore) {
if (rod == null || rod.getType() != Material.FISHING_ROD)
return;
NBTItem nbtItem = new NBTItem(rod);
NBTCompound cfCompound = nbtItem.getCompound("CustomFishing");
if (cfCompound != null && cfCompound.hasTag("hook_dur")) {
int hookDur = cfCompound.getInteger("hook_dur");
if (hookDur != -1) {
hookDur = Math.max(0, hookDur - amount);
if (hookDur > 0) {
cfCompound.setInteger("hook_dur", hookDur);
} else {
cfCompound.removeKey("hook_id");
cfCompound.removeKey("hook_dur");
cfCompound.removeKey("hook_item");
}
}
}
if (updateLore) updateNBTItemLore(nbtItem);
rod.setItemMeta(nbtItem.getItem().getItemMeta());
}
/**
* 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.
*/
public static void increaseHookDurability(ItemStack rod, int amount, boolean updateLore) {
if (rod == null || rod.getType() != Material.FISHING_ROD)
return;
NBTItem nbtItem = new NBTItem(rod);
NBTCompound cfCompound = nbtItem.getCompound("CustomFishing");
if (cfCompound != null && cfCompound.hasTag("hook_dur")) {
int hookDur = cfCompound.getInteger("hook_dur");
if (hookDur != -1) {
String id = cfCompound.getString("hook_id");
HookConfigImpl setting = BukkitCustomFishingPlugin.get().getHookManager().getHookSetting(id);
if (setting == null) {
cfCompound.removeKey("hook_id");
cfCompound.removeKey("hook_dur");
cfCompound.removeKey("hook_item");
} else {
hookDur = Math.min(setting.maxDurability(), hookDur + amount);
cfCompound.setInteger("hook_dur", hookDur);
}
}
}
if (updateLore) updateNBTItemLore(nbtItem);
rod.setItemMeta(nbtItem.getItem().getItemMeta());
}
/**
* 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.
*/
public static void setHookDurability(ItemStack rod, int amount, boolean updateLore) {
if (rod == null || rod.getType() != Material.FISHING_ROD)
return;
NBTItem nbtItem = new NBTItem(rod);
NBTCompound cfCompound = nbtItem.getCompound("CustomFishing");
if (cfCompound != null && cfCompound.hasTag("hook_dur")) {
int hookDur = cfCompound.getInteger("hook_dur");
if (hookDur != -1) {
String id = cfCompound.getString("hook_id");
HookConfigImpl setting = BukkitCustomFishingPlugin.get().getHookManager().getHookSetting(id);
if (setting == null) {
cfCompound.removeKey("hook_id");
cfCompound.removeKey("hook_dur");
cfCompound.removeKey("hook_item");
} else {
hookDur = Math.min(setting.maxDurability(), amount);
cfCompound.setInteger("hook_dur", hookDur);
}
}
}
if (updateLore) updateNBTItemLore(nbtItem);
rod.setItemMeta(nbtItem.getItem().getItemMeta());
}
/**
* Decreases the durability of an item and updates its lore.
*
* @param itemStack The ItemStack to reduce durability for
* @param amount The amount by which to reduce durability
* @param updateLore Whether to update the lore after reducing durability
*/
public static void decreaseDurability(Player player, ItemStack itemStack, int amount, boolean updateLore) {
if (itemStack == null || itemStack.getType() == Material.AIR)
return;
NBTItem nbtItem = new NBTItem(itemStack);
NBTCompound cfCompound = nbtItem.getCompound("CustomFishing");
if (cfCompound != null && cfCompound.hasTag("max_dur")) {
int unBreakingLevel = itemStack.getEnchantmentLevel(Enchantment.DURABILITY);
if (Math.random() > (double) 1 / (unBreakingLevel + 1)) {
return;
}
if (nbtItem.getByte("Unbreakable") == 1) {
return;
}
int max = cfCompound.getInteger("max_dur");
int current = cfCompound.getInteger("cur_dur") - amount;
cfCompound.setInteger("cur_dur", current);
int damage = (int) (itemStack.getType().getMaxDurability() * (1 - ((double) current / max)));
nbtItem.setInteger("Damage", damage);
if (current > 0) {
if (updateLore) updateNBTItemLore(nbtItem);
itemStack.setItemMeta(nbtItem.getItem().getItemMeta());
} else {
itemStack.setAmount(0);
}
} else {
ItemMeta previousMeta = itemStack.getItemMeta().clone();
PlayerItemDamageEvent itemDamageEvent = new PlayerItemDamageEvent(player, itemStack, amount, amount);
Bukkit.getPluginManager().callEvent(itemDamageEvent);
if (!itemStack.getItemMeta().equals(previousMeta) || itemDamageEvent.isCancelled()) {
return;
}
int unBreakingLevel = itemStack.getEnchantmentLevel(Enchantment.DURABILITY);
if (Math.random() > (double) 1 / (unBreakingLevel + 1)) {
return;
}
if (nbtItem.getByte("Unbreakable") == 1) {
return;
}
int damage = nbtItem.getInteger("Damage") + amount;
if (damage > itemStack.getType().getMaxDurability()) {
itemStack.setAmount(0);
} else {
nbtItem.setInteger("Damage", damage);
if (updateLore) updateNBTItemLore(nbtItem);
itemStack.setItemMeta(nbtItem.getItem().getItemMeta());
}
}
}
/**
* Increases the durability of an item and updates its lore.
*
* @param itemStack The ItemStack to increase durability for
* @param amount The amount by which to increase durability
* @param updateLore Whether to update the lore after increasing durability
*/
public static void increaseDurability(ItemStack itemStack, int amount, boolean updateLore) {
if (itemStack == null || itemStack.getType() == Material.AIR)
return;
NBTItem nbtItem = new NBTItem(itemStack);
if (nbtItem.getByte("Unbreakable") == 1) {
return;
}
NBTCompound cfCompound = nbtItem.getCompound("CustomFishing");
if (cfCompound != null && cfCompound.hasTag("max_dur")) {
int max = cfCompound.getInteger("max_dur");
int current = Math.min(max, cfCompound.getInteger("cur_dur") + amount);
cfCompound.setInteger("cur_dur", current);
int damage = (int) (itemStack.getType().getMaxDurability() * (1 - ((double) current / max)));
nbtItem.setInteger("Damage", damage);
if (updateLore) updateNBTItemLore(nbtItem);
} else {
int damage = Math.max(nbtItem.getInteger("Damage") - amount, 0);
nbtItem.setInteger("Damage", damage);
}
itemStack.setItemMeta(nbtItem.getItem().getItemMeta());
}
/**
* Sets the durability of an item and updates its lore.
*
* @param itemStack The ItemStack to set durability for
* @param amount The new durability value
* @param updateLore Whether to update the lore after setting durability
*/
public static void setDurability(ItemStack itemStack, int amount, boolean updateLore) {
if (itemStack == null || itemStack.getType() == Material.AIR)
return;
if (amount <= 0) {
itemStack.setAmount(0);
return;
}
NBTItem nbtItem = new NBTItem(itemStack);
if (nbtItem.getByte("Unbreakable") == 1) {
return;
}
NBTCompound cfCompound = nbtItem.getCompound("CustomFishing");
if (cfCompound != null && cfCompound.hasTag("max_dur")) {
int max = cfCompound.getInteger("max_dur");
amount = Math.min(amount, max);
cfCompound.setInteger("cur_dur", amount);
int damage = (int) (itemStack.getType().getMaxDurability() * (1 - ((double) amount / max)));
nbtItem.setInteger("Damage", damage);
if (updateLore) updateNBTItemLore(nbtItem);
} else {
nbtItem.setInteger("Damage", itemStack.getType().getMaxDurability() - amount);
}
itemStack.setItemMeta(nbtItem.getItem().getItemMeta());
}
/**
* Retrieves the current durability of an item.
*
* @param itemStack The ItemStack to get durability from
* @return The current durability value
*/
public static Pair<Integer, Integer> getCustomDurability(ItemStack itemStack) {
if (itemStack == null || itemStack.getType() == Material.AIR)
return Pair.of(0, 0);
if (itemStack.getItemMeta() instanceof Damageable damageable && damageable.isUnbreakable())
return Pair.of(-1, -1);
NBTItem nbtItem = new NBTItem(itemStack);
NBTCompound cfCompound = nbtItem.getCompound("CustomFishing");
if (cfCompound != null && cfCompound.hasTag("max_dur")) {
return Pair.of(cfCompound.getInteger("max_dur"), cfCompound.getInteger("cur_dur"));
} else {
return Pair.of(0, 0);
}
}
/**
* Gives a certain amount of an item to a player, handling stacking and item drops.
*
* @param player The player to give the item to
* @param itemStack The ItemStack to give
* @param amount The amount of items to give
* @return The actual amount of items given
*/
public static int giveItem(Player player, ItemStack itemStack, int amount) {
PlayerInventory inventory = player.getInventory();
ItemMeta meta = itemStack.getItemMeta();
int maxStackSize = itemStack.getMaxStackSize();
if (amount > maxStackSize * 100) {
LogUtils.warn("Detected too many items spawning. Lowering the amount to " + (maxStackSize * 100));
amount = maxStackSize * 100;
}
int actualAmount = amount;
for (ItemStack other : inventory.getStorageContents()) {
if (other != null) {
if (other.getType() == itemStack.getType() && other.getItemMeta().equals(meta)) {
if (other.getAmount() < maxStackSize) {
int delta = maxStackSize - other.getAmount();
if (amount > delta) {
other.setAmount(maxStackSize);
amount -= delta;
} else {
other.setAmount(amount + other.getAmount());
return actualAmount;
}
}
}
}
}
if (amount > 0) {
for (ItemStack other : inventory.getStorageContents()) {
if (other == null) {
if (amount > maxStackSize) {
amount -= maxStackSize;
ItemStack cloned = itemStack.clone();
cloned.setAmount(maxStackSize);
inventory.addItem(cloned);
} else {
ItemStack cloned = itemStack.clone();
cloned.setAmount(amount);
inventory.addItem(cloned);
return actualAmount;
}
}
}
}
if (amount > 0) {
for (int i = 0; i < amount / maxStackSize; i++) {
ItemStack cloned = itemStack.clone();
cloned.setAmount(maxStackSize);
player.getWorld().dropItem(player.getLocation(), cloned);
}
int left = amount % maxStackSize;
if (left != 0) {
ItemStack cloned = itemStack.clone();
cloned.setAmount(left);
player.getWorld().dropItem(player.getLocation(), cloned);
}
}
return actualAmount;
}
public static String toBase64(ItemStack itemStack) {
if (itemStack == null || itemStack.getType() == Material.AIR)
return "";
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
try (BukkitObjectOutputStream dataOutput = new BukkitObjectOutputStream(outputStream)) {
dataOutput.writeObject(itemStack);
byte[] byteArr = outputStream.toByteArray();
dataOutput.close();
outputStream.close();
return Base64Coder.encodeLines(byteArr);
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
public static ItemStack fromBase64(String base64) {
if (base64 == null || base64.equals(""))
return new ItemStack(Material.AIR);
ByteArrayInputStream inputStream;
try {
inputStream = new ByteArrayInputStream(Base64Coder.decodeLines(base64));
} catch (IllegalArgumentException e) {
return new ItemStack(Material.AIR);
}
ItemStack stack = null;
try (BukkitObjectInputStream dataInput = new BukkitObjectInputStream(inputStream)) {
stack = (ItemStack) dataInput.readObject();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
return stack;
}
public static ItemStack removeOwner(ItemStack itemStack) {
if (itemStack == null || itemStack.getType() == Material.AIR) return itemStack;
NBTItem nbtItem = new NBTItem(itemStack);
if (nbtItem.hasTag("owner")) {
nbtItem.removeKey("owner");
return nbtItem.getItem();
}
return itemStack;
}
/**
* @return the amount of items that can't be put in the inventory
*/
public static int putLootsToBag(Inventory inventory, ItemStack itemStack, int amount) {
itemStack = removeOwner(itemStack.clone());
ItemMeta meta = itemStack.getItemMeta();
int maxStackSize = itemStack.getMaxStackSize();
for (ItemStack other : inventory.getStorageContents()) {
if (other != null) {
if (other.getType() == itemStack.getType() && other.getItemMeta().equals(meta)) {
if (other.getAmount() < maxStackSize) {
int delta = maxStackSize - other.getAmount();
if (amount > delta) {
other.setAmount(maxStackSize);
amount -= delta;
} else {
other.setAmount(amount + other.getAmount());
return 0;
}
}
}
}
}
if (amount > 0) {
for (ItemStack other : inventory.getStorageContents()) {
if (other == null) {
if (amount > maxStackSize) {
amount -= maxStackSize;
ItemStack cloned = itemStack.clone();
cloned.setAmount(maxStackSize);
inventory.addItem(cloned);
} else {
ItemStack cloned = itemStack.clone();
cloned.setAmount(amount);
inventory.addItem(cloned);
return 0;
}
}
}
}
return amount;
}
}

View File

@@ -1,6 +1,4 @@
# Developer: @Xiao-MoMi
# Wiki: https://mo-mi.gitbook.io/xiaomomi-plugins/
config-version: '32'
config-version: '${config_version}'
# Debug
debug: false

View File

@@ -1,3 +1,5 @@
config-version: '${config_version}'
# file:
# JSON
# YAML

View File

@@ -1,3 +1,5 @@
config-version: '${config_version}'
enable: true
# Container title

View File

@@ -1,125 +0,0 @@
# Don't change this
config-version: '31'
messages:
prefix: '<gradient:#0070B3:#A0EACF>[CustomFishing] </gradient>'
reload: '<white>Reloaded. Took <green>{time}ms.'
item-not-exist: 'Item not found.'
give-item: 'Successfully given player {player} {amount}x {item}.'
get-item: 'Successfully got {amount}x {item}.'
possible-loots: 'Possible loots here: '
split-char: ', '
competition-not-exist: 'Competition {id} does not exist.'
no-competition-ongoing: "There's no competition ongoing."
stop-competition: 'Stopped the current competition.'
end-competition: 'Ended the current competition.'
no-score: 'No Score'
no-player: 'No Player'
no-rank: 'No Rank'
goal-catch-amount: 'Fish count caught'
goal-max-size: 'Largest fish caught'
goal-total-size: 'Total length of fish caught'
goal-total-score: 'Cumulative score of fish caught'
unsafe-modification: "Cannot modify a player's fishing bag if they're active on another linked server."
never-played: "The player hasn't joined the server before. Can't modify a nonexistent player's fishing bag."
data-not-loaded: "<red>Data hasn't loaded. Please re-enter the server. If issues persist, reach out to the server admin."
open-market-gui: "Successfully opened the market gui for {player}"
open-fishing-bag: "Successfully opened the fishing bag for {player}"
format-day: 'd'
format-hour: 'h'
format-minute: 'm'
format-second: 's'
gui:
search: "Search"
select-file: 'Select file'
select-item: "Select item"
dupe-invalid-key: "<red>● Duplicated or invalid key"
new-value: "New value: "
temp-new-key: 'New key'
set-new-key: "Set new key"
edit-key: 'Edit {0}'
delete-property: "<#00CED1>● Delete property"
click-confirm: "<#00FF7F> -> Click to confirm"
invalid-number: "<red>● Invalid number"
illegal-format: "<red>● Illegal format"
scroll-up: '<gray>● Scroll up'
scroll-down: '<gray>● Scroll down'
cannot-scroll-up: "<red>You've reached the top"
cannot-scroll-down: "<red>You can't scroll further down"
next-page: '<gray>● Next Page'
goto-next-page: '<gray>Go to page <yellow>{0} <gray>/ <yellow>{1}'
cannot-goto-next-page: '<red>There are no more pages'
previous-page: '<gray>● Previous page'
goto-previous-page: '<gray>Go to page <yellow>{0} <gray>/ <yellow>{1}'
cannot-goto-previous-page: "<red>You can't go further back"
back-to-parent-page: "<#FF8C00>Back to parent page"
back-to-parent-folder: "<#FF8C00>Back to parent folder"
current-value: "<gray>Current value: <white>"
click-to-toggle: "<#00FF7F> -> Click to toggle"
left-click-edit: "<#00FF7F> -> Left click to edit"
right-click-reset: "<#FF6347> -> Right click to reset"
right-click-delete: "<#FF6347> -> Right click to delete"
right-click-cancel: "<#00CED1> -> Right click to cancel"
loot-show-in-finder: "<#5F9EA0>● Show In Fish Finder"
loot-score: "<#FF1493>● Score"
loot-nick: "<#00FF00>● Nick"
loot-instant-game: "<#7B68EE>● Instant Game"
loot-disable-statistics: "<#CD853F>● Disable Statistics"
loot-disable-game: "<#8B4513>● Disable Game"
item-amount: "<#1E90FF>● Amount"
item-custom-model-data: "<#FFC0CB>● Custom Model Data"
item-display-name: "<#FAFAD2>● Display Name"
item-custom-durability: "<#1E90FF>● Custom Durability"
item-enchantment: "<#8A2BE2>● Enchantment"
item-head64: "<#2E8B57>● Head64"
item-item-flag: "<#E6E6FA>● Item Flag"
item-lore: "<#FA8072>● Lore"
item-material: "<#FF00FF>● Material"
item-nbt: "<#FA8072>● NBT"
item-prevent-grab: "<#FF4500>● Prevent Grabbing"
item-price: "<#FFD700>● Price"
item-price-base: "<gray> - base: <white>"
item-price-bonus: "<gray> - bonus: <white>"
item-random-durability: "<#FFFF00>● Random Durability"
item-size: "<#FFF0F5>● Size"
item-stackable: "<#9370DB>● Stackable"
item-stored-enchantment: "<#9370DB>● Stored Enchantment"
item-tag: "<#2E8B57>● Tag"
item-unbreakable: "<#C0C0C0>● Unbreakable"
page-amount-title: "Edit Amount"
page-model-data-title: "Edit CustomModelData"
page-display-name-title: "Edit display name"
page-new-display-name: "New name"
page-custom-durability-title: "Edit custom durability"
page-stored-enchantment-title: "Edit stored enchantment"
page-enchantment-title: "Edit enchantment"
page-select-one-enchantment: "Select one enchantment"
page-add-new-enchantment: "<green>[+] <gray>Add a new enchantment"
page-item-flag-title: "Edit item flag"
page-lore-title: "Edit lore"
page-add-new-lore: "<green>[+] <gray>Add a new line"
page-select-one-lore: "Select one line"
page-material-title: "Edit Material"
page-nbt-compound-key-title: "Edit compound key"
page-nbt-list-key-title: "Edit list key"
page-nbt-key-title: "Edit key"
page-nbt-invalid-key: "<red>Invaild key"
page-nbt-add-new-compound: "<green>[+] <gray>Add a new compound"
page-nbt-add-new-list: "<green>[+] <gray>Add a new list"
page-nbt-add-new-value: "<green>[+] <gray>Add a new value"
page-add-new-key: "<green>[+] <gray>Add a new key"
page-nbt-preview: "<green>● NBT Preview"
page-nbt-back-to-compound: "<gray>Back to parent compound"
page-nbt-set-value-title: "Set value"
page-nbt-edit-title: "Edit NBT"
page-nick-title: "Edit nick"
page-new-nick: "New nick"
page-price-title: "Edit price"
page-base-price: "Base"
page-base-bonus: "Bonus"
page-score-title: "Edit score"
page-size-title: "Edit size"
page-size-min: "Minimum"
page-size-max: "Maximum"
page-size-max-no-less-min: "<red>● Max must be no less than min"

View File

@@ -1,125 +0,0 @@
# Don't change this
config-version: '31'
messages:
prefix: '<gradient:#0070B3:#A0EACF>[CustomFishing] </gradient>'
reload: '<white>Recargado! Tardó <green>{time}ms.'
item-not-exist: 'Item no encontrado.'
give-item: 'Se ha entregado {amount}x {item} al jugador {player}.'
get-item: 'Se ha recibido {amount}x {item}.'
possible-loots: 'Posibles recompensas: '
split-char: ', '
competition-not-exist: 'La Competición {id} no existe.'
no-competition-ongoing: "No hay una competencia activa."
stop-competition: 'Se ha detenido la competición.'
end-competition: 'Ha finalizado la competición.'
no-score: 'Sin puntaje'
no-player: 'Sin jugador'
no-rank: 'Sin rango'
goal-catch-amount: 'Peces atrapados'
goal-max-size: 'Pez más grande capturado'
goal-total-size: 'Longitud total de peces capturados'
goal-total-score: 'Puntaje acumulado por peces capturados'
unsafe-modification: "No se puede modificar la bolsa de pesca de un jugador si sigue activo en otro servidor vinculado."
never-played: "Este jugador nunca se ha unido al servidor. No puedes modificar la bolsa de pesca de un jugador inexistente."
data-not-loaded: "<red>No se pudo cargar la información. Por favor, vuelve a ingresar al servidor. Si el problema persiste, contacta a un administrador."
open-market-gui: "Se ha abierto la interfaz para {player}"
open-fishing-bag: "Se ha abierto la bolsa de pesca de {player}"
format-day: 'd'
format-hour: 'h'
format-minute: 'm'
format-second: 's'
gui:
search: "Buscar"
select-file: 'Seleccionar archivo'
select-item: "Seleccionar item"
dupe-invalid-key: "<red>● ID inválida o duplicada"
new-value: "Nuevo valor: "
temp-new-key: 'Nueva ID'
set-new-key: "Definir nueva ID"
edit-key: 'Editar {0}'
delete-property: "<#00CED1>● Eliminar propiedad"
click-confirm: "<#00FF7F> -> Click para confirmar"
invalid-number: "<red>● Número inválido"
illegal-format: "<red>● Formato inválido"
scroll-up: '<gray>● Arriba'
scroll-down: '<gray>● Abajo'
cannot-scroll-up: "<red>Estás en el límite superior"
cannot-scroll-down: "<red>Estás en el límite inferior"
next-page: '<gray>● Siguiente Página'
goto-next-page: '<gray>Ir a la página <yellow>{0} <gray>/ <yellow>{1}'
cannot-goto-next-page: '<red>No hay más páginas'
previous-page: '<gray>● Página anterior'
goto-previous-page: '<gray>Ir a la página <yellow>{0} <gray>/ <yellow>{1}'
cannot-goto-previous-page: "<red>No hay más páginas atrás"
back-to-parent-page: "<#FF8C00>Volver al menú anterior"
back-to-parent-folder: "<#FF8C00>Volver a la carpeta anterior"
current-value: "<gray>Valor actual: <white>"
click-to-toggle: "<#00FF7F> -> Click para cambiar"
left-click-edit: "<#00FF7F> -> Click izquierdo para editar"
right-click-reset: "<#FF6347> -> Click derecho para restablecer"
right-click-delete: "<#FF6347> -> Click derecho para eliminar"
right-click-cancel: "<#00CED1> -> Click derecho para cancelar"
loot-show-in-finder: "<#5F9EA0>● Mostar en el rastreador de peces"
loot-score: "<#FF1493>● Puntaje"
loot-nick: "<#00FF00>● Apodo"
loot-instant-game: "<#7B68EE>● Juego Instantáneo"
loot-disable-statistics: "<#CD853F>● Deshabilitar Estadísticas"
loot-disable-game: "<#8B4513>● Deshabilitar Juego"
item-amount: "<#1E90FF>● Cantidad"
item-custom-model-data: "<#FFC0CB>● Custom Model Data"
item-display-name: "<#FAFAD2>● Nombre a mostrar"
item-custom-durability: "<#1E90FF>● Durabilidad"
item-enchantment: "<#8A2BE2>● Encantamiento"
item-head64: "<#2E8B57>● Head64"
item-item-flag: "<#E6E6FA>● Item Flag"
item-lore: "<#FA8072>● Descripción"
item-material: "<#FF00FF>● Material"
item-nbt: "<#FA8072>● NBT"
item-prevent-grab: "<#FF4500>● Evitar recoger item"
item-price: "<#FFD700>● Precio"
item-price-base: "<gray> - base: <white>"
item-price-bonus: "<gray> - bonus: <white>"
item-random-durability: "<#FFFF00>● Durabilidad Aleatoria"
item-size: "<#FFF0F5>● Tamaño"
item-stackable: "<#9370DB>● Acumulable"
item-stored-enchantment: "<#9370DB>● Encantamiento Almacenado"
item-tag: "<#2E8B57>● Etiqueta"
item-unbreakable: "<#C0C0C0>● Irrompible"
page-amount-title: "Editar Cantidad"
page-model-data-title: "Editar CustomModelData"
page-display-name-title: "Editar nombre a mostrar"
page-new-display-name: "Nuevo nombre"
page-custom-durability-title: "Edit durabilidad"
page-stored-enchantment-title: "Edit encantamiento almacenado"
page-enchantment-title: "Editar enchantmentamiento"
page-select-one-enchantment: "Seleccionar un encantamiento"
page-add-new-enchantment: "<green>[+] <gray>Añadir un encantamiento"
page-item-flag-title: "Editar item flag"
page-lore-title: "Editar descripción"
page-add-new-lore: "<green>[+] <gray>Añadir nueva línea"
page-select-one-lore: "Seleccionar una línea"
page-material-title: "Editar Material"
page-nbt-compound-key-title: "Editar ID de NBT compuesta"
page-nbt-list-key-title: "Editar lista de IDs"
page-nbt-key-title: "Editar ID"
page-nbt-invalid-key: "<red>ID inválida"
page-nbt-add-new-compound: "<green>[+] <gray>Añadir nueva NBT compuesta"
page-nbt-add-new-list: "<green>[+] <gray>Añadir nueva lista"
page-nbt-add-new-value: "<green>[+] <gray>Añadir nuevo valor"
page-add-new-key: "<green>[+] <gray>Añadir nueva ID"
page-nbt-preview: "<green>● Vista previa de NBT"
page-nbt-back-to-compound: "<gray>Volver al compuesto padre"
page-nbt-set-value-title: "Definir nuevo valor"
page-nbt-edit-title: "Editar NBT"
page-nick-title: "Editar apodo"
page-new-nick: "Nuevo apodo"
page-price-title: "Editar precio"
page-base-price: "Base"
page-base-bonus: "Bonus"
page-score-title: "Editar puntuación"
page-size-title: "Editar tamaño"
page-size-min: "Mínimo"
page-size-max: "Máximo"
page-size-max-no-less-min: "<red>● El valor máximo no puede ser inferior al mínimo"

View File

@@ -1,125 +0,0 @@
# Don't change this
config-version: '30'
messages:
prefix: '<gradient:#0070B3:#A0EACF>[CustomFishing] </gradient>'
reload: '<white>Rechargé. A pris <green>{time}ms.</green>'
item-not-exist: 'Objet non trouvé.'
give-item: 'Joueur {player} a reçu avec succès {amount}x {item}.'
get-item: 'A obtenu avec succès {amount}x {item}.'
possible-loots: 'Butins possibles ici : '
split-char: ', '
competition-not-exist: "La compétition {id} n'existe pas."
no-competition-ongoing: 'Aucune compétition en cours.'
stop-competition: 'Compétition actuelle arrêtée.'
end-competition: 'Compétition actuelle terminée.'
no-score: 'Pas de score'
no-player: 'Pas de joueur'
no-rank: 'Pas de classement'
goal-catch-amount: 'Nombre de poissons attrapés'
goal-max-size: 'Plus gros poisson attrapé'
goal-total-size: 'Longueur totale des poissons attrapés'
goal-total-score: 'Score cumulatif des poissons attrapés'
unsafe-modification: "Impossible de modifier le sac de pêche d'un joueur s'il est actif sur un autre serveur lié."
never-played: "Le joueur n'a jamais rejoint le serveur auparavant. Impossible de modifier le sac de pêche d'un joueur inexistant."
data-not-loaded: "<red>Les données n'ont pas été chargées. Veuillez réessayer de rejoindre le serveur. Si les problèmes persistent, contactez l'administrateur du serveur."
open-market-gui: "L'interface du marché a été ouverte avec succès pour {player}."
open-fishing-bag: "Le sac de pêche de {player} a été ouvert avec succès."
format-day: 'j'
format-hour: 'h'
format-minute: 'm'
format-second: 's'
gui:
search: "Rechercher"
select-file: "Sélectionner un fichier"
select-item: "Sélectionner un élément"
dupe-invalid-key: "<red>● Clé en double ou invalide"
new-value: "Nouvelle valeur : "
temp-new-key: "Nouvelle clé"
set-new-key: "Définir une nouvelle clé"
edit-key: "Modifier {0}"
delete-property: "<#00CED1>● Supprimer la propriété"
click-confirm: "<#00FF7F> -> Cliquez pour confirmer"
invalid-number: "<red>● Nombre invalide"
illegal-format: "<red>● Format illégal"
scroll-up: "<gray>● Faire défiler vers le haut"
scroll-down: "<gray>● Faire défiler vers le bas"
cannot-scroll-up: "<red>Vous avez atteint le haut"
cannot-scroll-down: "<red>Vous ne pouvez pas faire défiler plus bas"
next-page: "<gray>● Page suivante"
goto-next-page: "<gray>Aller à la page <yellow>{0} <gray>/ <yellow>{1}"
cannot-goto-next-page: "<red>Il n'y a plus de pages"
previous-page: "<gray>● Page précédente"
goto-previous-page: "<gray>Aller à la page <yellow>{0} <gray>/ <yellow>{1}"
cannot-goto-previous-page: "<red>Vous ne pouvez pas revenir en arrière"
back-to-parent-page: "<#FF8C00>Retour à la page parente"
back-to-parent-folder: "<#FF8C00>Retour au dossier parent"
current-value: "<gray>Valeur actuelle : <white>"
click-to-toggle: "<#00FF7F> -> Cliquez pour basculer"
left-click-edit: "<#00FF7F> -> Cliquez gauche pour modifier"
right-click-reset: "<#FF6347> -> Cliquez droit pour réinitialiser"
right-click-delete: "<#FF6347> -> Cliquez droit pour supprimer"
right-click-cancel: "<#00CED1> -> Cliquez droit pour annuler"
loot-show-in-finder: "<#5F9EA0>● Afficher dans le repère de poisson"
loot-score: "<#FF1493>● Score"
loot-nick: "<#00FF00>● Surnom"
loot-instant-game: "<#7B68EE>● Jeu instantané"
loot-disable-statistics: "<#CD853F>● Désactiver les statistiques"
loot-disable-game: "<#8B4513>● Désactiver le jeu"
item-amount: "<#1E90FF>● Quantité"
item-custom-model-data: "<#FFC0CB>● Données de modèle personnalisées"
item-display-name: "<#FAFAD2>● Nom affiché"
item-custom-durability: "<#1E90FF>● Durabilité personnalisée"
item-enchantment: "<#8A2BE2>● Enchantement"
item-head64: "<#2E8B57>● Tête64"
item-item-flag: "<#E6E6FA>● Drapeau d'élément"
item-lore: "<#FA8072>● Légende"
item-material: "<#FF00FF>● Matériau"
item-nbt: "<#FA8072>● NBT"
item-prevent-grab: "<#FF4500>● Empêcher la saisie"
item-price: "<#FFD700>● Prix"
item-price-base: "<gray> - de base : <white>"
item-price-bonus: "<gray> - bonus : <white>"
item-random-durability: "<#FFFF00>● Durabilité aléatoire"
item-size: "<#FFF0F5>● Taille"
item-stackable: "<#9370DB>● Empilable"
item-stored-enchantment: "<#9370DB>● Enchantement stocké"
item-tag: "<#2E8B57>● Étiquette"
item-unbreakable: "<#C0C0C0>● Incassable"
page-amount-title: "Modifier la quantité"
page-model-data-title: "Modifier CustomModelData"
page-display-name-title: "Modifier le nom affiché"
page-new-display-name: "Nouveau nom"
page-custom-durability-title: "Modifier la durabilité personnalisée"
page-stored-enchantment-title: "Modifier l'enchantement stocké"
page-enchantment-title: "Modifier l'enchantement"
page-select-one-enchantment: "Sélectionner un enchantement"
page-add-new-enchantment: "<green>[+] <gray>Ajouter un nouvel enchantement"
page-item-flag-title: "Modifier le drapeau d'élément"
page-lore-title: "Modifier la légende"
page-add-new-lore: "<green>[+] <gray>Ajouter une nouvelle ligne"
page-select-one-lore: "Sélectionner une ligne"
page-material-title: "Modifier le matériau"
page-nbt-compound-key-title: "Modifier la clé composée"
page-nbt-list-key-title: "Modifier la clé de liste"
page-nbt-key-title: "Modifier la clé"
page-nbt-invalid-key: "<red>Clé invalide"
page-nbt-add-new-compound: "<green>[+] <gray>Ajouter une nouvelle composante"
page-nbt-add-new-list: "<green>[+] <gray>Ajouter une nouvelle liste"
page-nbt-add-new-value: "<green>[+] <gray>Ajouter une nouvelle valeur"
page-add-new-key: "<green>[+] <gray>Ajouter une nouvelle clé"
page-nbt-preview: "<green>● Aperçu NBT"
page-nbt-back-to-compound: "<gray>Retour à la composante parente"
page-nbt-set-value-title: "Définir la valeur"
page-nbt-edit-title: "Modifier NBT"
page-nick-title: "Modifier le surnom"
page-new-nick: "Nouveau surnom"
page-price-title: "Modifier le prix"
page-base-price: "De base"
page-base-bonus: "Bonus"
page-score-title: "Modifier le score"
page-size-title: "Modifier la taille"
page-size-min: "Minimum"
page-size-max: "Maximum"
page-size-max-no-less-min: "<red>Le maximum ne doit pas être inférieur au minimum"

View File

@@ -1,126 +0,0 @@
# Don't change this
config-version: '30'
messages:
prefix: '<gradient:#0070B3:#A0EACF>[CustomFishing] </gradient>'
reload: '<white>Újratöltve. Időtartam: <green>{time}ms.'
item-not-exist: 'Tétel nem található.'
give-item: 'Sikeresen adva {player} játékosnak {amount}x {item}.'
get-item: 'Sikeresen megszerezve {amount}x {item}.'
possible-loots: 'Lehetséges kapások itt: '
split-char: ', '
competition-not-exist: 'A(z) {id} verseny nem létezik.'
no-competition-ongoing: "Nincs folyamatban lévő verseny."
stop-competition: 'Leállítottad a jelenlegi versenyt.'
end-competition: 'Befejezted a jelenlegi versenyt.'
no-score: 'Nincs pontszám'
no-player: 'Nincs játékos'
no-rank: 'Nincs rang'
goal-catch-amount: 'Kifogott halak száma'
goal-max-size: 'Legnagyobb kifogott hal'
goal-total-size: 'Összes kifogott hal hossza'
goal-total-score: 'Kifogott halak összpontszáma'
unsafe-modification: "Nem lehet módosítani egy játékos horgász táskáját, ha aktív egy másik szerveren."
never-played: "A játékos még nem csatlakozott a szerverhez. Nem lehet módosítani egy nem létező játékos horgász táskáját."
data-not-loaded: "<red>Az adatok nem lettek betöltve. Kérjük, csatlakozz újra a szerverhez. Ha a probléma továbbra is fennáll, fordulj a szerveradminisztrátorhoz."
open-market-gui: "A piac menü sikeresen meg lett nyitva {player} részére"
open-fishing-bag: "A horgász táska sikeresen meg lett nyitva {player} részére"
format-day: 'n'
format-hour: 'ó'
format-minute: 'p'
format-second: 'mp'
# We're looking for a translator :D
gui:
search: "Search"
select-file: 'Select file'
select-item: "Select item"
dupe-invalid-key: "<red>● Duplicated or invalid key"
new-value: "New value: "
temp-new-key: 'New key'
set-new-key: "Set new key"
edit-key: 'Edit {0}'
delete-property: "<#00CED1>● Delete property"
click-confirm: "<#00FF7F> -> Click to confirm"
invalid-number: "<red>● Invalid number"
illegal-format: "<red>● Illegal format"
scroll-up: '<gray>● Scroll up'
scroll-down: '<gray>● Scroll down'
cannot-scroll-up: "<red>You've reached the top"
cannot-scroll-down: "<red>You can't scroll further down"
next-page: '<gray>● Next Page'
goto-next-page: '<gray>Go to page <yellow>{0} <gray>/ <yellow>{1}'
cannot-goto-next-page: '<red>There are no more pages'
previous-page: '<gray>● Previous page'
goto-previous-page: '<gray>Go to page <yellow>{0} <gray>/ <yellow>{1}'
cannot-goto-previous-page: "<red>You can't go further back"
back-to-parent-page: "<#FF8C00>Back to parent page"
back-to-parent-folder: "<#FF8C00>Back to parent folder"
current-value: "<gray>Current value: <white>"
click-to-toggle: "<#00FF7F> -> Click to toggle"
left-click-edit: "<#00FF7F> -> Left click to edit"
right-click-reset: "<#FF6347> -> Right click to reset"
right-click-delete: "<#FF6347> -> Right click to delete"
right-click-cancel: "<#00CED1> -> Right click to cancel"
loot-show-in-finder: "<#5F9EA0>● Show In Fish Finder"
loot-score: "<#FF1493>● Score"
loot-nick: "<#00FF00>● Nick"
loot-instant-game: "<#7B68EE>● Instant Game"
loot-disable-statistics: "<#CD853F>● Disable Statistics"
loot-disable-game: "<#8B4513>● Disable Game"
item-amount: "<#1E90FF>● Amount"
item-custom-model-data: "<#FFC0CB>● Custom Model Data"
item-display-name: "<#FAFAD2>● Display Name"
item-custom-durability: "<#1E90FF>● Custom Durability"
item-enchantment: "<#8A2BE2>● Enchantment"
item-head64: "<#2E8B57>● Head64"
item-item-flag: "<#E6E6FA>● Item Flag"
item-lore: "<#FA8072>● Lore"
item-material: "<#FF00FF>● Material"
item-nbt: "<#FA8072>● NBT"
item-prevent-grab: "<#FF4500>● Prevent Grabbing"
item-price: "<#FFD700>● Price"
item-price-base: "<gray> - base: <white>"
item-price-bonus: "<gray> - bonus: <white>"
item-random-durability: "<#FFFF00>● Random Durability"
item-size: "<#FFF0F5>● Size"
item-stackable: "<#9370DB>● Stackable"
item-stored-enchantment: "<#9370DB>● Stored Enchantment"
item-tag: "<#2E8B57>● Tag"
item-unbreakable: "<#C0C0C0>● Unbreakable"
page-amount-title: "Edit Amount"
page-model-data-title: "Edit CustomModelData"
page-display-name-title: "Edit display name"
page-new-display-name: "New name"
page-custom-durability-title: "Edit custom durability"
page-stored-enchantment-title: "Edit stored enchantment"
page-enchantment-title: "Edit enchantment"
page-select-one-enchantment: "Select one enchantment"
page-add-new-enchantment: "<green>[+] <gray>Add a new enchantment"
page-item-flag-title: "Edit item flag"
page-lore-title: "Edit lore"
page-add-new-lore: "<green>[+] <gray>Add a new line"
page-select-one-lore: "Select one line"
page-material-title: "Edit Material"
page-nbt-compound-key-title: "Edit compound key"
page-nbt-list-key-title: "Edit list key"
page-nbt-key-title: "Edit key"
page-nbt-invalid-key: "<red>Invaild key"
page-nbt-add-new-compound: "<green>[+] <gray>Add a new compound"
page-nbt-add-new-list: "<green>[+] <gray>Add a new list"
page-nbt-add-new-value: "<green>[+] <gray>Add a new value"
page-add-new-key: "<green>[+] <gray>Add a new key"
page-nbt-preview: "<green>● NBT Preview"
page-nbt-back-to-compound: "<gray>Back to parent compound"
page-nbt-set-value-title: "Set value"
page-nbt-edit-title: "Edit NBT"
page-nick-title: "Edit nick"
page-new-nick: "New nick"
page-price-title: "Edit price"
page-base-price: "Base"
page-base-bonus: "Bonus"
page-score-title: "Edit score"
page-size-title: "Edit size"
page-size-min: "Minimum"
page-size-max: "Maximum"
page-size-max-no-less-min: "<red>● Max must be no less than min"

View File

@@ -1,125 +0,0 @@
# Don't change this
config-version: '31'
messages:
prefix: '<gradient:#0070B3:#A0EACF>[CustomFishing] </gradient>'
reload: '<white>重载完成. 耗时 <green>{time}ms.'
item-not-exist: '物品不存在.'
give-item: '给予玩家 {player} {amount}x {item}.'
get-item: '获得 {amount}x {item}.'
possible-loots: '可能的战利品: '
split-char: ', '
competition-not-exist: '比赛 {id} 不存在.'
no-competition-ongoing: "没有正在进行的比赛."
stop-competition: '停止了当前的比赛.'
end-competition: '结束了当前的比赛.'
no-score: '无比分'
no-player: '无选手'
no-rank: '无排名'
goal-catch-amount: '捕鱼总数'
goal-max-size: '最大尺寸'
goal-total-size: '捕鱼总尺寸'
goal-total-score: '捕鱼总分'
unsafe-modification: "你不能修改一个正在其他子服游玩的玩家钓鱼背包."
never-played: "此玩家从未玩过服务器."
data-not-loaded: "<red>数据未能正常加载. 请尝试切换子服或重进. 如果问题依然存在请联系服务器管理员."
open-market-gui: "为玩家 {player} 打开了市场"
open-fishing-bag: "为玩家 {player} 打开了钓鱼背包"
format-day: '天'
format-hour: '小时'
format-minute: '分'
format-second: '秒'
gui:
search: 搜索
select-file: 选择文件
select-item-to-edit: 选择要编辑的物品
dupe-invalid-key: <red>● 重复或无效的键
new-value: '新值: '
temp-new-key: '新键'
set-new-key: '设置新键'
edit-key: '修改 {0}'
delete-property: <#00CED1>● 删除属性
click-confirm: <#00FF7F> -> 点击确认
invalid-number: <red>● 无效的数字
illegal-format: <red>● 非法的格式
scroll-up: <gray>● 向上翻
scroll-down: <gray>● 向下翻
cannot-scroll-up: <red>你已经到顶了
cannot-scroll-down: <red>你不能再往下了
next-page: <gray>● 下一页
goto-next-page: <gray>前往 <yellow>{0} <gray>/ <yellow>{1}
cannot-goto-next-page: <red>没有更多页了
previous-page: <gray>● 上一页
goto-previous-page: <gray>前往 <yellow>{0} <gray>/ <yellow>{1}
cannot-goto-previous-page: <red>已经到达第一页了
back-to-parent-page: <#FF8C00>返回上一界面
back-to-parent-folder: <#FF8C00>返回父文件夹
current-value: '<gray>当前值: <white>'
click-to-toggle: <#00FF7F> -> 点击切换
left-click-edit: <#00FF7F> -> 左键编辑
right-click-reset: <#FF6347> -> 右键重置
right-click-delete: <#FF6347> -> 右键删除
right-click-cancel: <#00CED1> -> 右键取消
loot-show-in-finder: <#5F9EA0>● 在找鱼器中可见
loot-score: <#FF1493>● 比赛分数
loot-nick: <#00FF00>● 昵称
loot-instant-game: <#7B68EE>● 咬钩立即游戏
loot-disable-statistics: <#CD853F>● 禁用统计数据
loot-disable-game: <#8B4513>● 禁用游戏
item-amount: <#1E90FF>● 数量
item-custom-model-data: <#FFC0CB>● 自定义模型值
item-display-name: <#FAFAD2>● 名称
item-custom-durability: <#1E90FF>● 自定义耐久度
item-enchantment: <#8A2BE2>● 附魔
item-head64: <#2E8B57>● 头颅base64
item-item-flag: <#E6E6FA>● 物品标签
item-lore: <#FA8072>● 描述
item-material: <#FF00FF>● 材质
item-nbt: <#FA8072>● NBT
item-prevent-grab: <#FF4500>● 防止抢夺
item-price: <#FFD700>● 价格
item-price-base: '<gray> - 基础: <white>'
item-price-bonus: '<gray> - 尺寸增益: <white>'
item-random-durability: <#FFFF00>● 随机耐久
item-size: <#FFF0F5>● 尺寸
item-stackable: <#9370DB>● 是否可以堆叠
item-stored-enchantment: <#9370DB>● 存储附魔
item-tag: <#2E8B57>● 启用CustomFishing标签
item-unbreakable: <#C0C0C0>● 不可破坏
page-amount-title: 修改数量
page-model-data-title: 修改自定义模型值
page-display-name-title: 修改名称
page-new-display-name: 新名称
page-custom-durability-title: 修改自定义耐久度
page-stored-enchantment-title: 修改存储附魔
page-enchantment-title: 修改附魔
page-select-one-enchantment: 选择一个附魔
page-add-new-enchantment: <green>[+] <gray>新增一个附魔
page-item-flag-title: 修改物品标签
page-lore-title: 修改描述
page-add-new-lore: <green>[+] <gray>新增一行描述
page-select-one-lore: 选择一行描述
page-material-title: 修改材质
page-nbt-compound-key-title: 修改复合键名
page-nbt-list-key-title: 修改列表名
page-nbt-key-title: 修改键
page-nbt-invalid-key: <red>无效的键
page-nbt-add-new-compound: <green>[+] <gray>新增一个复合NBT
page-nbt-add-new-list: <green>[+] <gray>新增一个列表
page-nbt-add-new-value: <green>[+] <gray>新增一个值
page-add-new-key: <green>[+] <gray>新增一个键
page-nbt-preview: <green>● NBT 预览
page-nbt-back-to-compound: <gray>返回父复合NBT
page-nbt-set-value-title: 设置值
page-nbt-edit-title: 修改NBT
page-nick-title: 修改昵称
page-new-nick: 新昵称
page-price-title: 修改价格
page-base-price: 基础
page-base-bonus: 尺寸增益
page-score-title: 修改分数
page-size-title: 修改尺寸
page-size-min: 最小值
page-size-max: 最大值
page-size-max-no-less-min: <red>● 最大值必须大于最小值

View File

@@ -1,35 +0,0 @@
name: CustomFishing
version: '${version}'
main: net.momirealms.customfishing.CustomFishingPluginImpl
api-version: 1.17
authors: [ XiaoMoMi ]
folia-supported: true
depend:
- ProtocolLib
softdepend:
- Vault
- PlaceholderAPI
- RealisticSeasons
- ItemsAdder
- MythicMobs
- Oraxen
- MMOItems
- mcMMO
- AureliumSkills
- AuraSkills
- CustomCrops
- MMOCore
- EcoSkills
- BattlePass
- ClueScrolls
- BetonQuest
- AdvancedEnchantments
- EcoJobs
- Zaphkiel
permissions:
fishingbag.user:
default: true
fishingbag.collectloot:
default: false
customfishing.sellfish:
default: true

View File

@@ -0,0 +1,123 @@
# Don"t change this
config-version: "31"
command.prefix: "<gradient:#0070B3:#A0EACF>[CustomFishing] </gradient>"
command.reload.success: "<white>Reloaded. Took <green><arg:0></green>ms.</white>"
command.item.failure.not_exist: "<red>Item not exists</red>"
command.item.give.success: "Successfully given player <arg:0> <arg:1>x <arg:2>."
command.item.get.success: "Successfully got <arg:0>x <arg:1>."
command.fish_finder.possible_loots: "Possible loots here: "
command.fish_finder.no_loot: "No loot available"
command.fish_finder.split_char: ", "
command.competition.failure.not_exist: "Competition <arg:0> does not exist."
command.competition.failure.no_competition: "There's no competition ongoing."
command.competition.stop.success: "Stopped the current competition."
command.competition.end.success: "Ended the current competition."
command.bag.edit.failure.unsafe: "Cannot edit a player's fishing bag if they"re active on another linked server."
command.bag.edit.failure.never_played: 'The player hasn\'t joined the server before. Can't modify a nonexistent player"s fishing bag."
command.bag.open.success: "Successfully opened the fishing bag for <arg:0>"
command.data.failure.not_load: '<red>Data hasn't loaded. Please re-enter the server. If issues persist, reach out to the server admin.</red>"
command.market.open.success: "Successfully opened the market gui for <arg:0>"
competition.no_score: "No Score"
competition.no_player: "No Player"
competition.no_rank: "No Rank"
competition.goal.catch_amount: "Fish count caught"
competition.goal.max_size: "Largest fish caught"
competition.goal.total_score: "Cumulative score of fish caught"
competition.goal.total_size: "Total length of fish caught"
format.day: "d"
format.hour: "h"
format.minute: "m"
format.second: "s"
gui.search: "Search"
gui.select_file: "Select file"
gui.select_item: "Select item"
gui.invalid_key: "<red>● Duplicated or invalid key"
gui.new_value: "New value: "
gui.temp_new_key: "New key"
gui.set_new_key: "Set new key"
gui.edit_key: "Edit <arg:0>"
gui.delete_property: "<#00CED1>● Delete property"
gui.click_confirm: "<#00FF7F> -> Click to confirm"
gui.invalid_number: "<red>● Invalid number"
gui.illegal_format: "<red>● Illegal format"
gui.scroll_up: "<gray>● Scroll up"
gui.scroll_down: "<gray>● Scroll down"
gui.cannot_scroll_up: "<red>You"ve reached the top"
gui.cannot_scroll_down: "<red>You can"t scroll further down"
gui.next_page: "<gray>● Next Page"
gui.goto_next_page: "<gray>Go to page <yellow><arg:0> <gray>/ <yellow><arg:1>"
gui.cannot_goto_next_page: "<red>There are no more pages"
gui.previous_page: "<gray>● Previous page"
gui.goto_previous_page: "<gray>Go to page <yellow><arg:0> <gray>/ <yellow><arg:1>"
gui.cannot_goto_previous_page: "<red>You can"t go further back"
gui.back_to_parent_page: "<#FF8C00>Back to parent page"
gui.back_to_parent_folder: "<#FF8C00>Back to parent folder"
gui.current_value: "<gray>Current value: <white><arg:0>"
gui.click_to_toggle: "<#00FF7F> -> Click to toggle"
gui.left_click_edit: "<#00FF7F> -> Left click to edit"
gui.right_click_reset: "<#FF6347> -> Right click to reset"
gui.right_click_delete: "<#FF6347> -> Right click to delete"
gui.right_click_cancel: "<#00CED1> -> Right click to cancel"
gui.loot_show_in_finder: "<#5F9EA0>● Show In Fish Finder"
gui.loot_score: "<#FF1493>● Score"
gui.loot_nick: "<#00FF00>● Nick"
gui.loot_instant_game: "<#7B68EE>● Instant Game"
gui.loot_disable_statistics: "<#CD853F>● Disable Statistics"
gui.loot_disable_game: "<#8B4513>● Disable Game"
gui.item_amount: "<#1E90FF>● Amount"
gui.item_custom_model_data: "<#FFC0CB>● Custom Model Data"
gui.item_display_name: "<#FAFAD2>● Display Name"
gui.item_custom_durability: "<#1E90FF>● Custom Durability"
gui.item_enchantment: "<#8A2BE2>● Enchantment"
gui.item_head64: "<#2E8B57>● Head64"
gui.item_item_flag: "<#E6E6FA>● Item Flag"
gui.item_lore: "<#FA8072>● Lore"
gui.item_material: "<#FF00FF>● Material"
gui.item_nbt: "<#FA8072>● NBT"
gui.item_prevent_grab: "<#FF4500>● Prevent Grabbing"
gui.item_price: "<#FFD700>● Price"
gui.item_price_base: "<gray> - base: <white>"
gui.item_price_bonus: "<gray> - bonus: <white>"
gui.item_random_durability: "<#FFFF00>● Random Durability"
gui.item_size: "<#FFF0F5>● Size"
gui.item_stackable: "<#9370DB>● Stackable"
gui.item_stored_enchantment: "<#9370DB>● Stored Enchantment"
gui.item_tag: "<#2E8B57>● Tag"
gui.item_unbreakable: "<#C0C0C0>● Unbreakable"
gui.page_amount_title: "Edit Amount"
gui.page_model_data_title: "Edit CustomModelData"
gui.page_display_name_title: "Edit display name"
gui.page_new_display_name: "New name"
gui.page_custom_durability_title: "Edit custom durability"
gui.page_stored_enchantment_title: "Edit stored enchantment"
gui.page_enchantment_title: "Edit enchantment"
gui.page_select_one_enchantment: "Select one enchantment"
gui.page_add_new_enchantment: "<green>[+] <gray>Add a new enchantment"
gui.page_item_flag_title: "Edit item flag"
gui.page_lore_title: "Edit lore"
gui.page_add_new_lore: "<green>[+] <gray>Add a new line"
gui.page_select_one_lore: "Select one line"
gui.page_material_title: "Edit Material"
gui.page_nbt_compound_key_title: "Edit compound key"
gui.page_nbt_list_key_title: "Edit list key"
gui.page_nbt_key_title: "Edit key"
gui.page_nbt_invalid_key: "<red>Invaild key"
gui.page_nbt_add_new_compound: "<green>[+] <gray>Add a new compound"
gui.page_nbt_add_new_list: "<green>[+] <gray>Add a new list"
gui.page_nbt_add_new_value: "<green>[+] <gray>Add a new value"
gui.page_add_new_key: "<green>[+] <gray>Add a new key"
gui.page_nbt_preview: "<green>● NBT Preview"
gui.page_nbt_back_to_compound: "<gray>Back to parent compound"
gui.page_nbt_set_value_title: "Set value"
gui.page_nbt_edit_title: "Edit NBT"
gui.page_nick_title: "Edit nick"
gui.page_new_nick: "New nick"
gui.page_price_title: "Edit price"
gui.page_base_price: "Base"
gui.page_base_bonus: "Bonus"
gui.page_score_title: "Edit score"
gui.page_size_title: "Edit size"
gui.page_size_min: "Minimum"
gui.page_size_max: "Maximum"
gui.page_size_max_no_less_min: "<red>● Max must be no less than min</red>"