9
0
mirror of https://github.com/Xiao-MoMi/Custom-Fishing.git synced 2025-12-22 16:39:31 +00:00

checkpoint - 10

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,125 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customfishing.api.mechanic.totem;
import net.momirealms.customfishing.api.mechanic.requirement.Requirement;
import net.momirealms.customfishing.api.mechanic.totem.block.TotemBlock;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import static java.util.Objects.requireNonNull;
public class TotemConfigImpl implements TotemConfig {
private String id;
private TotemModel[] totemModels;
private TotemParticle[] particleSettings;
private Requirement<Player>[] activateRequirements;
private double radius;
private int duration;
public TotemConfigImpl(String id, TotemModel[] totemModels, TotemParticle[] particleSettings, Requirement<Player>[] activateRequirements, double radius, int duration) {
this.id = id;
this.totemModels = totemModels;
this.particleSettings = particleSettings;
this.activateRequirements = activateRequirements;
this.radius = radius;
this.duration = duration;
}
@Override
public TotemModel[] totemModels() {
return totemModels;
}
@Override
public Requirement<Player>[] activateRequirements() {
return activateRequirements;
}
@Override
public String id() {
return id;
}
@Override
public boolean isRightPattern(Location location) {
for (TotemModel totemModel : totemModels) {
if (totemModel.isPatternSatisfied(location)) {
return true;
}
}
return false;
}
@Override
public TotemParticle[] particleSettings() {
return particleSettings;
}
@Override
public double radius() {
return radius;
}
@Override
public int duration() {
return duration;
}
@Override
public TotemBlock[] totemCore() {
return totemModels[0].getTotemCore();
}
public static class BuilderImpl implements Builder {
private String id;
private TotemModel[] totemModels;
private TotemParticle[] particleSettings;
private Requirement<Player>[] activateRequirements;
private double radius;
private int duration;
public Builder id(String id) {
this.id = id;
return this;
}
public Builder totemModels(TotemModel[] totemModels) {
this.totemModels = totemModels;
return this;
}
public Builder particleSettings(TotemParticle[] particleSettings) {
this.particleSettings = particleSettings;
return this;
}
public Builder radius(double radius) {
this.radius = radius;
return this;
}
public Builder duration(int duration) {
this.duration = duration;
return this;
}
public Builder activateRequirements(Requirement<Player>[] activateRequirements) {
this.activateRequirements = activateRequirements;
return this;
}
public TotemConfig build() {
return new TotemConfigImpl(requireNonNull(id), requireNonNull(totemModels), particleSettings, activateRequirements, radius, duration);
}
}
}

View File

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

View File

