9
0
mirror of https://github.com/Xiao-MoMi/Custom-Fishing.git synced 2025-12-19 15:09:24 +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

@@ -35,10 +35,12 @@ import net.momirealms.customfishing.api.mechanic.misc.placeholder.PlaceholderMan
import net.momirealms.customfishing.api.mechanic.requirement.RequirementManager;
import net.momirealms.customfishing.api.mechanic.statistic.StatisticsManager;
import net.momirealms.customfishing.api.storage.StorageManager;
import net.momirealms.customfishing.common.dependency.DependencyManager;
import net.momirealms.customfishing.common.locale.TranslationManager;
import net.momirealms.customfishing.common.plugin.CustomFishingPlugin;
import net.momirealms.customfishing.common.plugin.feature.Reloadable;
import net.momirealms.customfishing.common.plugin.scheduler.AbstractJavaScheduler;
import net.momirealms.customfishing.common.sender.SenderFactory;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@@ -46,12 +48,10 @@ import org.bukkit.plugin.Plugin;
import java.io.File;
import static java.util.Objects.requireNonNull;
public abstract class BukkitCustomFishingPlugin implements CustomFishingPlugin {
public abstract class BukkitCustomFishingPlugin implements CustomFishingPlugin, Reloadable {
private static BukkitCustomFishingPlugin instance;
private final Plugin boostrap = requireNonNull(Bukkit.getPluginManager().getPlugin("CustomFishing"));
private final Plugin boostrap;
protected EventManager eventManager;
protected ConfigManager configManager;
@@ -73,13 +73,20 @@ public abstract class BukkitCustomFishingPlugin implements CustomFishingPlugin {
protected EffectManager effectManager;
protected HookManager hookManager;
protected BagManager bagManager;
protected DependencyManager dependencyManager;
protected TranslationManager translationManager;
protected boolean initialized = false;
public BukkitCustomFishingPlugin() {
public BukkitCustomFishingPlugin(Plugin boostrap) {
if (!boostrap.getName().equals("CustomFishing")) {
throw new IllegalArgumentException("CustomFishing plugin requires custom fishing plugin");
}
this.boostrap = boostrap;
instance = this;
}
public static BukkitCustomFishingPlugin getInstance() {
if (instance == null) {
if (instance == null || !instance.initialized) {
throw new IllegalArgumentException("Plugin not initialized");
}
return instance;
@@ -175,7 +182,15 @@ public abstract class BukkitCustomFishingPlugin implements CustomFishingPlugin {
return boostrap;
}
public void reload() {
@Override
public DependencyManager getDependencyManager() {
return dependencyManager;
}
@Override
public TranslationManager getTranslationManager() {
return translationManager;
}
public abstract void enable();
}

View File

@@ -17,8 +17,8 @@
package net.momirealms.customfishing.api.event;
import net.momirealms.customfishing.api.mechanic.condition.FishingPreparation;
import net.momirealms.customfishing.api.mechanic.effect.Effect;
import net.momirealms.customfishing.api.mechanic.fishing.FishingPreparation;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.player.PlayerEvent;

View File

@@ -17,6 +17,7 @@
package net.momirealms.customfishing.api.integration;
import net.momirealms.customfishing.common.plugin.feature.Reloadable;
import net.momirealms.customfishing.common.util.Pair;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
@@ -29,7 +30,7 @@ import java.util.List;
* This allows for the registration and retrieval of various types of providers
* such as Leveler, Enchantment, and Season providers.
*/
public interface IntegrationManager {
public interface IntegrationManager extends Reloadable {
/**
* Registers a LevelerProvider.

View File

@@ -19,6 +19,7 @@ package net.momirealms.customfishing.api.mechanic.action;
import dev.dejvokep.boostedyaml.block.implementation.Section;
import net.momirealms.customfishing.api.mechanic.context.Context;
import net.momirealms.customfishing.common.plugin.feature.Reloadable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -29,7 +30,7 @@ import java.util.*;
*
* @param <T> the type of the context in which the actions are triggered.
*/
public interface ActionManager<T> {
public interface ActionManager<T> extends Reloadable {
/**
* Registers a custom action type with its corresponding factory.

View File

@@ -18,7 +18,9 @@
package net.momirealms.customfishing.api.mechanic.competition;
import net.kyori.adventure.util.Index;
import net.momirealms.customfishing.common.locale.StandardLocales;
import net.momirealms.customfishing.common.util.RandomUtils;
import org.apache.logging.log4j.util.Supplier;
import org.apache.logging.log4j.util.TriConsumer;
import org.bukkit.entity.Player;
@@ -26,11 +28,13 @@ public final class CompetitionGoal {
public static final CompetitionGoal CATCH_AMOUNT = new CompetitionGoal(
"catch_amount",
((rankingProvider, player, score) -> rankingProvider.refreshData(player, 1))
((rankingProvider, player, score) -> rankingProvider.refreshData(player, 1)),
() -> StandardLocales.GOAL_CATCH_AMOUNT
);
public static final CompetitionGoal TOTAL_SCORE = new CompetitionGoal(
"total_score",
(RankingProvider::refreshData)
(RankingProvider::refreshData),
() -> StandardLocales.GOAL_TOTAL_SCORE
);
public static final CompetitionGoal MAX_SIZE = new CompetitionGoal(
"max_size",
@@ -38,15 +42,18 @@ public final class CompetitionGoal {
if (rankingProvider.getPlayerScore(player) < score) {
rankingProvider.setData(player, score);
}
})
}),
() -> StandardLocales.GOAL_MAX_SIZE
);
public static final CompetitionGoal TOTAL_SIZE = new CompetitionGoal(
"total_size",
(RankingProvider::refreshData)
(RankingProvider::refreshData),
() -> StandardLocales.GOAL_TOTAL_SIZE
);
public static final CompetitionGoal RANDOM = new CompetitionGoal(
"random",
(rankingProvider, player, score) -> {}
(rankingProvider, player, score) -> {},
() -> "random"
);
private static final CompetitionGoal[] values = new CompetitionGoal[] {
@@ -84,10 +91,12 @@ public final class CompetitionGoal {
private final String key;
private final TriConsumer<RankingProvider, String, Double> scoreConsumer;
private final Supplier<String> nameSupplier;
private CompetitionGoal(String key, TriConsumer<RankingProvider, String, Double> scoreConsumer) {
private CompetitionGoal(String key, TriConsumer<RankingProvider, String, Double> scoreConsumer, Supplier<String> nameSupplier) {
this.key = key;
this.scoreConsumer = scoreConsumer;
this.nameSupplier = nameSupplier;
}
/**
@@ -105,6 +114,6 @@ public final class CompetitionGoal {
@Override
public String toString() {
return super.toString();
return nameSupplier.get();
}
}

View File

@@ -17,9 +17,10 @@
package net.momirealms.customfishing.api.mechanic.competition;
import net.momirealms.customfishing.common.plugin.feature.Reloadable;
import org.jetbrains.annotations.Nullable;
public interface CompetitionManager {
public interface CompetitionManager extends Reloadable {
boolean startCompetition(String competition, boolean force, @Nullable String serverGroup);

View File

@@ -89,6 +89,15 @@ public abstract class ConfigManager implements ConfigLoader, Reloadable {
}
public static String bagTitle() {
return null;
}
public static boolean metrics() {
return true;
}
public static boolean checkUpdate() {
return true;
}
public void registerLootParser(Function<Object, Consumer<Loot.Builder>> function, String... nodes) {

View File

@@ -42,14 +42,14 @@ public interface EntityConfig {
*
* @return the horizontal vector value as a double
*/
MathValue<Player> getHorizontalVector();
MathValue<Player> horizontalVector();
/**
* Retrieves the vertical vector value for the entity.
*
* @return the vertical vector value as a double
*/
MathValue<Player> getVerticalVector();
MathValue<Player> verticalVector();
/**
* Retrieves the unique identifier for the entity.
@@ -57,7 +57,7 @@ public interface EntityConfig {
* @return the entity ID as a non-null String
*/
@NotNull
String getEntityID();
String entityID();
/**
* Retrieves a map of properties associated with the entity.
@@ -65,7 +65,7 @@ public interface EntityConfig {
* @return a non-null map where keys are property names and values are property values
*/
@NotNull
Map<String, Object> getPropertyMap();
Map<String, Object> propertyMap();
/**
* Creates a new Builder instance for constructing an EntityConfig.

View File

@@ -45,24 +45,24 @@ public class EntityConfigImpl implements EntityConfig {
}
@Override
public MathValue<Player> getHorizontalVector() {
public MathValue<Player> horizontalVector() {
return horizontalVector;
}
@Override
public MathValue<Player> getVerticalVector() {
public MathValue<Player> verticalVector() {
return verticalVector;
}
@NotNull
@Override
public String getEntityID() {
public String entityID() {
return entityID;
}
@NotNull
@Override
public Map<String, Object> getPropertyMap() {
public Map<String, Object> propertyMap() {
return propertyMap;
}

View File

@@ -0,0 +1,4 @@
package net.momirealms.customfishing.api.mechanic.fishing;
public class FishingPreparation {
}

View File

@@ -30,7 +30,7 @@ import java.util.concurrent.TimeUnit;
public abstract class AbstractGamingPlayer implements GamingPlayer, Runnable {
private final FishingManager manager;
// private final FishingManager manager;
protected long deadline;
protected boolean success;
protected SchedulerTask task;
@@ -43,7 +43,7 @@ public abstract class AbstractGamingPlayer implements GamingPlayer, Runnable {
this.player = player;
this.fishHook = hook;
this.settings = settings;
this.manager = BukkitCustomFishingPlugin.getFishingManager();
// this.manager = BukkitCustomFishingPlugin.getInstance().get();
this.deadline = (long) (System.currentTimeMillis() + settings.time() * 1000L);
this.arrangeTask();
}
@@ -119,7 +119,7 @@ public abstract class AbstractGamingPlayer implements GamingPlayer, Runnable {
}
protected void endGame() {
this.manager.processGameResult(this);
// this.manager.processGameResult(this);
}
protected void setGameResult(boolean success) {

View File

@@ -17,11 +17,12 @@
package net.momirealms.customfishing.api.mechanic.hook;
import net.momirealms.customfishing.common.plugin.feature.Reloadable;
import org.jetbrains.annotations.NotNull;
import java.util.Optional;
public interface HookManager {
public interface HookManager extends Reloadable {
boolean registerHook(HookConfig hook);

View File

@@ -19,6 +19,7 @@ package net.momirealms.customfishing.api.mechanic.loot;
import net.momirealms.customfishing.api.mechanic.context.Context;
import net.momirealms.customfishing.api.mechanic.effect.Effect;
import net.momirealms.customfishing.common.plugin.feature.Reloadable;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -27,7 +28,7 @@ import java.util.List;
import java.util.Map;
import java.util.Optional;
public interface LootManager {
public interface LootManager extends Reloadable {
void registerLoot(@NotNull Loot loot);

View File

@@ -18,6 +18,7 @@
package net.momirealms.customfishing.api.mechanic.misc.cooldown;
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
import net.momirealms.customfishing.common.plugin.feature.Reloadable;
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler;
import org.bukkit.event.HandlerList;
@@ -34,7 +35,7 @@ import java.util.concurrent.ConcurrentHashMap;
* Manages cooldowns for various actions or events.
* Keeps track of cooldown times for different keys associated with player UUIDs.
*/
public class CoolDownManager implements Listener {
public class CoolDownManager implements Listener, Reloadable {
private final ConcurrentHashMap<UUID, Data> dataMap;
private final BukkitCustomFishingPlugin plugin;
@@ -57,14 +58,17 @@ public class CoolDownManager implements Listener {
return data.isCoolDown(key, time);
}
@Override
public void load() {
Bukkit.getPluginManager().registerEvents(this, plugin.getBoostrap());
}
@Override
public void unload() {
HandlerList.unregisterAll(this);
}
@Override
public void disable() {
unload();
this.dataMap.clear();

View File

@@ -32,17 +32,21 @@ import java.util.stream.Collectors;
public class BukkitPlaceholderManager implements PlaceholderManager {
private final BukkitCustomFishingPlugin plugin;
private final boolean hasPapi;
private boolean hasPapi;
private final HashMap<String, String> customPlaceholderMap;
private static BukkitPlaceholderManager instance;
public BukkitPlaceholderManager(BukkitCustomFishingPlugin plugin) {
this.plugin = plugin;
this.hasPapi = Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI");
this.customPlaceholderMap = new HashMap<>();
instance = this;
}
@Override
public void reload() {
this.hasPapi = Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI");
}
public static BukkitPlaceholderManager getInstance() {
return instance;
}

View File

@@ -17,6 +17,7 @@
package net.momirealms.customfishing.api.mechanic.misc.placeholder;
import net.momirealms.customfishing.common.plugin.feature.Reloadable;
import org.bukkit.OfflinePlayer;
import org.jetbrains.annotations.Nullable;
@@ -24,7 +25,7 @@ import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
public interface PlaceholderManager {
public interface PlaceholderManager extends Reloadable {
Pattern PATTERN = Pattern.compile("\\{[^{}]+}");

View File

@@ -19,6 +19,7 @@ package net.momirealms.customfishing.api.mechanic.requirement;
import dev.dejvokep.boostedyaml.block.implementation.Section;
import net.momirealms.customfishing.api.mechanic.context.Context;
import net.momirealms.customfishing.common.plugin.feature.Reloadable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -29,7 +30,7 @@ import java.util.List;
*
* @param <T> the type of the context in which the requirements are evaluated.
*/
public interface RequirementManager<T> {
public interface RequirementManager<T> extends Reloadable {
/**
* Registers a custom requirement type with its corresponding factory.

View File

@@ -0,0 +1,33 @@
package net.momirealms.customfishing.api.mechanic.totem;
import net.momirealms.customfishing.api.mechanic.requirement.Requirement;
import net.momirealms.customfishing.api.mechanic.totem.block.TotemBlock;
import org.bukkit.Location;
import org.bukkit.entity.Player;
public interface TotemConfig
{
TotemModel[] totemModels();
Requirement<Player>[] activateRequirements();
String id();
boolean isRightPattern(Location location);
TotemParticle[] particleSettings();
double radius();
int duration();
TotemBlock[] totemCore();
static Builder builder() {
return new TotemConfigImpl.BuilderImpl();
}
interface Builder {
}
}

View File

@@ -0,0 +1,125 @@
/*
* 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.api.mechanic.totem;
import net.momirealms.customfishing.api.mechanic.requirement.Requirement;
import net.momirealms.customfishing.api.mechanic.totem.block.TotemBlock;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import static java.util.Objects.requireNonNull;
public class TotemConfigImpl implements TotemConfig {
private String id;
private TotemModel[] totemModels;
private TotemParticle[] particleSettings;
private Requirement<Player>[] activateRequirements;
private double radius;
private int duration;
public TotemConfigImpl(String id, TotemModel[] totemModels, TotemParticle[] particleSettings, Requirement<Player>[] activateRequirements, double radius, int duration) {
this.id = id;
this.totemModels = totemModels;
this.particleSettings = particleSettings;
this.activateRequirements = activateRequirements;
this.radius = radius;
this.duration = duration;
}
@Override
public TotemModel[] totemModels() {
return totemModels;
}
@Override
public Requirement<Player>[] activateRequirements() {
return activateRequirements;
}
@Override
public String id() {
return id;
}
@Override
public boolean isRightPattern(Location location) {
for (TotemModel totemModel : totemModels) {
if (totemModel.isPatternSatisfied(location)) {
return true;
}
}
return false;
}
@Override
public TotemParticle[] particleSettings() {
return particleSettings;
}
@Override
public double radius() {
return radius;
}
@Override
public int duration() {
return duration;
}
@Override
public TotemBlock[] totemCore() {
return totemModels[0].getTotemCore();
}
public static class BuilderImpl implements Builder {
private String id;
private TotemModel[] totemModels;
private TotemParticle[] particleSettings;
private Requirement<Player>[] activateRequirements;
private double radius;
private int duration;
public Builder id(String id) {
this.id = id;
return this;
}
public Builder totemModels(TotemModel[] totemModels) {
this.totemModels = totemModels;
return this;
}
public Builder particleSettings(TotemParticle[] particleSettings) {
this.particleSettings = particleSettings;
return this;
}
public Builder radius(double radius) {
this.radius = radius;
return this;
}
public Builder duration(int duration) {
this.duration = duration;
return this;
}
public Builder activateRequirements(Requirement<Player>[] activateRequirements) {
this.activateRequirements = activateRequirements;
return this;
}
public TotemConfig build() {
return new TotemConfigImpl(requireNonNull(id), requireNonNull(totemModels), particleSettings, activateRequirements, radius, duration);
}
}
}

View File

@@ -0,0 +1,6 @@
package net.momirealms.customfishing.api.mechanic.totem;
import net.momirealms.customfishing.common.plugin.feature.Reloadable;
public interface TotemManager extends Reloadable {
}

View File

@@ -0,0 +1,277 @@
/*
* 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.api.mechanic.totem;
import net.momirealms.customfishing.api.mechanic.totem.block.TotemBlock;
import org.apache.commons.lang3.SerializationUtils;
import org.bukkit.Axis;
import org.bukkit.Location;
import java.io.Serializable;
import java.util.StringJoiner;
/**
* This class represents a totem model used to define the pattern of a totem.
*/
public class TotemModel implements Serializable {
private int coreX;
private final int coreY;
private int coreZ;
// [Y][Z][X][alternative totem blocks]
private TotemBlock[][][][] model;
/**
* Constructs a TotemModel with the specified parameters.
*
* @param coreX X-coordinate of the totem's core within the model.
* @param coreY Y-coordinate of the totem's core within the model.
* @param coreZ Z-coordinate of the totem's core within the model.
* @param model 3D array representing the totem model's structure.
*/
public TotemModel(int coreX, int coreY, int coreZ, TotemBlock[][][][] model) {
this.coreX = coreX;
this.coreY = coreY;
this.coreZ = coreZ;
this.model = model;
}
/**
* Get the totem core as an array of TotemBlock objects.
*
* @return An array of TotemBlock objects representing the totem's core.
*/
public TotemBlock[] getTotemCore() {
return model[coreY][coreZ][coreX];
}
/**
* Get the X-coordinate of the totem's core within the model.
*
* @return The X-coordinate as an integer.
*/
public int getCoreX() {
return coreX;
}
/**
* Get the Y-coordinate of the totem's core within the model.
*
* @return The Y-coordinate as an integer.
*/
public int getCoreY() {
return coreY;
}
/**
* Get the Z-coordinate of the totem's core within the model.
*
* @return The Z-coordinate as an integer.
*/
public int getCoreZ() {
return coreZ;
}
/**
* Get the 3D array representing the totem model's structure.
*
* @return The 3D array of TotemBlock objects.
*/
public TotemBlock[][][][] getModel() {
return model;
}
@Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder();
for (int h = 0; h < model.length; h++) {
stringBuilder.append("layer: ").append(h + 1).append("\n");
TotemBlock[][][] totemBlocks1 = model[h];
for (TotemBlock[][] totemBlocks2 : totemBlocks1) {
for (TotemBlock[] totemBlocks3 : totemBlocks2) {
StringJoiner stringJoiner = new StringJoiner("||");
for (TotemBlock totemBlock : totemBlocks3) {
stringJoiner.add(totemBlock.toString());
}
stringBuilder.append(stringJoiner).append("\t");
}
stringBuilder.append("\n");
}
}
return stringBuilder.toString();
}
public TotemModel deepClone() {
return SerializationUtils.clone(this);
}
/**
* Rotate the totem model 90 degrees clockwise.
*
* @return The rotated TotemModel.
*/
public TotemModel rotate90() {
int tempX = this.coreX;
this.coreX = this.coreZ;
this.coreZ = this.model[0][0].length - 1 - tempX;
this.model = rotate90(model);
for (TotemBlock[][][] totemBlocks1 : model) {
for (TotemBlock[][] totemBlocks2 : totemBlocks1) {
for (TotemBlock[] totemBlocks3 : totemBlocks2) {
for (TotemBlock totemBlock : totemBlocks3) {
totemBlock.rotate90();
}
}
}
}
return this;
}
/**
* Mirror the totem model horizontally.
*
* @return The mirrored TotemModel.
*/
public TotemModel mirrorHorizontally() {
mirrorHorizontally(model);
this.coreZ = model[0].length - this.coreZ - 1;
for (TotemBlock[][][] totemBlocks1 : model) {
for (TotemBlock[][] totemBlocks2 : totemBlocks1) {
for (TotemBlock[] totemBlocks3 : totemBlocks2) {
for (TotemBlock totemBlock : totemBlocks3) {
totemBlock.mirror(Axis.X);
}
}
}
}
return this;
}
/**
* Mirror the totem model vertically.
*
* @return The mirrored TotemModel.
*/
public TotemModel mirrorVertically() {
mirrorVertically(model);
this.coreX = model[0][0].length - this.coreX - 1;
for (TotemBlock[][][] totemBlocks1 : model) {
for (TotemBlock[][] totemBlocks2 : totemBlocks1) {
for (TotemBlock[] totemBlocks3 : totemBlocks2) {
for (TotemBlock totemBlock : totemBlocks3) {
totemBlock.mirror(Axis.Z);
}
}
}
}
return this;
}
/**
* Check if the provided location satisfies the pattern defined by the totem model.
*
* @param location The location to check.
* @return True if the location satisfies the pattern, false otherwise.
*/
public boolean isPatternSatisfied(Location location) {
Location startLoc = location.clone().subtract(0, coreY, 0);
int height = model.length;
int width = model[0].length;
int length = model[0][0].length;
for (int y = 0; y < height; y++) {
Location loc = startLoc.clone().add(-coreX, y, -coreZ);
for (int z = 0; z < width; z++) {
outer:
for (int x = 0; x < length; x++) {
for (TotemBlock totemBlock : model[y][z][x]) {
if (totemBlock.isRightBlock(loc.clone().add(x, 0, z).getBlock())) {
continue outer;
}
}
return false;
}
}
}
return true;
}
/**
* Rotate a 3D totem model 90 degrees clockwise.
*
* @param matrix The 3D totem model to rotate.
* @return The rotated 3D totem model.
*/
private static TotemBlock[][][][] rotate90(TotemBlock[][][][] matrix) {
int height = matrix.length;
int rows = matrix[0].length;
int cols = matrix[0][0].length;
TotemBlock[][][][] rotated = new TotemBlock[height][cols][rows][];
for (int h = 0; h < height; h++) {
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
rotated[h][c][rows - 1 - r] = matrix[h][r][c];
}
}
}
return rotated;
}
/**
* Mirror a 3D totem model horizontally.
*
* @param matrix The 3D totem model to mirror.
*/
private static void mirrorHorizontally(TotemBlock[][][][] matrix) {
int height = matrix.length;
int rows = matrix[0].length;
int cols = matrix[0][0].length;
for (int h = 0; h < height; h++) {
for (int i = 0; i < rows / 2; i++) {
for (int j = 0; j < cols; j++) {
TotemBlock[] temp = matrix[h][i][j];
matrix[h][i][j] = matrix[h][rows - i - 1][j];
matrix[h][rows - i - 1][j] = temp;
}
}
}
}
/**
* Mirror a 3D totem model vertically.
*
* @param matrix The 3D totem model to mirror.
*/
private static void mirrorVertically(TotemBlock[][][][] matrix) {
int height = matrix.length;
int rows = matrix[0].length;
int cols = matrix[0][0].length;
for (int h = 0; h < height; h++) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols / 2; j++) {
TotemBlock[] temp = matrix[h][i][j];
matrix[h][i][j] = matrix[h][i][cols - j - 1];
matrix[h][i][cols - j - 1] = temp;
}
}
}
}
}

View File

@@ -0,0 +1,16 @@
package net.momirealms.customfishing.api.mechanic.totem;
import net.momirealms.customfishing.common.plugin.scheduler.SchedulerTask;
import org.bukkit.Location;
public interface TotemParticle {
/**
* Start the particle task at specified location
*
* @param location location
* @param radius totem radius
* @return cancellable task
*/
SchedulerTask start(Location location, double radius);
}

View File

@@ -0,0 +1,118 @@
/*
* 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.api.mechanic.totem.block;
import net.momirealms.customfishing.api.mechanic.totem.block.property.TotemBlockProperty;
import net.momirealms.customfishing.api.mechanic.totem.block.type.TypeCondition;
import org.bukkit.Axis;
import org.bukkit.block.Block;
import java.io.Serializable;
import java.util.StringJoiner;
/**
* Represents a TotemBlock that defines conditions and properties for a specific block type in a totem structure.
*/
public class TotemBlock implements Serializable {
private final TypeCondition typeCondition;
private final TotemBlockProperty[] properties;
/**
* Initializes a TotemBlock with the specified TypeCondition and properties.
*
* @param typeCondition The TypeCondition that specifies the block type.
* @param properties An array of TotemBlockProperty objects representing additional block properties.
*/
public TotemBlock(TypeCondition typeCondition, TotemBlockProperty[] properties) {
this.typeCondition = typeCondition;
this.properties = properties;
}
/**
* Gets the TypeCondition associated with this TotemBlock.
*
* @return The TypeCondition defining the block type.
*/
public TypeCondition getTypeCondition() {
return typeCondition;
}
/**
* Gets an array of properties associated with this TotemBlock.
*
* @return An array of TotemBlockProperty objects representing block properties.
*/
public TotemBlockProperty[] getProperties() {
return properties;
}
/**
* Checks if a given Block satisfies the TypeCondition and properties of this TotemBlock.
*
* @param block The Block to be checked against the conditions and properties.
* @return `true` if the block satisfies all conditions and properties, otherwise `false`.
*/
public boolean isRightBlock(Block block) {
if (!typeCondition.isMet(block)) {
return false;
}
for (TotemBlockProperty property : properties) {
if (!property.isPropertyMet(block)) {
return false;
}
}
return true;
}
/**
* Rotates the properties of this TotemBlock by 90 degrees.
* This method should be called when the totem structure is rotated.
*/
public void rotate90() {
for (TotemBlockProperty property : properties) {
property.rotate90();
}
}
/**
* Mirrors the properties of this TotemBlock horizontally or vertically.
* This method should be called when the totem structure is mirrored.
*
* @param axis The Axis along which to mirror the properties (X or Z).
*/
public void mirror(Axis axis) {
for (TotemBlockProperty property : properties) {
property.mirror(axis);
}
}
/**
* Returns the raw text representation of this TotemBlock, including its TypeCondition and properties.
*
* @return The raw text representation of this TotemBlock.
*/
@Override
public String toString() {
StringJoiner stringJoiner = new StringJoiner(";");
for (TotemBlockProperty property : properties) {
stringJoiner.add(property.getRawText());
}
return typeCondition.getRawText() + "{" + stringJoiner + "}";
}
}

View File

@@ -0,0 +1,71 @@
/*
* 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.api.mechanic.totem.block.property;
import org.bukkit.Axis;
import org.bukkit.block.Block;
import org.bukkit.block.data.Orientable;
import java.io.Serializable;
import java.util.Locale;
public class AxisImpl implements TotemBlockProperty, Serializable {
private Axis axis;
public AxisImpl(Axis axis) {
this.axis = axis;
}
@Override
public TotemBlockProperty mirror(Axis axis) {
return this;
}
/**
* Rotates the block axis 90 degrees. (X -> Z, Z -> X)
* @return The rotated block axis.
*/
@Override
public TotemBlockProperty rotate90() {
if (this.axis == Axis.X) {
axis = Axis.Z;
} else if (this.axis == Axis.Z) {
axis = Axis.X;
}
return this;
}
/**
* Checks if the block has the property.
* @param block The block to check.
* @return True if the block has the property.
*/
@Override
public boolean isPropertyMet(Block block) {
if (block.getBlockData() instanceof Orientable orientable) {
return orientable.getAxis().equals(this.axis);
}
return false;
}
@Override
public String getRawText() {
return "axis=" + axis.name().toLowerCase(Locale.ENGLISH);
}
}

View File

@@ -0,0 +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.api.mechanic.totem.block.property;
import org.bukkit.Axis;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.Directional;
import java.io.Serializable;
import java.util.Locale;
public class FaceImpl implements TotemBlockProperty, Serializable {
private BlockFace blockFace;
public FaceImpl(BlockFace blockFace) {
this.blockFace = blockFace;
}
/**
* Mirrors the block face if the axis is X or Z.
* @param axis The axis to mirror.
* @return The mirrored block face.
*/
@Override
public TotemBlockProperty mirror(Axis axis) {
if (axis == Axis.X) {
if (blockFace == BlockFace.SOUTH || blockFace == BlockFace.NORTH) {
return new FaceImpl(blockFace.getOppositeFace());
} else {
return this;
}
} else if (axis == Axis.Z) {
if (blockFace == BlockFace.EAST || blockFace == BlockFace.WEST) {
return new FaceImpl(blockFace.getOppositeFace());
} else {
return this;
}
}
return this;
}
@Override
public TotemBlockProperty rotate90() {
switch (blockFace) {
case UP, DOWN -> {
return this;
}
case EAST -> blockFace = BlockFace.SOUTH;
case SOUTH -> blockFace = BlockFace.WEST;
case WEST -> blockFace = BlockFace.NORTH;
case NORTH -> blockFace = BlockFace.EAST;
default -> throw new IllegalArgumentException("Unsupported block facing: " + blockFace);
}
return this;
}
@Override
public boolean isPropertyMet(Block block) {
if (block.getBlockData() instanceof Directional directional) {
return directional.getFacing().equals(this.blockFace);
}
return false;
}
@Override
public String getRawText() {
return "face=" + blockFace.name().toLowerCase(Locale.ENGLISH);
}
}

View File

@@ -0,0 +1,74 @@
/*
* 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.api.mechanic.totem.block.property;
import org.bukkit.Axis;
import org.bukkit.block.Block;
import org.bukkit.block.data.Bisected;
import java.io.Serializable;
import java.util.Locale;
public class HalfImpl implements TotemBlockProperty, Serializable {
private final Bisected.Half half;
public HalfImpl(Bisected.Half half) {
this.half = half;
}
/**
* half is not affected by mirroring.
* @param axis The axis to mirror.
* @return this
*/
@Override
public TotemBlockProperty mirror(Axis axis) {
return this;
}
/**
* half is not affected by rotation.
* @return this
*/
@Override
public TotemBlockProperty rotate90() {
return this;
}
/**
* Checks if the block's half is the same as the half of this property.
* @param block The block to check.
* @return true if the block's half is the same as the half of this property.
*/
@Override
public boolean isPropertyMet(Block block) {
if (block.getBlockData() instanceof Bisected bisected) {
return bisected.getHalf().equals(this.half);
}
return false;
}
/**
* Returns the raw text of the half property.
* @return The raw text of the half property.
*/
@Override
public String getRawText() {
return "half=" + half.name().toLowerCase(Locale.ENGLISH);
}
}

View File

@@ -0,0 +1,50 @@
/*
* 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.api.mechanic.totem.block.property;
import org.bukkit.Axis;
import org.bukkit.block.Block;
public interface TotemBlockProperty {
/**
* Mirrors the block face if the axis is X or Z.
* @param axis The axis to mirror.
* @return The mirrored block face.
*/
TotemBlockProperty mirror(Axis axis);
/**
* Rotates the block face 90 degrees.
* @return The rotated block face.
*/
TotemBlockProperty rotate90();
/**
* Checks if the block has the property.
* @param block The block to check.
* @return True if the block has the property.
*/
boolean isPropertyMet(Block block);
/**
* Gets the raw text of the property.
* @return The raw text of the property.
*/
String getRawText();
}

View File

@@ -0,0 +1,56 @@
/*
* 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.api.mechanic.totem.block.type;
import org.bukkit.block.Block;
import java.io.Serializable;
/**
* Represents a TypeCondition that checks if a Block's type name ends with a specified string.
*/
public class EndWithType implements TypeCondition, Serializable {
private final String end;
public EndWithType(String end) {
this.end = end;
}
/**
* Checks if the specified Block's type name ends with the configured ending string.
*
* @param type The Block to check.
* @return `true` if the Block's type name ends with the specified string, otherwise `false`.
*/
@Override
public boolean isMet(Block type) {
return type.getType().name().endsWith(end);
}
/**
* Gets the raw text representation of this TypeCondition.
* The raw text includes the asterisk (*) followed by the configured ending string.
*
* @return The raw text representation of this TypeCondition.
*/
@Override
public String getRawText() {
return "*" + end;
}
}

View File

@@ -0,0 +1,56 @@
/*
* 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.api.mechanic.totem.block.type;
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
import org.bukkit.block.Block;
import java.io.Serializable;
/**
* Represents a TypeCondition that checks if a Block's type matches a specified type string.
*/
public class EqualType implements TypeCondition, Serializable {
private final String type;
public EqualType(String type) {
this.type = type;
}
/**
* Checks if the specified Block's type matches the configured type string.
*
* @param type The Block to check.
* @return `true` if the Block's type matches the specified type string, otherwise `false`.
*/
@Override
public boolean isMet(Block type) {
return this.type.equals(BukkitCustomFishingPlugin.getInstance().getBlockManager().getBlockID(type));
}
/**
* Gets the raw text representation of this TypeCondition, which is the configured type string.
*
* @return The raw text representation of this TypeCondition.
*/
@Override
public String getRawText() {
return type;
}
}

View File

@@ -0,0 +1,55 @@
/*
* 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.api.mechanic.totem.block.type;
import org.bukkit.block.Block;
import java.io.Serializable;
/**
* Represents a TypeCondition that checks if a Block's type starts with a specified prefix.
*/
public class StartWithType implements TypeCondition, Serializable {
private final String start;
public StartWithType(String start) {
this.start = start;
}
/**
* Checks if the specified Block's type starts with the configured prefix.
*
* @param type The Block to check.
* @return `true` if the Block's type starts with the specified prefix, otherwise `false`.
*/
@Override
public boolean isMet(Block type) {
return type.getType().name().startsWith(start);
}
/**
* Gets the raw text representation of this TypeCondition, which is the configured prefix followed by '*'.
*
* @return The raw text representation of this TypeCondition.
*/
@Override
public String getRawText() {
return start + "*";
}
}

View File

@@ -0,0 +1,57 @@
/*
* 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.api.mechanic.totem.block.type;
import org.bukkit.block.Block;
/**
* Represents a condition used to check the type of a Block.
*/
public interface TypeCondition {
/**
* Checks if the specified Block meets the condition.
*
* @param block The Block to check.
* @return `true` if the condition is met, otherwise `false`.
*/
boolean isMet(Block block);
/**
* Gets the raw text representation of this TypeCondition.
*
* @return The raw text representation of this TypeCondition.
*/
String getRawText();
/**
* Gets a TypeCondition based on its raw text representation.
*
* @param raw The raw text representation of the TypeCondition.
* @return A TypeCondition instance corresponding to the raw text.
*/
static TypeCondition getTypeCondition(String raw) {
if (raw.startsWith("*")) {
return new EndWithType(raw.substring(1));
} else if (raw.endsWith("*")) {
return new StartWithType(raw.substring(0, raw.length() -1));
} else {
return new EqualType(raw);
}
}
}

View File

@@ -19,6 +19,7 @@ package net.momirealms.customfishing.api.storage;
import net.momirealms.customfishing.api.storage.data.PlayerData;
import net.momirealms.customfishing.api.storage.user.UserData;
import net.momirealms.customfishing.common.plugin.feature.Reloadable;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
@@ -26,7 +27,7 @@ import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
public interface StorageManager {
public interface StorageManager extends Reloadable {
@NotNull
String getServerID();
@@ -52,7 +53,7 @@ public interface StorageManager {
* @param data The PlayerData to be converted.
* @return The byte array representation of PlayerData.
*/
byte @NotNull [] toBytes(@NotNull PlayerData data);
byte[] toBytes(@NotNull PlayerData data);
/**
* Converts PlayerData to JSON format.

View File

@@ -0,0 +1,12 @@
repositories {
maven("https://oss.sonatype.org/content/repositories/snapshots")
maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/")
}
dependencies {
implementation(project(":core"))
implementation(project(":common"))
implementation(project(":compatibility"))
implementation(project(":api"))
compileOnly("org.spigotmc:spigot-api:${rootProject.properties["paper_version"]}-R0.1-SNAPSHOT")
}

View File

@@ -1,7 +0,0 @@
package net.momirealms;
public class Main {
public static void main(String[] args) {
System.out.println("Hello world!");
}
}

View File

@@ -0,0 +1,25 @@
package net.momirealms.customfishing.bukkit;
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
import org.bukkit.plugin.java.JavaPlugin;
public class BukkitBootstrap extends JavaPlugin {
private BukkitCustomFishingPlugin plugin;
@Override
public void onLoad() {
this.plugin = new BukkitCustomFishingPluginImpl(this);
this.plugin.load();
}
@Override
public void onEnable() {
this.plugin.enable();
}
@Override
public void onDisable() {
this.plugin.disable();
}
}

View File

@@ -1,11 +1,9 @@
name: CustomFishing
version: '${version}'
main: net.momirealms.customfishing.CustomFishingPluginImpl
version: '${project_version}'
main: net.momirealms.customfishing.bukkit.BukkitBootstrap
api-version: 1.17
authors: [ XiaoMoMi ]
folia-supported: true
depend:
- ProtocolLib
softdepend:
- Vault
- PlaceholderAPI

View File

@@ -13,4 +13,6 @@ public interface ConfigLoader {
YamlDocument loadData(File file);
YamlDocument loadData(File file, char routeSeparator);
void saveResource(String filePath);
}

View File

@@ -236,13 +236,6 @@ public enum Dependency {
"caffeine",
Relocation.of("caffeine", "com{}github{}benmanes{}caffeine")
),
LETTUCE(
"io{}lettuce",
"lettuce-core",
"maven",
"lettuce-core",
Relocation.of("lettuce", "io{}lettuce")
),
JEDIS(
"redis{}clients",
"jedis",

View File

@@ -17,126 +17,25 @@
package net.momirealms.customfishing.common.helper;
import net.momirealms.customfishing.common.plugin.CustomFishingPlugin;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
/**
* This class implements the VersionManager interface and is responsible for managing version-related information.
*/
public class VersionHelper {
private final boolean isNewerThan1_19_3;
private final boolean isNewerThan1_19_4;
private final boolean isNewerThan1_20;
private final boolean isNewerThan1_20_5;
private final boolean isNewerThan1_19;
private final String serverVersion;
private final boolean isSpigot;
private boolean hasRegionScheduler;
private boolean isMojmap;
private final String pluginVersion;
public VersionHelper(String serverVersion) {
this.serverVersion = serverVersion;
String[] split = serverVersion.split("\\.");
int main_ver = Integer.parseInt(split[0]);
// Determine if the server version is newer than 1_19_R2 and 1_20_R1
if (main_ver >= 20) {
isNewerThan1_20_5 = Integer.parseInt(split[1]) >= 5;
isNewerThan1_19_3 = isNewerThan1_19_4 = true;
isNewerThan1_20 = true;
isNewerThan1_19 = true;
} else if (main_ver == 19) {
isNewerThan1_20 = isNewerThan1_20_5 = false;
isNewerThan1_19_3 = Integer.parseInt(split[1]) >= 3;
isNewerThan1_19_4 = Integer.parseInt(split[1]) >= 4;
isNewerThan1_19 = true;
} else {
isNewerThan1_20 = isNewerThan1_20_5 = isNewerThan1_19 = isNewerThan1_19_3 = isNewerThan1_19_4 = false;
}
// Check if the server is Spigot
String server_name = plugin.getServer().getName();
this.isSpigot = server_name.equals("CraftBukkit");
// Check if the server is Folia
try {
Class.forName("io.papermc.paper.threadedregions.scheduler.AsyncScheduler");
this.hasRegionScheduler = true;
} catch (ClassNotFoundException ignored) {
}
// Check if the server is Mojmap
try {
Class.forName("net.minecraft.network.protocol.game.ClientboundBossEventPacket");
this.isMojmap = true;
} catch (ClassNotFoundException ignored) {
}
// Get the plugin version
this.pluginVersion = plugin.getDescription().getVersion();
}
@Override
public boolean isVersionNewerThan1_19() {
return isNewerThan1_19;
}
@Override
public boolean isVersionNewerThan1_19_4() {
return isNewerThan1_19_4;
}
@Override
public boolean isVersionNewerThan1_19_3() {
return isNewerThan1_19_3;
}
@Override
public boolean isVersionNewerThan1_20() {
return isNewerThan1_20;
}
@Override
public boolean isNewerThan1_20_5() {
return isNewerThan1_20_5;
}
@Override
public boolean isSpigot() {
return isSpigot;
}
@Override
public String getPluginVersion() {
return pluginVersion;
}
@Override
public boolean hasRegionScheduler() {
return hasRegionScheduler;
}
@Override
public boolean isMojmap() {
return isMojmap;
}
@Override
public String getServerVersion() {
return serverVersion;
}
// Method to asynchronously check for plugin updates
@Override
public CompletableFuture<Boolean> checkUpdate() {
public static final Function<CustomFishingPlugin, CompletableFuture<Boolean>> UPDATE_CHECKER = (plugin) -> {
CompletableFuture<Boolean> updateFuture = new CompletableFuture<>();
plugin.getScheduler().async(() -> {
plugin.getScheduler().async().execute(() -> {
try {
URL url = new URL("https://api.polymart.org/v1/getResourceInfoSimple/?resource_id=2723&key=version");
URLConnection conn = url.openConnection();
@@ -144,7 +43,7 @@ public class VersionHelper {
conn.setReadTimeout(60000);
InputStream inputStream = conn.getInputStream();
String newest = new BufferedReader(new InputStreamReader(inputStream)).readLine();
String current = plugin.getVersionManager().getPluginVersion();
String current = plugin.getPluginVersion();
inputStream.close();
if (!compareVer(newest, current)) {
updateFuture.complete(false);
@@ -152,15 +51,71 @@ public class VersionHelper {
}
updateFuture.complete(true);
} catch (Exception exception) {
LogUtils.warn("Error occurred when checking update.", exception);
plugin.getPluginLogger().warn("Error occurred when checking update.", exception);
updateFuture.complete(false);
}
});
return updateFuture;
};
private static float version;
private static boolean mojmap;
private static boolean folia;
public static void init(String serverVersion) {
String[] split = serverVersion.split("\\.");
version = Float.parseFloat(split[1] + "." + split[2]);
checkMojMap();
checkFolia();
}
private static void checkMojMap() {
// Check if the server is Mojmap
try {
Class.forName("net.minecraft.network.protocol.game.ClientboundBossEventPacket");
mojmap = true;
} catch (ClassNotFoundException ignored) {
}
}
private static void checkFolia() {
try {
Class.forName("io.papermc.paper.threadedregions.RegionizedServer");
folia = true;
} catch (ClassNotFoundException ignored) {
}
}
public static boolean isVersionNewerThan1_19() {
return version >= 19;
}
public static boolean isVersionNewerThan1_19_4() {
return version >= 19.4;
}
public static boolean isVersionNewerThan1_19_3() {
return version >= 19.3;
}
public static boolean isVersionNewerThan1_20() {
return version >= 20.0;
}
public boolean isNewerThan1_20_5() {
return version >= 20.5;
}
public static boolean isFolia() {
return folia;
}
public static boolean isMojmap() {
return mojmap;
}
// Method to compare two version strings
private boolean compareVer(String newV, String currentV) {
private static boolean compareVer(String newV, String currentV) {
if (newV == null || currentV == null || newV.isEmpty() || currentV.isEmpty()) {
return false;
}

View File

@@ -5,5 +5,112 @@ import net.kyori.adventure.text.TranslatableComponent;
public interface MessageConstants {
TranslatableComponent.Builder COMMAND_RELOAD = Component.translatable().key("argument.entity.notfound.player");
TranslatableComponent.Builder COMMAND_PREFIX = Component.translatable().key("command.prefix");
TranslatableComponent.Builder COMMAND_RELOAD_SUCCESS = Component.translatable().key("command.reload.success");
TranslatableComponent.Builder COMMAND_ITEM_FAILURE_NOT_EXIST = Component.translatable().key("command.item.failure.not_exist");
TranslatableComponent.Builder COMMAND_ITEM_GIVE_SUCCESS = Component.translatable().key("command.item.give.success");
TranslatableComponent.Builder COMMAND_ITEM_GET_SUCCESS = Component.translatable().key("command.item.get.success");
TranslatableComponent.Builder COMMAND_FISH_FINDER_POSSIBLE_LOOTS = Component.translatable().key("command.fish_finder.possible_loots");
TranslatableComponent.Builder COMMAND_FISH_FINDER_NO_LOOT = Component.translatable().key("command.fish_finder.no_loot");
TranslatableComponent.Builder COMMAND_FISH_FINDER_SPLIT_CHAR = Component.translatable().key("command.fish_finder.split_char");
TranslatableComponent.Builder COMMAND_COMPETITION_FAILURE_NOT_EXIST = Component.translatable().key("command.competition.failure.not_exist");
TranslatableComponent.Builder COMMAND_COMPETITION_FAILURE_NO_COMPETITION = Component.translatable().key("command.competition.failure.no_competition");
TranslatableComponent.Builder COMMAND_COMPETITION_FAILURE_STOP_SUCCESS = Component.translatable().key("command.competition.failure.stop.success");
TranslatableComponent.Builder COMMAND_COMPETITION_FAILURE_END_SUCCESS = Component.translatable().key("command.competition.failure.end.success");
TranslatableComponent.Builder COMMAND_BAG_EDIT_FAILURE_UNSAFE = Component.translatable().key("command.bag.edit.failure.unsafe");
TranslatableComponent.Builder COMMAND_BAG_EDIT_FAILURE_NEVER_PLAYED = Component.translatable().key("command.bag.edit.failure.never_played");
TranslatableComponent.Builder COMMAND_BAG_OPEN_SUCCESS = Component.translatable().key("command.bag.edit.open.success");
TranslatableComponent.Builder COMMAND_DATA_FAILURE_NOT_LOAD = Component.translatable().key("command.data.failure.not_load");
TranslatableComponent.Builder COMMAND_MARKET_OPEN_SUCCESS = Component.translatable().key("command.market.open.success");
TranslatableComponent.Builder GUI_SELECT_FILE = Component.translatable().key("gui.select_file");
TranslatableComponent.Builder GUI_SELECT_ITEM = Component.translatable().key("gui.select_item");
TranslatableComponent.Builder GUI_INVALID_KEY = Component.translatable().key("gui.invalid_key");
TranslatableComponent.Builder GUI_NEW_VALUE = Component.translatable().key("gui.new_value");
TranslatableComponent.Builder GUI_TEMP_NEW_KEY = Component.translatable().key("gui.temp_new_key");
TranslatableComponent.Builder GUI_SET_NEW_KEY = Component.translatable().key("gui.set_new_key");
TranslatableComponent.Builder GUI_EDIT_KEY = Component.translatable().key("gui.edit_key");
TranslatableComponent.Builder GUI_DELETE_PROPERTY = Component.translatable().key("gui.delete_property");
TranslatableComponent.Builder GUI_CLICK_CONFIRM = Component.translatable().key("gui.click_confirm");
TranslatableComponent.Builder GUI_INVALID_NUMBER = Component.translatable().key("gui.invalid_number");
TranslatableComponent.Builder GUI_ILLEGAL_FORMAT = Component.translatable().key("gui.illegal_format");
TranslatableComponent.Builder GUI_SCROLL_UP = Component.translatable().key("gui.scroll_up");
TranslatableComponent.Builder GUI_SCROLL_DOWN = Component.translatable().key("gui.scroll_down");
TranslatableComponent.Builder GUI_CANNOT_SCROLL_UP = Component.translatable().key("gui.cannot_scroll_up");
TranslatableComponent.Builder GUI_CANNOT_SCROLL_DOWN = Component.translatable().key("gui.cannot_scroll_down");
TranslatableComponent.Builder GUI_NEXT_PAGE = Component.translatable().key("gui.next_page");
TranslatableComponent.Builder GUI_GOTO_NEXT_PAGE = Component.translatable().key("gui.goto_next_page");
TranslatableComponent.Builder GUI_CANNOT_GOTO_NEXT_PAGE = Component.translatable().key("gui.cannot_goto_next_page");
TranslatableComponent.Builder GUI_PREVIOUS_PAGE = Component.translatable().key("gui.previous_page");
TranslatableComponent.Builder GUI_GOTO_PREVIOUS_PAGE = Component.translatable().key("gui.goto_previous_page");
TranslatableComponent.Builder GUI_CANNOT_GOTO_PREVIOUS_PAGE = Component.translatable().key("gui.cannot_goto_previous_page");
TranslatableComponent.Builder GUI_BACK_TO_PARENT_PAGE = Component.translatable().key("gui.back_to_parent_page");
TranslatableComponent.Builder GUI_BACK_TO_PARENT_FOLDER = Component.translatable().key("gui.back_to_parent_folder");
TranslatableComponent.Builder GUI_CURRENT_VALUE = Component.translatable().key("gui.current_value");
TranslatableComponent.Builder GUI_CLICK_TO_TOGGLE = Component.translatable().key("gui.click_to_toggle");
TranslatableComponent.Builder GUI_LEFT_CLICK_EDIT = Component.translatable().key("gui.left_click_edit");
TranslatableComponent.Builder GUI_RIGHT_CLICK_RESET = Component.translatable().key("gui.right_click_reset");
TranslatableComponent.Builder GUI_RIGHT_CLICK_DELETE = Component.translatable().key("gui.right_click_delete");
TranslatableComponent.Builder GUI_RIGHT_CLICK_CANCEL = Component.translatable().key("gui.right_click_cancel");
TranslatableComponent.Builder GUI_LOOT_SHOW_IN_FINDER = Component.translatable().key("gui.loot_show_in_finder");
TranslatableComponent.Builder GUI_LOOT_SCORE = Component.translatable().key("gui.loot_score");
TranslatableComponent.Builder GUI_LOOT_NICK = Component.translatable().key("gui.loot_nick");
TranslatableComponent.Builder GUI_LOOT_INSTANT_GAME = Component.translatable().key("gui.loot_instant_game");
TranslatableComponent.Builder GUI_LOOT_DISABLE_STATISTICS = Component.translatable().key("gui.loot_disable_statistics");
TranslatableComponent.Builder GUI_LOOT_DISABLE_GAME = Component.translatable().key("gui.loot_disable_game");
TranslatableComponent.Builder GUI_ITEM_AMOUNT = Component.translatable().key("gui.item_amount");
TranslatableComponent.Builder GUI_ITEM_CUSTOM_MODEL_DATA = Component.translatable().key("gui.item_custom_model_data");
TranslatableComponent.Builder GUI_ITEM_DISPLAY_NAME = Component.translatable().key("gui.item_display_name");
TranslatableComponent.Builder GUI_ITEM_CUSTOM_DURABILITY = Component.translatable().key("gui.item_custom_durability");
TranslatableComponent.Builder GUI_ITEM_ENCHANTMENT = Component.translatable().key("gui.item_enchantment");
TranslatableComponent.Builder GUI_ITEM_HEAD64 = Component.translatable().key("gui.item_head64");
TranslatableComponent.Builder GUI_ITEM_FLAG = Component.translatable().key("gui.item_item_flag");
TranslatableComponent.Builder GUI_ITEM_LORE = Component.translatable().key("gui.item_lore");
TranslatableComponent.Builder GUI_ITEM_MATERIAL = Component.translatable().key("gui.item_material");
TranslatableComponent.Builder GUI_ITEM_NBT = Component.translatable().key("gui.item_nbt");
TranslatableComponent.Builder GUI_ITEM_PREVENT_GRAB = Component.translatable().key("gui.item_prevent_grab");
TranslatableComponent.Builder GUI_ITEM_PRICE = Component.translatable().key("gui.item_price");
TranslatableComponent.Builder GUI_ITEM_PRICE_BASE = Component.translatable().key("gui.item_price_base");
TranslatableComponent.Builder GUI_ITEM_PRICE_BONUS = Component.translatable().key("gui.item_price_bonus");
TranslatableComponent.Builder GUI_ITEM_RANDOM_DURABILITY = Component.translatable().key("gui.item_random_durability");
TranslatableComponent.Builder GUI_ITEM_SIZE = Component.translatable().key("gui.item_size");
TranslatableComponent.Builder GUI_ITEM_STACKABLE = Component.translatable().key("gui.item_stackable");
TranslatableComponent.Builder GUI_ITEM_STORED_ENCHANTMENT = Component.translatable().key("gui.item_stored_enchantment");
TranslatableComponent.Builder GUI_ITEM_TAG = Component.translatable().key("gui.item_tag");
TranslatableComponent.Builder GUI_ITEM_UNBREAKABLE = Component.translatable().key("gui.item_unbreakable");
TranslatableComponent.Builder GUI_PAGE_AMOUNT_TITLE = Component.translatable().key("gui.page_amount_title");
TranslatableComponent.Builder GUI_PAGE_MODEL_DATA_TITLE = Component.translatable().key("gui.page_model_data_title");
TranslatableComponent.Builder GUI_PAGE_DISPLAY_NAME_TITLE = Component.translatable().key("gui.page_display_name_title");
TranslatableComponent.Builder GUI_PAGE_NEW_DISPLAY_NAME = Component.translatable().key("gui.page_new_display_name");
TranslatableComponent.Builder GUI_PAGE_CUSTOM_DURABILITY_TITLE = Component.translatable().key("gui.page_custom_durability_title");
TranslatableComponent.Builder GUI_PAGE_STORED_ENCHANTMENT_TITLE = Component.translatable().key("gui.page_stored_enchantment_title");
TranslatableComponent.Builder GUI_PAGE_ENCHANTMENT_TITLE = Component.translatable().key("gui.page_enchantment_title");
TranslatableComponent.Builder GUI_PAGE_SELECT_ONE_ENCHANTMENT = Component.translatable().key("gui.page_select_one_enchantment");
TranslatableComponent.Builder GUI_PAGE_ADD_NEW_ENCHANTMENT = Component.translatable().key("gui.page_add_new_enchantment");
TranslatableComponent.Builder GUI_PAGE_ITEM_FLAG_TITLE = Component.translatable().key("gui.page_item_flag_title");
TranslatableComponent.Builder GUI_PAGE_LORE_TITLE = Component.translatable().key("gui.page_lore_title");
TranslatableComponent.Builder GUI_PAGE_ADD_NEW_LORE = Component.translatable().key("gui.page_add_new_lore");
TranslatableComponent.Builder GUI_PAGE_SELECT_ONE_LORE = Component.translatable().key("gui.page_select_one_lore");
TranslatableComponent.Builder GUI_PAGE_MATERIAL_TITLE = Component.translatable().key("gui.page_material_title");
TranslatableComponent.Builder GUI_PAGE_NBT_COMPOUND_KEY_TITLE = Component.translatable().key("gui.page_nbt_compound_key_title");
TranslatableComponent.Builder GUI_PAGE_NBT_LIST_KEY_TITLE = Component.translatable().key("gui.page_nbt_list_key_title");
TranslatableComponent.Builder GUI_PAGE_NBT_KEY_TITLE = Component.translatable().key("gui.page_nbt_key_title");
TranslatableComponent.Builder GUI_PAGE_NBT_INVALID_KEY = Component.translatable().key("gui.page_nbt_invalid_key");
TranslatableComponent.Builder GUI_PAGE_NBT_ADD_NEW_COMPOUND= Component.translatable().key("gui.page_nbt_add_new_compound");
TranslatableComponent.Builder GUI_PAGE_NBT_ADD_NEW_LIST = Component.translatable().key("gui.page_nbt_add_new_list");
TranslatableComponent.Builder GUI_PAGE_NBT_ADD_NEW_VALUE = Component.translatable().key("gui.page_nbt_add_new_value");
TranslatableComponent.Builder GUI_PAGE_ADD_NEW_KEY = Component.translatable().key("gui.page_add_new_key");
TranslatableComponent.Builder GUI_PAGE_NBT_PREVIEW = Component.translatable().key("gui.page_nbt_preview");
TranslatableComponent.Builder GUI_PAGE_NBT_BACK_TO_COMPOUND = Component.translatable().key("gui.page_nbt_back_to_compound");
TranslatableComponent.Builder GUI_PAGE_NBT_SET_VALUE_TITLE = Component.translatable().key("gui.page_nbt_set_value_title");
TranslatableComponent.Builder GUI_PAGE_NBT_EDIT_TITLE = Component.translatable().key("gui.page_nbt_edit_title");
TranslatableComponent.Builder GUI_PAGE_NICK_TITLE = Component.translatable().key("gui.page_nick_title");
TranslatableComponent.Builder GUI_PAGE_NEW_NICK = Component.translatable().key("gui.page_new_nick");
TranslatableComponent.Builder GUI_PAGE_PRICE_TITLE = Component.translatable().key("gui.page_price_title");
TranslatableComponent.Builder GUI_PAGE_BASE_PRICE = Component.translatable().key("gui.page_base_price");
TranslatableComponent.Builder GUI_PAGE_BASE_BONUS = Component.translatable().key("gui.page_base_bonus");
TranslatableComponent.Builder GUI_PAGE_SCORE_TITLE = Component.translatable().key("gui.page_score_title");
TranslatableComponent.Builder GUI_PAGE_SIZE_TITLE = Component.translatable().key("gui.page_size_title");
TranslatableComponent.Builder GUI_PAGE_SIZE_MIN = Component.translatable().key("gui.page_size_min");
TranslatableComponent.Builder GUI_PAGE_SIZE_MAX = Component.translatable().key("gui.page_size_max");
TranslatableComponent.Builder GUI_PAGE_SIZE_MAX_NO_LESS_MIN = Component.translatable().key("gui.page_size_max_no_less_min");
}

View File

@@ -5,7 +5,123 @@ public class StandardLocales {
public static String COMPETITION_NO_PLAYER = "No Player";
public static String COMPETITION_NO_SCORE = "No Score";
public static String COMPETITION_NO_RANK = "No Rank";
public static String GOAL_TOTAL_SIZE;
public static String GOAL_CATCH_AMOUNT;
public static String GOAL_TOTAL_SCORE;
public static String GOAL_MAX_SIZE;
public static String FORMAT_SECOND = "s";
public static String FORMAT_MINUTE = "m";
public static String FORMAT_HOUR = "h";
public static String COMMAND_PREFIX;
public static String COMMAND_RELOAD;
public static String COMMAND_COMPETITION_NOT_EXISTS;
public static String COMMAND_N0_COMPETITION_ONGOING;
public static String COMMAND_END_COMPETITION;
public static String COMMAND_STOP_COMPETITION;
public static String COMMAND_ITEM_NOT_EXISTS;
public static String COMMAND_GET_ITEM;
public static String COMMAND_GIVE_ITEM;
public static String COMMAND_NEVER_PLAYED;
public static String COMMAND_UNSAFE_MODIFICATION;
public static String COMMAND_DATA_NOT_LOAD;
public static String COMMAND_MARKET_OPEN;
public static String COMMAND_FISHING_BAG_OPEN;
public static String COMMAND_POSSIBLE_LOOTS_SPLIT_CHAR;
public static String COMMAND_POSSIBLE_LOOTS;
public static String GUI_SCROLL_DOWN;
public static String GUI_SCROLL_UP;
public static String GUI_CANNOT_SCROLL_UP;
public static String GUI_CANNOT_SCROLL_DOWN;
public static String GUI_NEXT_PAGE;
public static String GUI_GOTO_NEXT_PAGE;
public static String GUI_CANNOT_GOTO_NEXT_PAGE;
public static String GUI_PREVIOUS_PAGE;
public static String GUI_GOTO_PREVIOUS_PAGE;
public static String GUI_CANNOT_GOTO_PREVIOUS_PAGE;
public static String GUI_BACK_TO_PARENT_PAGE;
public static String GUI_BACK_TO_PARENT_FOLDER;
public static String GUI_CURRENT_VALUE;
public static String GUI_CLICK_TO_TOGGLE;
public static String GUI_LEFT_CLICK_EDIT;
public static String GUI_RIGHT_CLICK_RESET;
public static String GUI_RIGHT_CLICK_DELETE;
public static String GUI_LOOT_SHOW_IN_FINDER;
public static String GUI_LOOT_SCORE;
public static String GUI_LOOT_NICK;
public static String GUI_LOOT_INSTANT_GAME;
public static String GUI_LOOT_DISABLE_STATS;
public static String GUI_LOOT_DISABLE_GAME;
public static String GUI_ITEM_AMOUNT;
public static String GUI_ITEM_MODEL_DATA;
public static String GUI_ITEM_DISPLAY_NAME;
public static String GUI_ITEM_DURABILITY;
public static String GUI_ITEM_ENCHANTMENT;
public static String GUI_ITEM_HEAD64;
public static String GUI_ITEM_FLAG;
public static String GUI_ITEM_LORE;
public static String GUI_ITEM_MATERIAL;
public static String GUI_ITEM_NBT;
public static String GUI_ITEM_PREVENT_GRAB;
public static String GUI_ITEM_PRICE;
public static String GUI_ITEM_PRICE_BASE;
public static String GUI_ITEM_PRICE_BONUS;
public static String GUI_ITEM_RANDOM_DURABILITY;
public static String GUI_ITEM_SIZE;
public static String GUI_ITEM_STACKABLE;
public static String GUI_ITEM_STORED_ENCHANTMENT;
public static String GUI_ITEM_TAG;
public static String GUI_ITEM_UNBREAKABLE;
public static String GUI_DELETE_PROPERTY;
public static String GUI_NEW_VALUE;
public static String GUI_CLICK_CONFIRM;
public static String GUI_INVALID_NUMBER;
public static String GUI_ILLEGAL_FORMAT;
public static String GUI_TITLE_AMOUNT;
public static String GUI_TITLE_MODEL_DATA;
public static String GUI_TITLE_DISPLAY_NAME;
public static String GUI_NEW_DISPLAY_NAME;
public static String GUI_TITLE_CUSTOM_DURABILITY;
public static String GUI_TITLE_ENCHANTMENT;
public static String GUI_TITLE_STORED_ENCHANTMENT;
public static String GUI_SELECT_ONE_ENCHANTMENT;
public static String GUI_ADD_NEW_ENCHANTMENT;
public static String GUI_TITLE_ITEM_FLAG;
public static String GUI_TITLE_LORE;
public static String GUI_ADD_NEW_LORE;
public static String GUI_SELECT_ONE_LORE;
public static String GUI_TITLE_MATERIAL;
public static String GUI_TITLE_NBT_COMPOUND;
public static String GUI_TITLE_NBT_LIST;
public static String GUI_TITLE_NBT_KEY;
public static String GUI_NBT_INVALID_KEY;
public static String GUI_RIGHT_CLICK_CANCEL;
public static String GUI_NBT_ADD_COMPOUND;
public static String GUI_NBT_ADD_LIST;
public static String GUI_NBT_ADD_VALUE;
public static String GUI_NBT_PREVIEW;
public static String GUI_NBT_BACK_TO_COMPOUND;
public static String GUI_NBT_SET_VALUE_TITLE;
public static String GUI_NBT_EDIT_TITLE;
public static String GUI_NICK_TITLE;
public static String GUI_NICK_NEW;
public static String GUI_PRICE_TITLE;
public static String GUI_PRICE_BASE;
public static String GUI_PRICE_BONUS;
public static String GUI_SCORE_TITLE;
public static String GUI_SIZE_TITLE;
public static String GUI_SIZE_MIN;
public static String GUI_SIZE_MAX;
public static String GUI_SIZE_MAX_NO_LESS;
public static String GUI_SELECT_FILE;
public static String GUI_SELECT_ITEM;
public static String GUI_ADD_NEW_KEY;
public static String GUI_DUPE_INVALID_KEY;
public static String GUI_SEARCH;
public static String GUI_TEMP_NEW_KEY;
public static String GUI_SET_NEW_KEY;
public static String GUI_EDIT_KEY;
}

View File

@@ -20,7 +20,7 @@ import java.util.stream.Stream;
public class TranslationManager {
public static final Locale DEFAULT_LOCALE = Locale.ENGLISH;
private static final List<String> locales = List.of("en");
private static final List<String> locales = List.of("en", "zh_cn");
private final CustomFishingPlugin plugin;
private final Set<Locale> installed = ConcurrentHashMap.newKeySet();
@@ -40,7 +40,7 @@ public class TranslationManager {
}
for (String lang : locales) {
this.plugin.getConfigManager().loadConfig("translations/" + lang + ".yml");
this.plugin.getConfigManager().saveResource("translations/" + lang + ".yml");
}
this.registry = MiniMessageTranslationRegistry.create(Key.key("customfishing", "main"), AdventureHelper.getMiniMessage());

View File

@@ -8,6 +8,7 @@ repositories {
maven("https://repo.oraxen.com/releases/") // oraxen
maven("https://repo.auxilor.io/repository/maven-public/") // eco
maven("https://nexus.betonquest.org/repository/betonquest/") // betonquest
maven("https://repo.dmulloy2.net/repository/public/") // betonquest needs packet wrapper?
}
dependencies {
@@ -48,7 +49,7 @@ dependencies {
compileOnly("net.Indyuce:MMOItems-API:6.10-SNAPSHOT")
compileOnly("io.lumine:MythicLib-dist:1.6.2-SNAPSHOT")
compileOnly("pers.neige.neigeitems:NeigeItems:1.17.13")
compileOnly("io.th0rgal:oraxen:1.175.0")
compileOnly("io.th0rgal:oraxen:1.168.0")
// entity
compileOnly("io.lumine:Mythic-Dist:5.6.2")
// eco

View File

@@ -17,10 +17,10 @@
package net.momirealms.customfishing.bukkit.integration.item;
import net.kyori.adventure.key.Key;
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
import net.momirealms.customfishing.api.integration.ItemProvider;
import net.momirealms.customfishing.api.mechanic.context.Context;
import net.momirealms.customfishing.common.util.Key;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
@@ -38,7 +38,13 @@ public class CustomFishingItemProvider implements ItemProvider {
@Override
public ItemStack buildItem(@NotNull Player player, @NotNull String id) {
String[] split = id.split(":", 2);
ItemStack itemStack = BukkitCustomFishingPlugin.getInstance().getItemManager().buildInternal(Context.player(player), Key.key(split[0], split[1]));
String finalID;
if (split.length != 2) {
finalID = split[0];
} else {
finalID = split[1];
}
ItemStack itemStack = BukkitCustomFishingPlugin.getInstance().getItemManager().buildInternal(Context.player(player), finalID);
return requireNonNull(itemStack);
}

View File

@@ -1,144 +1,144 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customfishing.bukkit.integration.papi;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
import net.momirealms.customfishing.api.mechanic.competition.FishingCompetition;
import org.bukkit.OfflinePlayer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Optional;
public class CompetitionPapi extends PlaceholderExpansion {
private final BukkitCustomFishingPlugin plugin;
public CompetitionPapi(BukkitCustomFishingPlugin plugin) {
this.plugin = plugin;
}
public void load() {
super.register();
}
public void unload() {
super.unregister();
}
@Override
public @NotNull String getIdentifier() {
return "cfcompetition";
}
@Override
public @NotNull String getAuthor() {
return "XiaoMoMi";
}
@Override
public @NotNull String getVersion() {
return "2.0";
}
@Override
public boolean persist() {
return true;
}
@Override
public @Nullable String onRequest(OfflinePlayer player, @NotNull String params) {
switch (params) {
case "goingon" -> {
return String.valueOf(plugin.getCompetitionManager().getOnGoingCompetition() != null);
}
case "nextseconds" -> {
return String.valueOf(plugin.getCompetitionManager().getNextCompetitionInSeconds());
}
case "nextsecond" -> {
return plugin.getCompetitionManager().getNextCompetitionInSeconds() % 60 + CFLocale.FORMAT_Second;
}
case "nextminute" -> {
int sec = plugin.getCompetitionManager().getNextCompetitionInSeconds();
int min = (sec % 3600) / 60;
return sec < 60 ? "" : min + CFLocale.FORMAT_Minute;
}
case "nexthour" -> {
int sec = plugin.getCompetitionManager().getNextCompetitionInSeconds();
int h = (sec % (3600 * 24)) / 3600;
return sec < 3600 ? "" : h + CFLocale.FORMAT_Hour;
}
case "nextday" -> {
int sec = plugin.getCompetitionManager().getNextCompetitionInSeconds();
int day = sec / (3600 * 24);
return day == 0 ? "" : day + CFLocale.FORMAT_Day;
}
case "rank" -> {
FishingCompetition competition = plugin.getCompetitionManager().getOnGoingCompetition();
if (competition == null) return "";
else return String.valueOf(competition.getRanking().getPlayerRank(player.getName()));
}
case "goal" -> {
FishingCompetition competition = plugin.getCompetitionManager().getOnGoingCompetition();
if (competition == null) return "";
else return competition.getGoal().name();
}
case "seconds" -> {
FishingCompetition competition = plugin.getCompetitionManager().getOnGoingCompetition();
if (competition == null) return "";
return competition.getCachedPlaceholder("{seconds}");
}
case "second" -> {
FishingCompetition competition = plugin.getCompetitionManager().getOnGoingCompetition();
if (competition == null) return "";
return competition.getCachedPlaceholder("{second}");
}
case "minute" -> {
FishingCompetition competition = plugin.getCompetitionManager().getOnGoingCompetition();
if (competition == null) return "";
return competition.getCachedPlaceholder("{minute}");
}
case "hour" -> {
FishingCompetition competition = plugin.getCompetitionManager().getOnGoingCompetition();
if (competition == null) return "";
return competition.getCachedPlaceholder("{hour}");
}
}
String[] split = params.split("_", 2);
switch (split[0]) {
case "score" -> {
FishingCompetition competition = plugin.getCompetitionManager().getOnGoingCompetition();
if (competition == null) return "";
if (split.length == 1) {
return String.format("%.2f", competition.getRanking().getPlayerScore(player.getName()));
} else {
return String.format("%.2f", competition.getRanking().getScoreAt(Integer.parseInt(split[1])));
}
}
case "player" -> {
FishingCompetition competition = plugin.getCompetitionManager().getOnGoingCompetition();
if (competition == null) return "";
if (split.length == 1) return "Invalid format";
return Optional.ofNullable(competition.getRanking().getPlayerAt(Integer.parseInt(split[1]))).orElse("");
}
}
return "null";
}
}
///*
// * Copyright (C) <2022> <XiaoMoMi>
// *
// * This program is free software: you can redistribute it and/or modify
// * it under the terms of the GNU General Public License as published by
// * the Free Software Foundation, either version 3 of the License, or
// * any later version.
// *
// * This program is distributed in the hope that it will be useful,
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// * GNU General Public License for more details.
// *
// * You should have received a copy of the GNU General Public License
// * along with this program. If not, see <https://www.gnu.org/licenses/>.
// */
//
//package net.momirealms.customfishing.bukkit.integration.papi;
//
//import me.clip.placeholderapi.expansion.PlaceholderExpansion;
//import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
//import net.momirealms.customfishing.api.mechanic.competition.FishingCompetition;
//import org.bukkit.OfflinePlayer;
//import org.jetbrains.annotations.NotNull;
//import org.jetbrains.annotations.Nullable;
//
//import java.util.Optional;
//
//public class CompetitionPapi extends PlaceholderExpansion {
//
// private final BukkitCustomFishingPlugin plugin;
//
// public CompetitionPapi(BukkitCustomFishingPlugin plugin) {
// this.plugin = plugin;
// }
//
// public void load() {
// super.register();
// }
//
// public void unload() {
// super.unregister();
// }
//
// @Override
// public @NotNull String getIdentifier() {
// return "cfcompetition";
// }
//
// @Override
// public @NotNull String getAuthor() {
// return "XiaoMoMi";
// }
//
// @Override
// public @NotNull String getVersion() {
// return "2.0";
// }
//
// @Override
// public boolean persist() {
// return true;
// }
//
// @Override
// public @Nullable String onRequest(OfflinePlayer player, @NotNull String params) {
// switch (params) {
// case "goingon" -> {
// return String.valueOf(plugin.getCompetitionManager().getOnGoingCompetition() != null);
// }
// case "nextseconds" -> {
// return String.valueOf(plugin.getCompetitionManager().getNextCompetitionInSeconds());
// }
// case "nextsecond" -> {
// return plugin.getCompetitionManager().getNextCompetitionInSeconds() % 60 + CFLocale.FORMAT_Second;
// }
// case "nextminute" -> {
// int sec = plugin.getCompetitionManager().getNextCompetitionInSeconds();
// int min = (sec % 3600) / 60;
// return sec < 60 ? "" : min + CFLocale.FORMAT_Minute;
// }
// case "nexthour" -> {
// int sec = plugin.getCompetitionManager().getNextCompetitionInSeconds();
// int h = (sec % (3600 * 24)) / 3600;
// return sec < 3600 ? "" : h + CFLocale.FORMAT_Hour;
// }
// case "nextday" -> {
// int sec = plugin.getCompetitionManager().getNextCompetitionInSeconds();
// int day = sec / (3600 * 24);
// return day == 0 ? "" : day + CFLocale.FORMAT_Day;
// }
// case "rank" -> {
// FishingCompetition competition = plugin.getCompetitionManager().getOnGoingCompetition();
// if (competition == null) return "";
// else return String.valueOf(competition.getRanking().getPlayerRank(player.getName()));
// }
// case "goal" -> {
// FishingCompetition competition = plugin.getCompetitionManager().getOnGoingCompetition();
// if (competition == null) return "";
// else return competition.getGoal().name();
// }
// case "seconds" -> {
// FishingCompetition competition = plugin.getCompetitionManager().getOnGoingCompetition();
// if (competition == null) return "";
// return competition.getCachedPlaceholder("{seconds}");
// }
// case "second" -> {
// FishingCompetition competition = plugin.getCompetitionManager().getOnGoingCompetition();
// if (competition == null) return "";
// return competition.getCachedPlaceholder("{second}");
// }
// case "minute" -> {
// FishingCompetition competition = plugin.getCompetitionManager().getOnGoingCompetition();
// if (competition == null) return "";
// return competition.getCachedPlaceholder("{minute}");
// }
// case "hour" -> {
// FishingCompetition competition = plugin.getCompetitionManager().getOnGoingCompetition();
// if (competition == null) return "";
// return competition.getCachedPlaceholder("{hour}");
// }
// }
//
// String[] split = params.split("_", 2);
// switch (split[0]) {
// case "score" -> {
// FishingCompetition competition = plugin.getCompetitionManager().getOnGoingCompetition();
// if (competition == null) return "";
// if (split.length == 1) {
// return String.format("%.2f", competition.getRanking().getPlayerScore(player.getName()));
// } else {
// return String.format("%.2f", competition.getRanking().getScoreAt(Integer.parseInt(split[1])));
// }
// }
// case "player" -> {
// FishingCompetition competition = plugin.getCompetitionManager().getOnGoingCompetition();
// if (competition == null) return "";
// if (split.length == 1) return "Invalid format";
// return Optional.ofNullable(competition.getRanking().getPlayerAt(Integer.parseInt(split[1]))).orElse("");
// }
// }
// return "null";
// }
//}

View File

@@ -1,126 +1,126 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customfishing.bukkit.integration.papi;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class CustomFishingPapi extends PlaceholderExpansion {
private final BukkitCustomFishingPlugin plugin;
public CustomFishingPapi(BukkitCustomFishingPlugin plugin) {
this.plugin = plugin;
}
public void load() {
super.register();
}
public void unload() {
super.unregister();
}
@Override
public @NotNull String getIdentifier() {
return "customfishing";
}
@Override
public @NotNull String getAuthor() {
return "XiaoMoMi";
}
@Override
public @NotNull String getVersion() {
return "2.0";
}
@Override
public boolean persist() {
return true;
}
@Override
public @Nullable String onRequest(OfflinePlayer offlinePlayer, @NotNull String params) {
String[] split = params.split("_");
Player player = offlinePlayer.getPlayer();
if (player == null)
return "";
switch (split[0]) {
case "market" -> {
if (split.length < 2)
return null;
switch (split[1]) {
case "limit" -> {
if (split.length < 3) {
return String.format("%.2f", plugin.getMarketManager().earningLimit(player));
} else {
Player another = Bukkit.getPlayer(split[2]);
if (another == null) {
return "";
}
return String.format("%.2f", plugin.getMarketManager().earningLimit(another));
}
}
case "earnings" -> {
OnlineUserData user;
if (split.length < 3) {
user = plugin.getStorageManager().getOnlineUser(player.getUniqueId());
} else {
Player another = Bukkit.getPlayer(split[2]);
if (another == null) {
return "";
}
user = plugin.getStorageManager().getOnlineUser(another.getUniqueId());
}
if (user == null)
return "";
return String.format("%.2f", user.getEarningData().earnings);
}
case "canearn" -> {
if (split.length < 3) {
OnlineUserData user = plugin.getStorageManager().getOnlineUser(player.getUniqueId());
if (user == null)
return "";
return String.format("%.2f", plugin.getMarketManager().earningLimit(player) - user.getEarningData().earnings);
} else {
Player another = Bukkit.getPlayer(split[2]);
if (another == null) {
return "";
}
OnlineUserData user = plugin.getStorageManager().getOnlineUser(another.getUniqueId());
if (user == null)
return "";
return String.format("%.2f", plugin.getMarketManager().earningLimit(another) - user.getEarningData().earnings);
}
}
}
}
}
return null;
}
}
///*
// * Copyright (C) <2022> <XiaoMoMi>
// *
// * This program is free software: you can redistribute it and/or modify
// * it under the terms of the GNU General Public License as published by
// * the Free Software Foundation, either version 3 of the License, or
// * any later version.
// *
// * This program is distributed in the hope that it will be useful,
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// * GNU General Public License for more details.
// *
// * You should have received a copy of the GNU General Public License
// * along with this program. If not, see <https://www.gnu.org/licenses/>.
// */
//
//package net.momirealms.customfishing.bukkit.integration.papi;
//
//import me.clip.placeholderapi.expansion.PlaceholderExpansion;
//import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
//import org.bukkit.Bukkit;
//import org.bukkit.OfflinePlayer;
//import org.bukkit.entity.Player;
//import org.jetbrains.annotations.NotNull;
//import org.jetbrains.annotations.Nullable;
//
//public class CustomFishingPapi extends PlaceholderExpansion {
//
// private final BukkitCustomFishingPlugin plugin;
//
// public CustomFishingPapi(BukkitCustomFishingPlugin plugin) {
// this.plugin = plugin;
// }
//
// public void load() {
// super.register();
// }
//
// public void unload() {
// super.unregister();
// }
//
// @Override
// public @NotNull String getIdentifier() {
// return "customfishing";
// }
//
// @Override
// public @NotNull String getAuthor() {
// return "XiaoMoMi";
// }
//
// @Override
// public @NotNull String getVersion() {
// return "2.0";
// }
//
// @Override
// public boolean persist() {
// return true;
// }
//
// @Override
// public @Nullable String onRequest(OfflinePlayer offlinePlayer, @NotNull String params) {
// String[] split = params.split("_");
//
// Player player = offlinePlayer.getPlayer();
// if (player == null)
// return "";
//
// switch (split[0]) {
// case "market" -> {
// if (split.length < 2)
// return null;
// switch (split[1]) {
// case "limit" -> {
// if (split.length < 3) {
// return String.format("%.2f", plugin.getMarketManager().earningLimit(player));
// } else {
// Player another = Bukkit.getPlayer(split[2]);
// if (another == null) {
// return "";
// }
// return String.format("%.2f", plugin.getMarketManager().earningLimit(another));
// }
// }
// case "earnings" -> {
// OnlineUserData user;
// if (split.length < 3) {
// user = plugin.getStorageManager().getOnlineUser(player.getUniqueId());
// } else {
// Player another = Bukkit.getPlayer(split[2]);
// if (another == null) {
// return "";
// }
// user = plugin.getStorageManager().getOnlineUser(another.getUniqueId());
// }
// if (user == null)
// return "";
// return String.format("%.2f", user.getEarningData().earnings);
// }
// case "canearn" -> {
// if (split.length < 3) {
// OnlineUserData user = plugin.getStorageManager().getOnlineUser(player.getUniqueId());
// if (user == null)
// return "";
// return String.format("%.2f", plugin.getMarketManager().earningLimit(player) - user.getEarningData().earnings);
// } else {
// Player another = Bukkit.getPlayer(split[2]);
// if (another == null) {
// return "";
// }
//
// OnlineUserData user = plugin.getStorageManager().getOnlineUser(another.getUniqueId());
// if (user == null)
// return "";
// return String.format("%.2f", plugin.getMarketManager().earningLimit(another) - user.getEarningData().earnings);
// }
// }
// }
// }
// }
// return null;
// }
//}

View File

@@ -1,112 +1,112 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customfishing.bukkit.integration.papi;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
import org.bukkit.OfflinePlayer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public class StatisticsPapi extends PlaceholderExpansion {
private final BukkitCustomFishingPlugin plugin;
public StatisticsPapi(BukkitCustomFishingPlugin plugin) {
this.plugin = plugin;
}
public void load() {
super.register();
}
public void unload() {
super.unregister();
}
@Override
public @NotNull String getIdentifier() {
return "fishingstats";
}
@Override
public @NotNull String getAuthor() {
return "XiaoMoMi";
}
@Override
public @NotNull String getVersion() {
return "2.0";
}
@Override
public boolean persist() {
return true;
}
@Override
public @Nullable String onRequest(OfflinePlayer player, @NotNull String params) {
OnlineUserData onlineUser = plugin.getStorageManager().getOnlineUser(player.getUniqueId());
if (onlineUser == null) return "Data not loaded";
Statistics statistics = onlineUser.getStatistics();
String[] split = params.split("_", 2);
switch (split[0]) {
case "total" -> {
return String.valueOf(statistics.getTotalCatchAmount());
}
case "hascaught" -> {
if (split.length == 1) return "Invalid format";
return String.valueOf(statistics.getLootAmount(split[1]) != 0);
}
case "amount" -> {
if (split.length == 1) return "Invalid format";
return String.valueOf(statistics.getLootAmount(split[1]));
}
case "size-record" -> {
return String.format("%.2f", statistics.getSizeRecord(split[1]));
}
case "category" -> {
if (split.length == 1) return "Invalid format";
String[] categorySplit = split[1].split("_", 2);
if (categorySplit.length == 1) return "Invalid format";
List<String> category = plugin.getStatisticsManager().getCategory(categorySplit[1]);
if (category == null) return "Category Not Exists";
if (categorySplit[0].equals("total")) {
int total = 0;
for (String loot : category) {
total += statistics.getLootAmount(loot);
}
return String.valueOf(total);
} else if (categorySplit[0].equals("progress")) {
int size = category.size();
int unlocked = 0;
for (String loot : category) {
if (statistics.getLootAmount(loot) != 0) unlocked++;
}
double percent = ((double) unlocked * 100) / size;
String progress = String.format("%.1f", percent);
return progress.equals("100.0") ? "100" : progress;
}
}
}
return "null";
}
}
///*
// * Copyright (C) <2022> <XiaoMoMi>
// *
// * This program is free software: you can redistribute it and/or modify
// * it under the terms of the GNU General Public License as published by
// * the Free Software Foundation, either version 3 of the License, or
// * any later version.
// *
// * This program is distributed in the hope that it will be useful,
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// * GNU General Public License for more details.
// *
// * You should have received a copy of the GNU General Public License
// * along with this program. If not, see <https://www.gnu.org/licenses/>.
// */
//
//package net.momirealms.customfishing.bukkit.integration.papi;
//
//import me.clip.placeholderapi.expansion.PlaceholderExpansion;
//import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
//import org.bukkit.OfflinePlayer;
//import org.jetbrains.annotations.NotNull;
//import org.jetbrains.annotations.Nullable;
//
//import java.util.List;
//
//public class StatisticsPapi extends PlaceholderExpansion {
//
// private final BukkitCustomFishingPlugin plugin;
//
// public StatisticsPapi(BukkitCustomFishingPlugin plugin) {
// this.plugin = plugin;
// }
//
// public void load() {
// super.register();
// }
//
// public void unload() {
// super.unregister();
// }
//
// @Override
// public @NotNull String getIdentifier() {
// return "fishingstats";
// }
//
// @Override
// public @NotNull String getAuthor() {
// return "XiaoMoMi";
// }
//
// @Override
// public @NotNull String getVersion() {
// return "2.0";
// }
//
// @Override
// public boolean persist() {
// return true;
// }
//
// @Override
// public @Nullable String onRequest(OfflinePlayer player, @NotNull String params) {
// OnlineUserData onlineUser = plugin.getStorageManager().getOnlineUser(player.getUniqueId());
// if (onlineUser == null) return "Data not loaded";
// Statistics statistics = onlineUser.getStatistics();
// String[] split = params.split("_", 2);
// switch (split[0]) {
// case "total" -> {
// return String.valueOf(statistics.getTotalCatchAmount());
// }
// case "hascaught" -> {
// if (split.length == 1) return "Invalid format";
// return String.valueOf(statistics.getLootAmount(split[1]) != 0);
// }
// case "amount" -> {
// if (split.length == 1) return "Invalid format";
// return String.valueOf(statistics.getLootAmount(split[1]));
// }
// case "size-record" -> {
// return String.format("%.2f", statistics.getSizeRecord(split[1]));
// }
// case "category" -> {
// if (split.length == 1) return "Invalid format";
// String[] categorySplit = split[1].split("_", 2);
// if (categorySplit.length == 1) return "Invalid format";
// List<String> category = plugin.getStatisticsManager().getCategory(categorySplit[1]);
// if (category == null) return "Category Not Exists";
// if (categorySplit[0].equals("total")) {
// int total = 0;
// for (String loot : category) {
// total += statistics.getLootAmount(loot);
// }
// return String.valueOf(total);
// } else if (categorySplit[0].equals("progress")) {
// int size = category.size();
// int unlocked = 0;
// for (String loot : category) {
// if (statistics.getLootAmount(loot) != 0) unlocked++;
// }
// double percent = ((double) unlocked * 100) / size;
// String progress = String.format("%.1f", percent);
// return progress.equals("100.0") ? "100" : progress;
// }
// }
// }
//
// return "null";
// }
//}

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

@@ -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>"

View File

@@ -1,7 +1,7 @@
# Project settings
# Rule: [major update].[feature update].[bug fix]
project_version=1.7.1
config_version=2
project_version=2.2.0
config_version=32
project_group=net.momirealms
# Dependency settings