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.requirement.RequirementManager;
import net.momirealms.customfishing.api.mechanic.statistic.StatisticsManager; import net.momirealms.customfishing.api.mechanic.statistic.StatisticsManager;
import net.momirealms.customfishing.api.storage.StorageManager; 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.CustomFishingPlugin;
import net.momirealms.customfishing.common.plugin.feature.Reloadable;
import net.momirealms.customfishing.common.plugin.scheduler.AbstractJavaScheduler; import net.momirealms.customfishing.common.plugin.scheduler.AbstractJavaScheduler;
import net.momirealms.customfishing.common.sender.SenderFactory; import net.momirealms.customfishing.common.sender.SenderFactory;
import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@@ -46,12 +48,10 @@ import org.bukkit.plugin.Plugin;
import java.io.File; import java.io.File;
import static java.util.Objects.requireNonNull; public abstract class BukkitCustomFishingPlugin implements CustomFishingPlugin, Reloadable {
public abstract class BukkitCustomFishingPlugin implements CustomFishingPlugin {
private static BukkitCustomFishingPlugin instance; private static BukkitCustomFishingPlugin instance;
private final Plugin boostrap = requireNonNull(Bukkit.getPluginManager().getPlugin("CustomFishing")); private final Plugin boostrap;
protected EventManager eventManager; protected EventManager eventManager;
protected ConfigManager configManager; protected ConfigManager configManager;
@@ -73,13 +73,20 @@ public abstract class BukkitCustomFishingPlugin implements CustomFishingPlugin {
protected EffectManager effectManager; protected EffectManager effectManager;
protected HookManager hookManager; protected HookManager hookManager;
protected BagManager bagManager; 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; instance = this;
} }
public static BukkitCustomFishingPlugin getInstance() { public static BukkitCustomFishingPlugin getInstance() {
if (instance == null) { if (instance == null || !instance.initialized) {
throw new IllegalArgumentException("Plugin not initialized"); throw new IllegalArgumentException("Plugin not initialized");
} }
return instance; return instance;
@@ -175,7 +182,15 @@ public abstract class BukkitCustomFishingPlugin implements CustomFishingPlugin {
return boostrap; 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; 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.effect.Effect;
import net.momirealms.customfishing.api.mechanic.fishing.FishingPreparation;
import org.bukkit.event.Cancellable; import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList; import org.bukkit.event.HandlerList;
import org.bukkit.event.player.PlayerEvent; import org.bukkit.event.player.PlayerEvent;

View File

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

View File

@@ -19,6 +19,7 @@ package net.momirealms.customfishing.api.mechanic.action;
import dev.dejvokep.boostedyaml.block.implementation.Section; import dev.dejvokep.boostedyaml.block.implementation.Section;
import net.momirealms.customfishing.api.mechanic.context.Context; 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.NotNull;
import org.jetbrains.annotations.Nullable; 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. * @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. * Registers a custom action type with its corresponding factory.

View File

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

View File

@@ -17,9 +17,10 @@
package net.momirealms.customfishing.api.mechanic.competition; package net.momirealms.customfishing.api.mechanic.competition;
import net.momirealms.customfishing.common.plugin.feature.Reloadable;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
public interface CompetitionManager { public interface CompetitionManager extends Reloadable {
boolean startCompetition(String competition, boolean force, @Nullable String serverGroup); 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() { 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) { 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 * @return the horizontal vector value as a double
*/ */
MathValue<Player> getHorizontalVector(); MathValue<Player> horizontalVector();
/** /**
* Retrieves the vertical vector value for the entity. * Retrieves the vertical vector value for the entity.
* *
* @return the vertical vector value as a double * @return the vertical vector value as a double
*/ */
MathValue<Player> getVerticalVector(); MathValue<Player> verticalVector();
/** /**
* Retrieves the unique identifier for the entity. * Retrieves the unique identifier for the entity.
@@ -57,7 +57,7 @@ public interface EntityConfig {
* @return the entity ID as a non-null String * @return the entity ID as a non-null String
*/ */
@NotNull @NotNull
String getEntityID(); String entityID();
/** /**
* Retrieves a map of properties associated with the entity. * 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 * @return a non-null map where keys are property names and values are property values
*/ */
@NotNull @NotNull
Map<String, Object> getPropertyMap(); Map<String, Object> propertyMap();
/** /**
* Creates a new Builder instance for constructing an EntityConfig. * Creates a new Builder instance for constructing an EntityConfig.

View File

@@ -45,24 +45,24 @@ public class EntityConfigImpl implements EntityConfig {
} }
@Override @Override
public MathValue<Player> getHorizontalVector() { public MathValue<Player> horizontalVector() {
return horizontalVector; return horizontalVector;
} }
@Override @Override
public MathValue<Player> getVerticalVector() { public MathValue<Player> verticalVector() {
return verticalVector; return verticalVector;
} }
@NotNull @NotNull
@Override @Override
public String getEntityID() { public String entityID() {
return entityID; return entityID;
} }
@NotNull @NotNull
@Override @Override
public Map<String, Object> getPropertyMap() { public Map<String, Object> propertyMap() {
return 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 { public abstract class AbstractGamingPlayer implements GamingPlayer, Runnable {
private final FishingManager manager; // private final FishingManager manager;
protected long deadline; protected long deadline;
protected boolean success; protected boolean success;
protected SchedulerTask task; protected SchedulerTask task;
@@ -43,7 +43,7 @@ public abstract class AbstractGamingPlayer implements GamingPlayer, Runnable {
this.player = player; this.player = player;
this.fishHook = hook; this.fishHook = hook;
this.settings = settings; this.settings = settings;
this.manager = BukkitCustomFishingPlugin.getFishingManager(); // this.manager = BukkitCustomFishingPlugin.getInstance().get();
this.deadline = (long) (System.currentTimeMillis() + settings.time() * 1000L); this.deadline = (long) (System.currentTimeMillis() + settings.time() * 1000L);
this.arrangeTask(); this.arrangeTask();
} }
@@ -119,7 +119,7 @@ public abstract class AbstractGamingPlayer implements GamingPlayer, Runnable {
} }
protected void endGame() { protected void endGame() {
this.manager.processGameResult(this); // this.manager.processGameResult(this);
} }
protected void setGameResult(boolean success) { protected void setGameResult(boolean success) {

View File

@@ -17,11 +17,12 @@
package net.momirealms.customfishing.api.mechanic.hook; package net.momirealms.customfishing.api.mechanic.hook;
import net.momirealms.customfishing.common.plugin.feature.Reloadable;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.Optional; import java.util.Optional;
public interface HookManager { public interface HookManager extends Reloadable {
boolean registerHook(HookConfig hook); 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.context.Context;
import net.momirealms.customfishing.api.mechanic.effect.Effect; import net.momirealms.customfishing.api.mechanic.effect.Effect;
import net.momirealms.customfishing.common.plugin.feature.Reloadable;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -27,7 +28,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
public interface LootManager { public interface LootManager extends Reloadable {
void registerLoot(@NotNull Loot loot); void registerLoot(@NotNull Loot loot);

View File

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

View File

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

View File

@@ -17,6 +17,7 @@
package net.momirealms.customfishing.api.mechanic.misc.placeholder; package net.momirealms.customfishing.api.mechanic.misc.placeholder;
import net.momirealms.customfishing.common.plugin.feature.Reloadable;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -24,7 +25,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.regex.Pattern; import java.util.regex.Pattern;
public interface PlaceholderManager { public interface PlaceholderManager extends Reloadable {
Pattern PATTERN = Pattern.compile("\\{[^{}]+}"); 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 dev.dejvokep.boostedyaml.block.implementation.Section;
import net.momirealms.customfishing.api.mechanic.context.Context; 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.NotNull;
import org.jetbrains.annotations.Nullable; 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. * @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. * 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.data.PlayerData;
import net.momirealms.customfishing.api.storage.user.UserData; import net.momirealms.customfishing.api.storage.user.UserData;
import net.momirealms.customfishing.common.plugin.feature.Reloadable;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.Collection; import java.util.Collection;
@@ -26,7 +27,7 @@ import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
public interface StorageManager { public interface StorageManager extends Reloadable {
@NotNull @NotNull
String getServerID(); String getServerID();
@@ -52,7 +53,7 @@ public interface StorageManager {
* @param data The PlayerData to be converted. * @param data The PlayerData to be converted.
* @return The byte array representation of PlayerData. * @return The byte array representation of PlayerData.
*/ */
byte @NotNull [] toBytes(@NotNull PlayerData data); byte[] toBytes(@NotNull PlayerData data);
/** /**
* Converts PlayerData to JSON format. * 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 name: CustomFishing
version: '${version}' version: '${project_version}'
main: net.momirealms.customfishing.CustomFishingPluginImpl main: net.momirealms.customfishing.bukkit.BukkitBootstrap
api-version: 1.17 api-version: 1.17
authors: [ XiaoMoMi ] authors: [ XiaoMoMi ]
folia-supported: true folia-supported: true
depend:
- ProtocolLib
softdepend: softdepend:
- Vault - Vault
- PlaceholderAPI - PlaceholderAPI

View File

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

View File

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

View File

@@ -17,126 +17,25 @@
package net.momirealms.customfishing.common.helper; package net.momirealms.customfishing.common.helper;
import net.momirealms.customfishing.common.plugin.CustomFishingPlugin;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.net.URL; import java.net.URL;
import java.net.URLConnection; import java.net.URLConnection;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
/** /**
* This class implements the VersionManager interface and is responsible for managing version-related information. * This class implements the VersionManager interface and is responsible for managing version-related information.
*/ */
public class VersionHelper { 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 // Method to asynchronously check for plugin updates
@Override public static final Function<CustomFishingPlugin, CompletableFuture<Boolean>> UPDATE_CHECKER = (plugin) -> {
public CompletableFuture<Boolean> checkUpdate() {
CompletableFuture<Boolean> updateFuture = new CompletableFuture<>(); CompletableFuture<Boolean> updateFuture = new CompletableFuture<>();
plugin.getScheduler().async(() -> { plugin.getScheduler().async().execute(() -> {
try { try {
URL url = new URL("https://api.polymart.org/v1/getResourceInfoSimple/?resource_id=2723&key=version"); URL url = new URL("https://api.polymart.org/v1/getResourceInfoSimple/?resource_id=2723&key=version");
URLConnection conn = url.openConnection(); URLConnection conn = url.openConnection();
@@ -144,7 +43,7 @@ public class VersionHelper {
conn.setReadTimeout(60000); conn.setReadTimeout(60000);
InputStream inputStream = conn.getInputStream(); InputStream inputStream = conn.getInputStream();
String newest = new BufferedReader(new InputStreamReader(inputStream)).readLine(); String newest = new BufferedReader(new InputStreamReader(inputStream)).readLine();
String current = plugin.getVersionManager().getPluginVersion(); String current = plugin.getPluginVersion();
inputStream.close(); inputStream.close();
if (!compareVer(newest, current)) { if (!compareVer(newest, current)) {
updateFuture.complete(false); updateFuture.complete(false);
@@ -152,15 +51,71 @@ public class VersionHelper {
} }
updateFuture.complete(true); updateFuture.complete(true);
} catch (Exception exception) { } catch (Exception exception) {
LogUtils.warn("Error occurred when checking update.", exception); plugin.getPluginLogger().warn("Error occurred when checking update.", exception);
updateFuture.complete(false); updateFuture.complete(false);
} }
}); });
return updateFuture; 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 // 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()) { if (newV == null || currentV == null || newV.isEmpty() || currentV.isEmpty()) {
return false; return false;
} }

View File

@@ -5,5 +5,112 @@ import net.kyori.adventure.text.TranslatableComponent;
public interface MessageConstants { 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_PLAYER = "No Player";
public static String COMPETITION_NO_SCORE = "No Score"; public static String COMPETITION_NO_SCORE = "No Score";
public static String COMPETITION_NO_RANK = "No Rank"; 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_SECOND = "s";
public static String FORMAT_MINUTE = "m"; public static String FORMAT_MINUTE = "m";
public static String FORMAT_HOUR = "h"; 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 class TranslationManager {
public static final Locale DEFAULT_LOCALE = Locale.ENGLISH; 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 CustomFishingPlugin plugin;
private final Set<Locale> installed = ConcurrentHashMap.newKeySet(); private final Set<Locale> installed = ConcurrentHashMap.newKeySet();
@@ -40,7 +40,7 @@ public class TranslationManager {
} }
for (String lang : locales) { 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()); 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.oraxen.com/releases/") // oraxen
maven("https://repo.auxilor.io/repository/maven-public/") // eco maven("https://repo.auxilor.io/repository/maven-public/") // eco
maven("https://nexus.betonquest.org/repository/betonquest/") // betonquest maven("https://nexus.betonquest.org/repository/betonquest/") // betonquest
maven("https://repo.dmulloy2.net/repository/public/") // betonquest needs packet wrapper?
} }
dependencies { dependencies {
@@ -48,7 +49,7 @@ dependencies {
compileOnly("net.Indyuce:MMOItems-API:6.10-SNAPSHOT") compileOnly("net.Indyuce:MMOItems-API:6.10-SNAPSHOT")
compileOnly("io.lumine:MythicLib-dist:1.6.2-SNAPSHOT") compileOnly("io.lumine:MythicLib-dist:1.6.2-SNAPSHOT")
compileOnly("pers.neige.neigeitems:NeigeItems:1.17.13") compileOnly("pers.neige.neigeitems:NeigeItems:1.17.13")
compileOnly("io.th0rgal:oraxen:1.175.0") compileOnly("io.th0rgal:oraxen:1.168.0")
// entity // entity
compileOnly("io.lumine:Mythic-Dist:5.6.2") compileOnly("io.lumine:Mythic-Dist:5.6.2")
// eco // eco

View File

@@ -17,10 +17,10 @@
package net.momirealms.customfishing.bukkit.integration.item; package net.momirealms.customfishing.bukkit.integration.item;
import net.kyori.adventure.key.Key;
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin; import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
import net.momirealms.customfishing.api.integration.ItemProvider; import net.momirealms.customfishing.api.integration.ItemProvider;
import net.momirealms.customfishing.api.mechanic.context.Context; import net.momirealms.customfishing.api.mechanic.context.Context;
import net.momirealms.customfishing.common.util.Key;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -38,7 +38,13 @@ public class CustomFishingItemProvider implements ItemProvider {
@Override @Override
public ItemStack buildItem(@NotNull Player player, @NotNull String id) { public ItemStack buildItem(@NotNull Player player, @NotNull String id) {
String[] split = id.split(":", 2); 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); return requireNonNull(itemStack);
} }

View File

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

View File

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

View File

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

View File

@@ -47,6 +47,8 @@ dependencies {
compileOnly("org.incendo:cloud-core:${rootProject.properties["cloud_core_version"]}") 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-minecraft-extras:${rootProject.properties["cloud_minecraft_extras_version"]}")
compileOnly("org.incendo:cloud-paper:${rootProject.properties["cloud_paper_version"]}") compileOnly("org.incendo:cloud-paper:${rootProject.properties["cloud_paper_version"]}")
// expression
compileOnly("net.objecthunter:exp4j:${rootProject.properties["exp4j_version"]}")
} }
tasks { 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.misc.value.TextValue;
import net.momirealms.customfishing.api.mechanic.requirement.Requirement; import net.momirealms.customfishing.api.mechanic.requirement.Requirement;
import net.momirealms.customfishing.bukkit.integration.VaultHook; import net.momirealms.customfishing.bukkit.integration.VaultHook;
import net.momirealms.customfishing.bukkit.util.ItemUtils;
import net.momirealms.customfishing.bukkit.util.LocationUtils; import net.momirealms.customfishing.bukkit.util.LocationUtils;
import net.momirealms.customfishing.bukkit.util.PlayerUtils; import net.momirealms.customfishing.bukkit.util.PlayerUtils;
import net.momirealms.customfishing.common.helper.AdventureHelper; import net.momirealms.customfishing.common.helper.AdventureHelper;
@@ -52,6 +51,16 @@ public class BukkitActionManager implements ActionManager<Player> {
public BukkitActionManager(BukkitCustomFishingPlugin plugin) { public BukkitActionManager(BukkitCustomFishingPlugin plugin) {
this.plugin = plugin; this.plugin = plugin;
this.registerBuiltInActions(); this.registerBuiltInActions();
}
@Override
public void disable() {
this.actionFactoryMap.clear();
}
@Override
public void reload() {
this.loadExpansions(); this.loadExpansions();
} }
@@ -393,11 +402,11 @@ public class BukkitActionManager implements ActionManager<Player> {
if (Math.random() > chance) return; if (Math.random() > chance) return;
Player player = context.getHolder(); Player player = context.getHolder();
ItemStack itemStack = player.getInventory().getItem(slot); ItemStack itemStack = player.getInventory().getItem(slot);
if (amount > 0) { // if (amount > 0) {
ItemUtils.increaseDurability(itemStack, amount, true); // ItemUtils.increaseDurability(itemStack, amount, true);
} else { // } else {
ItemUtils.decreaseDurability(context.getHolder(), itemStack, -amount, true); // ItemUtils.decreaseDurability(context.getHolder(), itemStack, -amount, true);
} // }
}; };
} else { } else {
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at durability action which should be Section"); 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 final HashMap<String, BlockStateModifierFactory> stateFactories = new HashMap<>();
private BlockProvider[] blockDetectArray; private BlockProvider[] blockDetectArray;
public BukkitBlockManager(BukkitCustomFishingPluginImpl plugin) { public BukkitBlockManager(BukkitCustomFishingPlugin plugin) {
this.plugin = plugin; this.plugin = plugin;
this.registerInbuiltProperties(); this.registerInbuiltProperties();
this.registerBlockProvider(new BlockProvider() { 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 @Override
public void load() { public void load() {
Bukkit.getPluginManager().registerEvents(this, plugin.getBoostrap()); Bukkit.getPluginManager().registerEvents(this, plugin.getBoostrap());
@@ -122,6 +115,13 @@ public class BukkitBlockManager implements BlockManager, Listener {
this.blockDetectArray = list.toArray(new BlockProvider[0]); 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. * Event handler for the EntityChangeBlockEvent.
* This method is triggered when an entity changes a block, typically when a block falls or lands. * 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, PersistentDataType.STRING,
id + ";" + context.getHolder().getName() id + ";" + context.getHolder().getName()
); );
Vector vector = playerLocation.subtract(hookLocation).toVector().multiply((config.horizontalVector().evaluate(context)) - 1); Vector vector = playerLocation.subtract(hookLocation).toVector().multiply(1.2 - 1);
vector = vector.setY((vector.getY() + 0.2) * config.verticalVector().evaluate(context)); vector = vector.setY((vector.getY() + 0.2) * 1.2);
fallingBlock.setVelocity(vector); fallingBlock.setVelocity(vector);
return fallingBlock; return fallingBlock;
} }

View File

@@ -20,7 +20,7 @@ public class ReloadCommand extends BukkitCommandFeature<CommandSender> {
.flag(manager.flagBuilder("silent")) .flag(manager.flagBuilder("silent"))
.handler(context -> { .handler(context -> {
BukkitCustomFishingPlugin.getInstance().reload(); 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.BiConsumer;
import java.util.function.BiFunction; 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); super(plugin);
this.registerBuiltInItemProperties(); this.registerBuiltInItemProperties();
this.registerBuiltInBaseEffectParser(); this.registerBuiltInBaseEffectParser();
@@ -438,4 +438,11 @@ public class BukkitConfigLoader extends ConfigManager {
return builder -> builder.statisticsKeys(keys); return builder -> builder.statisticsKeys(keys);
}, "statistics"); }, "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 @Override
public boolean registerEntity(String id, EntityConfig entity) { public boolean registerEntity(EntityConfig entity) {
if (entities.containsKey(id)) return false; if (entities.containsKey(entity.id())) return false;
this.entities.put(id, entity); this.entities.put(entity.id(), entity);
return true; return true;
} }
@@ -99,17 +99,17 @@ public class BukkitEntityManager implements EntityManager {
EntityConfig config = requireNonNull(entities.get(id), "Entity " + id + " not found"); EntityConfig config = requireNonNull(entities.get(id), "Entity " + id + " not found");
Location hookLocation = requireNonNull(context.arg(ContextKeys.HOOK_LOCATION)); Location hookLocation = requireNonNull(context.arg(ContextKeys.HOOK_LOCATION));
Location playerLocation = requireNonNull(context.getHolder().getLocation()); Location playerLocation = requireNonNull(context.getHolder().getLocation());
String entityID = config.getEntityID(); String entityID = config.entityID();
Entity entity; Entity entity;
if (entityID.contains(":")) { if (entityID.contains(":")) {
String[] split = entityID.split(":", 2); String[] split = entityID.split(":", 2);
EntityProvider provider = requireNonNull(entityProviders.get(split[0]), "EntityProvider " + split[0] + " doesn't exist"); 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 { } 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 = playerLocation.subtract(hookLocation).toVector().multiply(config.horizontalVector().evaluate(context) - 1);
vector = vector.setY((vector.getY() + 0.2) * config.getVerticalVector()); vector = vector.setY((vector.getY() + 0.2) * config.verticalVector().evaluate(context));
entity.setVelocity(vector); entity.setVelocity(vector);
return entity; 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.adventure.ShadedAdventureComponentWrapper;
import net.momirealms.customfishing.bukkit.gui.Icon; import net.momirealms.customfishing.bukkit.gui.Icon;
import net.momirealms.customfishing.bukkit.gui.page.file.FileSelector; 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.Material;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType; import org.bukkit.event.inventory.ClickType;
@@ -44,10 +47,8 @@ public class BackToFolderItem extends AbstractItem implements Icon {
public ItemProvider getItemProvider() { public ItemProvider getItemProvider() {
if (file != null && (file.getPath().startsWith("plugins\\CustomFishing\\contents") || file.getPath().startsWith("plugins/CustomFishing/contents"))) { if (file != null && (file.getPath().startsWith("plugins\\CustomFishing\\contents") || file.getPath().startsWith("plugins/CustomFishing/contents"))) {
return new ItemBuilder(Material.ORANGE_STAINED_GLASS_PANE) return new ItemBuilder(Material.ORANGE_STAINED_GLASS_PANE)
.setDisplayName(new ShadedAdventureComponentWrapper(AdventureHelper.getInstance().getComponentFromMiniMessage( .setDisplayName(new ShadedAdventureComponentWrapper(TranslationManager.render(MessageConstants.GUI_BACK_TO_PARENT_FOLDER.build())))
CFLocale.GUI_BACK_TO_PARENT_FOLDER .setLore(List.of(new ShadedAdventureComponentWrapper(AdventureHelper.miniMessage(
)))
.setLore(List.of(new ShadedAdventureComponentWrapper(AdventureHelper.getInstance().getComponentFromMiniMessage(
"<#FFA500>-> " + file.getName() "<#FFA500>-> " + file.getName()
)))); ))));
} else { } 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.adventure.ShadedAdventureComponentWrapper;
import net.momirealms.customfishing.bukkit.gui.ParentPage; 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.Material;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType; import org.bukkit.event.inventory.ClickType;
@@ -39,9 +41,7 @@ public class BackToPageItem extends AbstractItem {
@Override @Override
public ItemProvider getItemProvider() { public ItemProvider getItemProvider() {
return new ItemBuilder(Material.ORANGE_STAINED_GLASS_PANE) return new ItemBuilder(Material.ORANGE_STAINED_GLASS_PANE)
.setDisplayName(new ShadedAdventureComponentWrapper(AdventureHelper.getInstance().getComponentFromMiniMessage( .setDisplayName(new ShadedAdventureComponentWrapper(TranslationManager.render(MessageConstants.GUI_BACK_TO_PARENT_PAGE.build())));
CFLocale.GUI_BACK_TO_PARENT_PAGE
)));
} }
@Override @Override

View File

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

View File

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

View File

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

View File

@@ -17,9 +17,12 @@
package net.momirealms.customfishing.bukkit.gui.icon.property.item; 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.adventure.ShadedAdventureComponentWrapper;
import net.momirealms.customfishing.bukkit.gui.SectionPage; import net.momirealms.customfishing.bukkit.gui.SectionPage;
import net.momirealms.customfishing.bukkit.gui.page.property.CustomModelDataEditor; 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.Material;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType; import org.bukkit.event.inventory.ClickType;
@@ -40,23 +43,20 @@ public class CMDItem extends AbstractItem {
@Override @Override
public ItemProvider getItemProvider() { public ItemProvider getItemProvider() {
ItemBuilder itemBuilder = new ItemBuilder(Material.GLOW_INK_SAC) ItemBuilder itemBuilder = new ItemBuilder(Material.GLOW_INK_SAC)
.setDisplayName(new ShadedAdventureComponentWrapper(AdventureHelper.getInstance().getComponentFromMiniMessage( .setDisplayName(new ShadedAdventureComponentWrapper(TranslationManager.render(
CFLocale.GUI_ITEM_MODEL_DATA MessageConstants.GUI_ITEM_CUSTOM_MODEL_DATA.build()
))); )));
if (itemPage.getSection().contains("custom-model-data")) { if (itemPage.getSection().contains("custom-model-data")) {
itemBuilder.addLoreLines(new ShadedAdventureComponentWrapper(AdventureHelper.getInstance().getComponentFromMiniMessage( itemBuilder.addLoreLines(new ShadedAdventureComponentWrapper(TranslationManager.render(
CFLocale.GUI_CURRENT_VALUE + itemPage.getSection().getInt("custom-model-data") MessageConstants.GUI_CURRENT_VALUE.arguments(
Component.text(itemPage.getSection().getInt("custom-model-data"))
).build()
))) )))
.addLoreLines(""); .addLoreLines("");
itemBuilder.addLoreLines(new ShadedAdventureComponentWrapper(AdventureHelper.getInstance().getComponentFromMiniMessage( itemBuilder.addLoreLines(new ShadedAdventureComponentWrapper(TranslationManager.render(MessageConstants.GUI_LEFT_CLICK_EDIT.build())))
CFLocale.GUI_LEFT_CLICK_EDIT .addLoreLines(new ShadedAdventureComponentWrapper(TranslationManager.render(MessageConstants.GUI_RIGHT_CLICK_RESET.build())));
))).addLoreLines(new ShadedAdventureComponentWrapper(AdventureHelper.getInstance().getComponentFromMiniMessage(
CFLocale.GUI_RIGHT_CLICK_RESET
)));
} else { } else {
itemBuilder.addLoreLines(new ShadedAdventureComponentWrapper(AdventureHelper.getInstance().getComponentFromMiniMessage( itemBuilder.addLoreLines(new ShadedAdventureComponentWrapper(TranslationManager.render(MessageConstants.GUI_LEFT_CLICK_EDIT.build())));
CFLocale.GUI_LEFT_CLICK_EDIT
)));
} }
return itemBuilder; 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.adventure.ShadedAdventureComponentWrapper;
import net.momirealms.customfishing.bukkit.gui.SectionPage; import net.momirealms.customfishing.bukkit.gui.SectionPage;
import net.momirealms.customfishing.bukkit.gui.page.property.NBTEditor; import net.momirealms.customfishing.bukkit.gui.page.property.NBTEditor;
import net.momirealms.customfishing.bukkit.util.ConfigUtils;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType; 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.ScrollDownItem;
import net.momirealms.customfishing.bukkit.gui.icon.ScrollUpItem; import net.momirealms.customfishing.bukkit.gui.icon.ScrollUpItem;
import net.momirealms.customfishing.bukkit.gui.page.item.ItemSelector; 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.Material;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType; import org.bukkit.event.inventory.ClickType;
@@ -79,19 +81,10 @@ public class FileSelector {
Window window = Window.single() Window window = Window.single()
.setViewer(player) .setViewer(player)
.setTitle(new ShadedAdventureComponentWrapper(AdventureHelper.getInstance().getComponentFromMiniMessage( .setTitle(new ShadedAdventureComponentWrapper(TranslationManager.render(MessageConstants.GUI_SELECT_FILE.build())))
CFLocale.GUI_SELECT_FILE
)))
.setGui(gui) .setGui(gui)
.build(); .build();
// gui.playAnimation(new SequentialAnimation(1, true), slotElement -> {
// if (slotElement instanceof SlotElement.ItemSlotElement itemSlotElement) {
// return !(itemSlotElement.getItem() instanceof Icon);
// }
// return true;
// });
window.open(); 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.adventure.ShadedAdventureComponentWrapper;
import net.momirealms.customfishing.bukkit.gui.SectionPage; import net.momirealms.customfishing.bukkit.gui.SectionPage;
import net.momirealms.customfishing.bukkit.gui.icon.BackGroundItem; import net.momirealms.customfishing.bukkit.gui.icon.BackGroundItem;
import net.momirealms.customfishing.bukkit.util.ConfigUtils;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Player; 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.context.ContextKeys;
import net.momirealms.customfishing.api.mechanic.item.CustomFishingItem; import net.momirealms.customfishing.api.mechanic.item.CustomFishingItem;
import net.momirealms.customfishing.api.mechanic.item.ItemManager; 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.bukkit.util.LocationUtils;
import net.momirealms.customfishing.common.item.Item; import net.momirealms.customfishing.common.item.Item;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;

View File

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

View File

@@ -1,63 +1,62 @@
/* ///*
* Copyright (C) <2022> <XiaoMoMi> // * Copyright (C) <2022> <XiaoMoMi>
* // *
* This program is free software: you can redistribute it and/or modify // * 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 // * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or // * the Free Software Foundation, either version 3 of the License, or
* any later version. // * any later version.
* // *
* This program is distributed in the hope that it will be useful, // * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of // * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. // * GNU General Public License for more details.
* // *
* You should have received a copy of the GNU General Public License // * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. // * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ // */
//
package net.momirealms.customfishing.bukkit.requirement; //package net.momirealms.customfishing.bukkit.requirement;
//
import net.momirealms.customfishing.api.common.Pair; //import net.momirealms.customfishing.api.mechanic.requirement.Requirement;
import net.momirealms.customfishing.api.mechanic.requirement.Requirement; //import org.bukkit.entity.Player;
import org.bukkit.entity.Player; //
//import java.util.HashMap;
import java.util.HashMap; //import java.util.List;
import java.util.List; //
//public class ConditionalElement {
public class ConditionalElement { //
// private final List<Pair<String, WeightModifier>> modifierList;
private final List<Pair<String, WeightModifier>> modifierList; // private final HashMap<String, ConditionalElement> subLoots;
private final HashMap<String, ConditionalElement> subLoots; // private final Requirement[] requirements;
private final Requirement[] requirements; //
// public ConditionalElement(
public ConditionalElement( // Requirement[] requirements,
Requirement[] requirements, // List<Pair<String, WeightModifier>> modifierList,
List<Pair<String, WeightModifier>> modifierList, // HashMap<String, ConditionalElement> subElements
HashMap<String, ConditionalElement> subElements // ) {
) { // this.modifierList = modifierList;
this.modifierList = modifierList; // this.requirements = requirements;
this.requirements = requirements; // this.subLoots = subElements;
this.subLoots = subElements; // }
} //
// /**
/** // * Combines the weight modifiers for this element.
* Combines the weight modifiers for this element. // *
* // * @param player The player for whom the modifiers are applied.
* @param player The player for whom the modifiers are applied. // * @param weightMap The map of weight modifiers.
* @param weightMap The map of weight modifiers. // */
*/ // synchronized public void combine(Player player, HashMap<String, Double> weightMap) {
synchronized public void combine(Player player, HashMap<String, Double> weightMap) { // for (Pair<String, WeightModifier> modifierPair : this.modifierList) {
for (Pair<String, WeightModifier> modifierPair : this.modifierList) { // double previous = weightMap.getOrDefault(modifierPair.left(), 0d);
double previous = weightMap.getOrDefault(modifierPair.left(), 0d); // weightMap.put(modifierPair.left(), modifierPair.right().modify(player, previous));
weightMap.put(modifierPair.left(), modifierPair.right().modify(player, previous)); // }
} // }
} //
// public Requirement[] getRequirements() {
public Requirement[] getRequirements() { // return requirements;
return requirements; // }
} //
// public HashMap<String, ConditionalElement> getSubElements() {
public HashMap<String, ConditionalElement> getSubElements() { // return subLoots;
return subLoots; // }
} //}
}

View File

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

View File

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

View File

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

View File

@@ -18,9 +18,9 @@
package net.momirealms.customfishing.bukkit.totem.particle; package net.momirealms.customfishing.bukkit.totem.particle;
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin; 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.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.Expression;
import net.objecthunter.exp4j.ExpressionBuilder; import net.objecthunter.exp4j.ExpressionBuilder;
import org.bukkit.Location; import org.bukkit.Location;
@@ -63,9 +63,9 @@ public class ParticleSetting implements TotemParticle {
} }
@SuppressWarnings("DuplicatedCode") @SuppressWarnings("DuplicatedCode")
public CancellableTask start(Location location, double radius) { public SchedulerTask start(Location location, double radius) {
World world = location.getWorld(); World world = location.getWorld();
return BukkitCustomFishingPlugin.get().getScheduler().runTaskAsyncTimer(() -> { return BukkitCustomFishingPlugin.getInstance().getScheduler().asyncRepeating(() -> {
for (Pair<Double, Double> range : ranges) { for (Pair<Double, Double> range : ranges) {
for (double theta = range.left(); theta <= range.right(); theta += interval) { for (double theta = range.left(); theta <= range.right(); theta += interval) {
double r = expressionHorizontal.setVariable("theta", theta).setVariable("radius", radius).evaluate(); 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 config-version: '${config_version}'
# Wiki: https://mo-mi.gitbook.io/xiaomomi-plugins/
config-version: '32'
# Debug # Debug
debug: false debug: false

View File

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

View File

@@ -1,3 +1,5 @@
config-version: '${config_version}'
enable: true enable: true
# Container title # 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 # Project settings
# Rule: [major update].[feature update].[bug fix] # Rule: [major update].[feature update].[bug fix]
project_version=1.7.1 project_version=2.2.0
config_version=2 config_version=32
project_group=net.momirealms project_group=net.momirealms
# Dependency settings # Dependency settings