@@ -0,0 +1,277 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customfishing.api.mechanic.totem;
import net.momirealms.customfishing.api.mechanic.totem.block.TotemBlock;
import org.apache.commons.lang3.SerializationUtils;
import org.bukkit.Axis;
import org.bukkit.Location;
import java.io.Serializable;
import java.util.StringJoiner;
/**
* This class represents a totem model used to define the pattern of a totem.
*/
public class TotemModel implements Serializable {
private int coreX;
private final int coreY;
private int coreZ;
// [Y][Z][X][alternative totem blocks]
private TotemBlock[][][][] model;
/**
* Constructs a TotemModel with the specified parameters.
*
* @param coreX X-coordinate of the totem's core within the model.
* @param coreY Y-coordinate of the totem's core within the model.
* @param coreZ Z-coordinate of the totem's core within the model.
* @param model 3D array representing the totem model's structure.
*/
public TotemModel(int coreX, int coreY, int coreZ, TotemBlock[][][][] model) {
this.coreX = coreX;
this.coreY = coreY;
this.coreZ = coreZ;
this.model = model;
}
/**
* Get the totem core as an array of TotemBlock objects.
*
* @return An array of TotemBlock objects representing the totem's core.
*/
public TotemBlock[] getTotemCore() {
return model[coreY][coreZ][coreX];
}
/**
* Get the X-coordinate of the totem's core within the model.
*
* @return The X-coordinate as an integer.
*/
public int getCoreX() {
return coreX;
}
/**
* Get the Y-coordinate of the totem's core within the model.
*
* @return The Y-coordinate as an integer.
*/
public int getCoreY() {
return coreY;
}
/**
* Get the Z-coordinate of the totem's core within the model.
*
* @return The Z-coordinate as an integer.
*/
public int getCoreZ() {
return coreZ;
}
/**
* Get the 3D array representing the totem model's structure.
*
* @return The 3D array of TotemBlock objects.
*/
public TotemBlock[][][][] getModel() {
return model;
}
@Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder();
for (int h = 0; h < model.length; h++) {
stringBuilder.append("layer: ").append(h + 1).append("\n");
TotemBlock[][][] totemBlocks1 = model[h];
for (TotemBlock[][] totemBlocks2 : totemBlocks1) {
for (TotemBlock[] totemBlocks3 : totemBlocks2) {
StringJoiner stringJoiner = new StringJoiner("||");
for (TotemBlock totemBlock : totemBlocks3) {
stringJoiner.add(totemBlock.toString());
}
stringBuilder.append(stringJoiner).append("\t");
}
stringBuilder.append("\n");
}
}
return stringBuilder.toString();
}
public TotemModel deepClone() {
return SerializationUtils.clone(this);
}
/**
* Rotate the totem model 90 degrees clockwise.
*
* @return The rotated TotemModel.
*/
public TotemModel rotate90() {
int tempX = this.coreX;
this.coreX = this.coreZ;
this.coreZ = this.model[0][0].length - 1 - tempX;
this.model = rotate90(model);
for (TotemBlock[][][] totemBlocks1 : model) {
for (TotemBlock[][] totemBlocks2 : totemBlocks1) {
for (TotemBlock[] totemBlocks3 : totemBlocks2) {
for (TotemBlock totemBlock : totemBlocks3) {
totemBlock.rotate90();
}
}
}
}
return this;
}
/**
* Mirror the totem model horizontally.
*
* @return The mirrored TotemModel.
*/
public TotemModel mirrorHorizontally() {
mirrorHorizontally(model);
this.coreZ = model[0].length - this.coreZ - 1;
for (TotemBlock[][][] totemBlocks1 : model) {
for (TotemBlock[][] totemBlocks2 : totemBlocks1) {
for (TotemBlock[] totemBlocks3 : totemBlocks2) {
for (TotemBlock totemBlock : totemBlocks3) {
totemBlock.mirror(Axis.X);
}
}
}
}
return this;
}
/**
* Mirror the totem model vertically.
*
* @return The mirrored TotemModel.
*/
public TotemModel mirrorVertically() {
mirrorVertically(model);
this.coreX = model[0][0].length - this.coreX - 1;
for (TotemBlock[][][] totemBlocks1 : model) {
for (TotemBlock[][] totemBlocks2 : totemBlocks1) {
for (TotemBlock[] totemBlocks3 : totemBlocks2) {
for (TotemBlock totemBlock : totemBlocks3) {
totemBlock.mirror(Axis.Z);
}
}
}
}
return this;
}
/**
* Check if the provided location satisfies the pattern defined by the totem model.
*
* @param location The location to check.
* @return True if the location satisfies the pattern, false otherwise.
*/
public boolean isPatternSatisfied(Location location) {
Location startLoc = location.clone().subtract(0, coreY, 0);
int height = model.length;
int width = model[0].length;
int length = model[0][0].length;
for (int y = 0; y < height; y++) {
Location loc = startLoc.clone().add(-coreX, y, -coreZ);
for (int z = 0; z < width; z++) {
outer:
for (int x = 0; x < length; x++) {
for (TotemBlock totemBlock : model[y][z][x]) {
if (totemBlock.isRightBlock(loc.clone().add(x, 0, z).getBlock())) {
continue outer;
}
}
return false;
}
}
}
return true;
}
/**
* Rotate a 3D totem model 90 degrees clockwise.
*
* @param matrix The 3D totem model to rotate.
* @return The rotated 3D totem model.
*/
private static TotemBlock[][][][] rotate90(TotemBlock[][][][] matrix) {
int height = matrix.length;
int rows = matrix[0].length;
int cols = matrix[0][0].length;
TotemBlock[][][][] rotated = new TotemBlock[height][cols][rows][];
for (int h = 0; h < height; h++) {
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
rotated[h][c][rows - 1 - r] = matrix[h][r][c];
}
}
}
return rotated;
}
/**
* Mirror a 3D totem model horizontally.
*
* @param matrix The 3D totem model to mirror.
*/
private static void mirrorHorizontally(TotemBlock[][][][] matrix) {
int height = matrix.length;
int rows = matrix[0].length;
int cols = matrix[0][0].length;
for (int h = 0; h < height; h++) {
for (int i = 0; i < rows / 2; i++) {
for (int j = 0; j < cols; j++) {
TotemBlock[] temp = matrix[h][i][j];
matrix[h][i][j] = matrix[h][rows - i - 1][j];
matrix[h][rows - i - 1][j] = temp;
}
}
}
}
/**
* Mirror a 3D totem model vertically.
*
* @param matrix The 3D totem model to mirror.
*/
private static void mirrorVertically(TotemBlock[][][][] matrix) {
int height = matrix.length;
int rows = matrix[0].length;
int cols = matrix[0][0].length;
for (int h = 0; h < height; h++) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols / 2; j++) {
TotemBlock[] temp = matrix[h][i][j];
matrix[h][i][j] = matrix[h][i][cols - j - 1];
matrix[h][i][cols - j - 1] = temp;
}
}
}
}
}

View File

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

View File

@@ -0,0 +1,118 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customfishing.api.mechanic.totem.block;
import net.momirealms.customfishing.api.mechanic.totem.block.property.TotemBlockProperty;
import net.momirealms.customfishing.api.mechanic.totem.block.type.TypeCondition;
import org.bukkit.Axis;
import org.bukkit.block.Block;
import java.io.Serializable;
import java.util.StringJoiner;
/**
* Represents a TotemBlock that defines conditions and properties for a specific block type in a totem structure.
*/
public class TotemBlock implements Serializable {
private final TypeCondition typeCondition;
private final TotemBlockProperty[] properties;
/**
* Initializes a TotemBlock with the specified TypeCondition and properties.
*
* @param typeCondition The TypeCondition that specifies the block type.
* @param properties An array of TotemBlockProperty objects representing additional block properties.
*/
public TotemBlock(TypeCondition typeCondition, TotemBlockProperty[] properties) {
this.typeCondition = typeCondition;
this.properties = properties;
}
/**
* Gets the TypeCondition associated with this TotemBlock.
*
* @return The TypeCondition defining the block type.
*/
public TypeCondition getTypeCondition() {
return typeCondition;
}
/**
* Gets an array of properties associated with this TotemBlock.
*
* @return An array of TotemBlockProperty objects representing block properties.
*/
public TotemBlockProperty[] getProperties() {
return properties;
}
/**
* Checks if a given Block satisfies the TypeCondition and properties of this TotemBlock.
*
* @param block The Block to be checked against the conditions and properties.
* @return `true` if the block satisfies all conditions and properties, otherwise `false`.
*/
public boolean isRightBlock(Block block) {
if (!typeCondition.isMet(block)) {
return false;
}
for (TotemBlockProperty property : properties) {
if (!property.isPropertyMet(block)) {
return false;
}
}
return true;
}
/**
* Rotates the properties of this TotemBlock by 90 degrees.
* This method should be called when the totem structure is rotated.
*/
public void rotate90() {
for (TotemBlockProperty property : properties) {
property.rotate90();
}
}
/**
* Mirrors the properties of this TotemBlock horizontally or vertically.
* This method should be called when the totem structure is mirrored.
*
* @param axis The Axis along which to mirror the properties (X or Z).
*/
public void mirror(Axis axis) {
for (TotemBlockProperty property : properties) {
property.mirror(axis);
}
}
/**
* Returns the raw text representation of this TotemBlock, including its TypeCondition and properties.
*
* @return The raw text representation of this TotemBlock.
*/
@Override
public String toString() {
StringJoiner stringJoiner = new StringJoiner(";");
for (TotemBlockProperty property : properties) {
stringJoiner.add(property.getRawText());
}
return typeCondition.getRawText() + "{" + stringJoiner + "}";
}
}

View File

@@ -0,0 +1,71 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customfishing.api.mechanic.totem.block.property;
import org.bukkit.Axis;
import org.bukkit.block.Block;
import org.bukkit.block.data.Orientable;
import java.io.Serializable;
import java.util.Locale;
public class AxisImpl implements TotemBlockProperty, Serializable {
private Axis axis;
public AxisImpl(Axis axis) {
this.axis = axis;
}
@Override
public TotemBlockProperty mirror(Axis axis) {
return this;
}
/**
* Rotates the block axis 90 degrees. (X -> Z, Z -> X)
* @return The rotated block axis.
*/
@Override
public TotemBlockProperty rotate90() {
if (this.axis == Axis.X) {
axis = Axis.Z;
} else if (this.axis == Axis.Z) {
axis = Axis.X;
}
return this;
}
/**
* Checks if the block has the property.
* @param block The block to check.
* @return True if the block has the property.
*/
@Override
public boolean isPropertyMet(Block block) {
if (block.getBlockData() instanceof Orientable orientable) {
return orientable.getAxis().equals(this.axis);
}
return false;
}
@Override
public String getRawText() {
return "axis=" + axis.name().toLowerCase(Locale.ENGLISH);
}
}

View File

@@ -0,0 +1,86 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customfishing.api.mechanic.totem.block.property;
import org.bukkit.Axis;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.Directional;
import java.io.Serializable;
import java.util.Locale;
public class FaceImpl implements TotemBlockProperty, Serializable {
private BlockFace blockFace;
public FaceImpl(BlockFace blockFace) {
this.blockFace = blockFace;
}
/**
* Mirrors the block face if the axis is X or Z.
* @param axis The axis to mirror.
* @return The mirrored block face.
*/
@Override
public TotemBlockProperty mirror(Axis axis) {
if (axis == Axis.X) {
if (blockFace == BlockFace.SOUTH || blockFace == BlockFace.NORTH) {
return new FaceImpl(blockFace.getOppositeFace());
} else {
return this;
}
} else if (axis == Axis.Z) {
if (blockFace == BlockFace.EAST || blockFace == BlockFace.WEST) {
return new FaceImpl(blockFace.getOppositeFace());
} else {
return this;
}
}
return this;
}
@Override
public TotemBlockProperty rotate90() {
switch (blockFace) {
case UP, DOWN -> {
return this;
}
case EAST -> blockFace = BlockFace.SOUTH;
case SOUTH -> blockFace = BlockFace.WEST;
case WEST -> blockFace = BlockFace.NORTH;
case NORTH -> blockFace = BlockFace.EAST;
default -> throw new IllegalArgumentException("Unsupported block facing: " + blockFace);
}
return this;
}
@Override
public boolean isPropertyMet(Block block) {
if (block.getBlockData() instanceof Directional directional) {
return directional.getFacing().equals(this.blockFace);
}
return false;
}
@Override
public String getRawText() {
return "face=" + blockFace.name().toLowerCase(Locale.ENGLISH);
}
}

View File

@@ -0,0 +1,74 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customfishing.api.mechanic.totem.block.property;
import org.bukkit.Axis;
import org.bukkit.block.Block;
import org.bukkit.block.data.Bisected;
import java.io.Serializable;
import java.util.Locale;
public class HalfImpl implements TotemBlockProperty, Serializable {
private final Bisected.Half half;
public HalfImpl(Bisected.Half half) {
this.half = half;
}
/**
* half is not affected by mirroring.
* @param axis The axis to mirror.
* @return this
*/
@Override
public TotemBlockProperty mirror(Axis axis) {
return this;
}
/**
* half is not affected by rotation.
* @return this
*/
@Override
public TotemBlockProperty rotate90() {
return this;
}
/**
* Checks if the block's half is the same as the half of this property.
* @param block The block to check.
* @return true if the block's half is the same as the half of this property.
*/
@Override
public boolean isPropertyMet(Block block) {
if (block.getBlockData() instanceof Bisected bisected) {
return bisected.getHalf().equals(this.half);
}
return false;
}
/**
* Returns the raw text of the half property.
* @return The raw text of the half property.
*/
@Override
public String getRawText() {
return "half=" + half.name().toLowerCase(Locale.ENGLISH);
}
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customfishing.api.mechanic.totem.block.property;
import org.bukkit.Axis;
import org.bukkit.block.Block;
public interface TotemBlockProperty {
/**
* Mirrors the block face if the axis is X or Z.
* @param axis The axis to mirror.
* @return The mirrored block face.
*/
TotemBlockProperty mirror(Axis axis);
/**
* Rotates the block face 90 degrees.
* @return The rotated block face.
*/
TotemBlockProperty rotate90();
/**
* Checks if the block has the property.
* @param block The block to check.
* @return True if the block has the property.
*/
boolean isPropertyMet(Block block);
/**
* Gets the raw text of the property.
* @return The raw text of the property.
*/
String getRawText();
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customfishing.api.mechanic.totem.block.type;
import org.bukkit.block.Block;
import java.io.Serializable;
/**
* Represents a TypeCondition that checks if a Block's type name ends with a specified string.
*/
public class EndWithType implements TypeCondition, Serializable {
private final String end;
public EndWithType(String end) {
this.end = end;
}
/**
* Checks if the specified Block's type name ends with the configured ending string.
*
* @param type The Block to check.
* @return `true` if the Block's type name ends with the specified string, otherwise `false`.
*/
@Override
public boolean isMet(Block type) {
return type.getType().name().endsWith(end);
}
/**
* Gets the raw text representation of this TypeCondition.
* The raw text includes the asterisk (*) followed by the configured ending string.
*
* @return The raw text representation of this TypeCondition.
*/
@Override
public String getRawText() {
return "*" + end;
}
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customfishing.api.mechanic.totem.block.type;
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
import org.bukkit.block.Block;
import java.io.Serializable;
/**
* Represents a TypeCondition that checks if a Block's type matches a specified type string.
*/
public class EqualType implements TypeCondition, Serializable {
private final String type;
public EqualType(String type) {
this.type = type;
}
/**
* Checks if the specified Block's type matches the configured type string.
*
* @param type The Block to check.
* @return `true` if the Block's type matches the specified type string, otherwise `false`.
*/
@Override
public boolean isMet(Block type) {
return this.type.equals(BukkitCustomFishingPlugin.getInstance().getBlockManager().getBlockID(type));
}
/**
* Gets the raw text representation of this TypeCondition, which is the configured type string.
*
* @return The raw text representation of this TypeCondition.
*/
@Override
public String getRawText() {
return type;
}
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customfishing.api.mechanic.totem.block.type;
import org.bukkit.block.Block;
import java.io.Serializable;
/**
* Represents a TypeCondition that checks if a Block's type starts with a specified prefix.
*/
public class StartWithType implements TypeCondition, Serializable {
private final String start;
public StartWithType(String start) {
this.start = start;
}
/**
* Checks if the specified Block's type starts with the configured prefix.
*
* @param type The Block to check.
* @return `true` if the Block's type starts with the specified prefix, otherwise `false`.
*/
@Override
public boolean isMet(Block type) {
return type.getType().name().startsWith(start);
}
/**
* Gets the raw text representation of this TypeCondition, which is the configured prefix followed by '*'.
*
* @return The raw text representation of this TypeCondition.
*/
@Override
public String getRawText() {
return start + "*";
}
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customfishing.api.mechanic.totem.block.type;
import org.bukkit.block.Block;
/**
* Represents a condition used to check the type of a Block.
*/
public interface TypeCondition {
/**
* Checks if the specified Block meets the condition.
*
* @param block The Block to check.
* @return `true` if the condition is met, otherwise `false`.
*/
boolean isMet(Block block);
/**
* Gets the raw text representation of this TypeCondition.
*
* @return The raw text representation of this TypeCondition.
*/
String getRawText();
/**
* Gets a TypeCondition based on its raw text representation.
*
* @param raw The raw text representation of the TypeCondition.
* @return A TypeCondition instance corresponding to the raw text.
*/
static TypeCondition getTypeCondition(String raw) {
if (raw.startsWith("*")) {
return new EndWithType(raw.substring(1));
} else if (raw.endsWith("*")) {
return new StartWithType(raw.substring(0, raw.length() -1));
} else {
return new EqualType(raw);
}
}
}

View File

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