9
0
mirror of https://github.com/Xiao-MoMi/Custom-Fishing.git synced 2025-12-19 15:09:24 +00:00

checkpoint - 18

This commit is contained in:
XiaoMoMi
2024-07-01 01:34:19 +08:00
parent 53a6dc20bb
commit 4eb4ff901a
48 changed files with 775 additions and 154 deletions

View File

@@ -21,6 +21,7 @@ dependencies {
compileOnly("dev.folia:folia-api:${rootProject.properties["paper_version"]}-R0.1-SNAPSHOT")
compileOnly("com.google.code.gson:gson:${rootProject.properties["gson_version"]}")
compileOnly("me.clip:placeholderapi:${rootProject.properties["placeholder_api_version"]}")
compileOnly("com.github.Xiao-MoMi:Sparrow-Heart:${rootProject.properties["sparrow_heart_version"]}")
}
java {

View File

@@ -17,9 +17,7 @@
package net.momirealms.customfishing.api.event;
import net.momirealms.customfishing.api.mechanic.effect.Effect;
import net.momirealms.customfishing.api.mechanic.fishing.FishingGears;
import net.momirealms.customfishing.api.mechanic.fishing.FishingPreparation;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.player.PlayerEvent;
@@ -48,9 +46,10 @@ public class RodCastEvent extends PlayerEvent implements Cancellable {
}
/**
* Cancelling this event would not cancel the bukkit PlayerFishEvent
* Cancelling this event would disable CustomFishing mechanics
* If you want to prevent players from casting, use {@link #getBukkitPlayerFishEvent()} instead
*
* @param cancel true if you wish to cancel this event
* @param cancel true if you want to cancel this event
*/
@Override
public void setCancelled(boolean cancel) {
@@ -61,19 +60,23 @@ public class RodCastEvent extends PlayerEvent implements Cancellable {
return handlerList;
}
@NotNull
@Override
public HandlerList getHandlers() {
return getHandlerList();
}
/**
* Get the {@link FishingGears}
*
* @return fishing gears
*/
public FishingGears getGears() {
return gears;
}
/**
* Gets the original PlayerFishEvent that triggered the rod cast.
* Gets the original PlayerFishEvent that triggered the {@link RodCastEvent}.
*
* @return The original PlayerFishEvent.
*/

View File

@@ -81,7 +81,7 @@ public interface ActionManager<T> extends Reloadable {
* @return An array of parsed actions.
*/
@NotNull
Action<T>[] parseActions(@NotNull Section section);
Action<T>[] parseActions(Section section);
/**
* Parses an action from the given type and arguments.

View File

@@ -21,6 +21,7 @@ import net.momirealms.customfishing.common.config.ConfigLoader;
import net.momirealms.customfishing.common.config.node.Node;
import net.momirealms.customfishing.common.item.Item;
import net.momirealms.customfishing.common.plugin.feature.Reloadable;
import net.momirealms.customfishing.common.util.Pair;
import org.bukkit.entity.Player;
import org.bukkit.event.EventPriority;
import org.bukkit.inventory.ItemStack;
@@ -34,6 +35,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
@@ -56,8 +58,12 @@ public abstract class ConfigManager implements ConfigLoader, Reloadable {
protected boolean overrideVanillaWaitTime;
protected int waterMinTime;
protected int waterMaxTime;
protected boolean enableLavaFishing;
protected int lavaMinTime;
protected int lavaMaxTime;
protected boolean enableVoidFishing;
protected int voidMinTime;
protected int voidMaxTime;
protected boolean restrictedSizeRange;
protected List<String> durabilityLore;
protected boolean allowMultipleTotemType;
@@ -66,6 +72,7 @@ public abstract class ConfigManager implements ConfigLoader, Reloadable {
protected Requirement<Player>[] mechanicRequirements;
protected boolean enableBag;
protected ConfigManager(BukkitCustomFishingPlugin plugin) {
this.plugin = plugin;
instance = this;
@@ -127,6 +134,10 @@ public abstract class ConfigManager implements ConfigLoader, Reloadable {
return instance.waterMaxTime;
}
public static boolean enableLavaFishing() {
return instance.enableLavaFishing;
}
public static int lavaMinTime() {
return instance.lavaMinTime;
}
@@ -135,6 +146,18 @@ public abstract class ConfigManager implements ConfigLoader, Reloadable {
return instance.lavaMaxTime;
}
public static boolean enableVoidFishing() {
return instance.enableVoidFishing;
}
public static int voidMinTime() {
return instance.voidMinTime;
}
public static int voidMaxTime() {
return instance.voidMaxTime;
}
public static boolean restrictedSizeRange() {
return instance.restrictedSizeRange;
}
@@ -312,4 +335,8 @@ public abstract class ConfigManager implements ConfigLoader, Reloadable {
public Map<String, Node<ConfigParserFunction>> getFormatFunctions() {
return formatFunctions;
}
public abstract List<Pair<String, BiFunction<Context<Player>, Double, Double>>> parseWeightOperation(List<String> ops);
public abstract List<Pair<String, BiFunction<Context<Player>, Double, Double>>> parseGroupWeightOperation(List<String> gops);
}

View File

@@ -98,4 +98,11 @@ public class ContextKeys<T> {
public final int hashCode() {
return Objects.hashCode(this.key);
}
@Override
public String toString() {
return "ContextKeys{" +
"key='" + key + '\'' +
'}';
}
}

View File

@@ -90,4 +90,12 @@ public final class PlayerContextImpl implements Context<Player> {
public Player getHolder() {
return player;
}
@Override
public String toString() {
return "PlayerContext{" +
"args=" + args +
", player=" + player +
'}';
}
}

View File

@@ -1,94 +1,143 @@
package net.momirealms.customfishing.api.mechanic.fishing;
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
import net.momirealms.customfishing.api.mechanic.config.ConfigManager;
import net.momirealms.customfishing.api.mechanic.context.Context;
import net.momirealms.customfishing.api.mechanic.effect.Effect;
import net.momirealms.customfishing.api.mechanic.effect.EffectModifier;
import net.momirealms.customfishing.api.mechanic.fishing.hook.HookMechanic;
import net.momirealms.customfishing.api.mechanic.fishing.hook.LavaFishingMechanic;
import net.momirealms.customfishing.api.mechanic.fishing.hook.VanillaMechanic;
import net.momirealms.customfishing.api.mechanic.fishing.hook.VoidFishingMechanic;
import net.momirealms.customfishing.api.mechanic.loot.Loot;
import net.momirealms.customfishing.common.plugin.scheduler.SchedulerTask;
import net.momirealms.customfishing.common.util.TriConsumer;
import net.momirealms.customfishing.common.util.TriFunction;
import net.momirealms.sparrow.heart.SparrowHeart;
import org.bukkit.entity.FishHook;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
public class CustomFishingHook {
private static final Consumer<FishHook> hookConsumer = defaultHookLogics();
private FishHook hook;
private final FishHook hook;
private final SchedulerTask task;
private final FishingGears gears;
private HookMechanic hookMechanic;
private Loot nextLoot;
private Context<Player> context;
public static Consumer<FishHook> defaultHookLogics() {
return fishHook -> {
private static TriFunction<FishHook, Context<Player>, Effect, List<HookMechanic>> mechanicProviders = defaultMechanicProviders();
public static TriFunction<FishHook, Context<Player>, Effect, List<HookMechanic>> defaultMechanicProviders() {
return (h, c, e) -> {
ArrayList<HookMechanic> mechanics = new ArrayList<>();
mechanics.add(new VanillaMechanic(h, c));
if (ConfigManager.enableLavaFishing()) mechanics.add(new LavaFishingMechanic(h, e, c));
if (ConfigManager.enableVoidFishing()) mechanics.add(new VoidFishingMechanic(h, e, c));
return mechanics;
};
};
public static void mechanicProviders(TriFunction<FishHook, Context<Player>, Effect, List<HookMechanic>> mechanicProviders) {
CustomFishingHook.mechanicProviders = mechanicProviders;
}
public CustomFishingHook(FishHook hook, FishingGears gears, Context<Player> context, List<HookMechanic> enabledMechanics) {
public CustomFishingHook(FishHook hook, FishingGears gears, Context<Player> context) {
this.gears = gears;
this.hook = hook;
// once it becomes a custom hook, the wait time is controlled by plugin
this.context = context;
Effect effect = Effect.newInstance();
// The effects impact mechanism at this stage
for (EffectModifier modifier : gears.effectModifiers()) {
for (TriConsumer<Effect, Context<Player>, Integer> consumer : modifier.modifiers()) {
consumer.accept(effect, context, 0);
}
}
List<HookMechanic> enabledMechanics = mechanicProviders.apply(hook, context, effect);
this.task = BukkitCustomFishingPlugin.getInstance().getScheduler().sync().runRepeating(() -> {
// destroy if hook is invalid
if (hook.isValid()) {
if (!hook.isValid()) {
BukkitCustomFishingPlugin.getInstance().getFishingManager().destroy(hook.getOwnerUniqueId());
return;
}
for (HookMechanic mechanic : enabledMechanics) {
// find the first available mechanic
if (mechanic.canStart()) {
if (hookMechanic != mechanic) {
if (hookMechanic != null) hookMechanic.destroy();
hookMechanic = mechanic;
if (this.hookMechanic != mechanic) {
if (this.hookMechanic != null) this.hookMechanic.destroy();
this.hookMechanic = mechanic;
// to update some properties
mechanic.preStart();
Effect tempEffect = effect.copy();
for (EffectModifier modifier : gears.effectModifiers()) {
for (TriConsumer<Effect, Context<Player>, Integer> consumer : modifier.modifiers()) {
consumer.accept(tempEffect, context, 1);
}
}
// get the next loot
Loot loot = BukkitCustomFishingPlugin.getInstance().getLootManager().getNextLoot(effect, context);
if (loot == null) {
// TODO warn
BukkitCustomFishingPlugin.getInstance().debug("No loot available for player " + context.getHolder().getName());
return;
}
this.nextLoot = loot;
BukkitCustomFishingPlugin.getInstance().debug("Next loot: " + loot.id());
// get its basic properties
Effect baseEffect = loot.baseEffect().toEffect(context);
tempEffect.combine(baseEffect);
// apply the gears' effects
for (EffectModifier modifier : gears.effectModifiers()) {
for (TriConsumer<Effect, Context<Player>, Integer> consumer : modifier.modifiers()) {
consumer.accept(tempEffect, context, 2);
}
}
// start the mechanic
mechanic.start(tempEffect);
}
}
}
}, 1, 1, hook.getLocation());
}
public void cancel() {
public void destroy() {
task.cancel();
if (hook.isValid()) hook.remove();
if (hookMechanic != null) hookMechanic.destroy();
}
@NotNull
public FishHook getHookEntity() {
return hook;
}
@Nullable
public HookMechanic getCurrentHookMechanic() {
return hookMechanic;
}
@Nullable
public Loot getNextLoot() {
return nextLoot;
}
public void onReelIn() {
if (hookMechanic != null) {
if (!hookMechanic.isHooked()) {
destroy();
System.out.println("fail");
} else {
System.out.println("succeed");
}
}
}
public void onBite() {
gears.bite();
}
}

View File

@@ -20,16 +20,16 @@ import java.util.function.Consumer;
public class FishingGears {
private static BiConsumer<Context<Player>, FishingGears> fishingGearsGetter = defaultFishingGearsGetter();
private static BiConsumer<Context<Player>, FishingGears> fishingGearsConsumers = defaultFishingGearsConsumers();
private final HashMap<GearType, Collection<ItemStack>> gears = new HashMap<>();
private final ArrayList<EffectModifier> modifiers = new ArrayList<>();
public static void fishingGearsGetter(BiConsumer<Context<Player>, FishingGears> fishingGearsGetter) {
FishingGears.fishingGearsGetter = fishingGearsGetter;
public static void fishingGearsConsumers(BiConsumer<Context<Player>, FishingGears> fishingGearsConsumers) {
FishingGears.fishingGearsConsumers = fishingGearsConsumers;
}
public FishingGears(Context<Player> context) {
fishingGearsGetter.accept(context, this);
fishingGearsConsumers.accept(context, this);
}
public void cast() {
@@ -40,6 +40,38 @@ public class FishingGears {
}
}
public void reel() {
for (Map.Entry<GearType, Collection<ItemStack>> entry : gears.entrySet()) {
for (ItemStack itemStack : entry.getValue()) {
entry.getKey().reelFunction.accept(itemStack);
}
}
}
public void succeed() {
for (Map.Entry<GearType, Collection<ItemStack>> entry : gears.entrySet()) {
for (ItemStack itemStack : entry.getValue()) {
entry.getKey().successFunction.accept(itemStack);
}
}
}
public void fail() {
for (Map.Entry<GearType, Collection<ItemStack>> entry : gears.entrySet()) {
for (ItemStack itemStack : entry.getValue()) {
entry.getKey().failureFunction.accept(itemStack);
}
}
}
public void bite() {
for (Map.Entry<GearType, Collection<ItemStack>> entry : gears.entrySet()) {
for (ItemStack itemStack : entry.getValue()) {
entry.getKey().biteFunction.accept(itemStack);
}
}
}
@NotNull
public List<EffectModifier> effectModifiers() {
return modifiers;
@@ -50,7 +82,7 @@ public class FishingGears {
return gears.getOrDefault(type, List.of());
}
public static BiConsumer<Context<Player>, FishingGears> defaultFishingGearsGetter() {
public static BiConsumer<Context<Player>, FishingGears> defaultFishingGearsConsumers() {
return (context, fishingGears) -> {
Player player = context.getHolder();
PlayerInventory playerInventory = player.getInventory();
@@ -120,37 +152,43 @@ public class FishingGears {
public static final GearType ROD = new GearType("rod",
(itemStack -> {}),
(itemStack -> {}),
(itemStack -> BukkitCustomFishingPlugin.getInstance().getItemManager().decreaseDurability(itemStack)),
(itemStack -> {}),
(itemStack -> BukkitCustomFishingPlugin.getInstance().getItemManager().decreaseDurability(itemStack, 1, false)),
(itemStack -> {}));
public static final GearType BAIT = new GearType("bait",
(itemStack -> itemStack.setAmount(itemStack.getAmount() - 1)),
(itemStack -> {}),
(itemStack -> {}),
(itemStack -> {}),
(itemStack -> {}));
public static final GearType HOOK = new GearType("hook",
(itemStack -> {}),
(itemStack -> {}),
(itemStack -> {}),
(itemStack -> {}),
(itemStack -> {}));
public static final GearType UTIL = new GearType("util",
(itemStack -> {}),
(itemStack -> {}),
(itemStack -> {}),
(itemStack -> {}),
(itemStack -> {}));
private final String type;
private Consumer<ItemStack> castFunction;
private Consumer<ItemStack> reelFunction;
private Consumer<ItemStack> biteFunction;
private Consumer<ItemStack> successFunction;
private Consumer<ItemStack> failureFunction;
public GearType(String type, Consumer<ItemStack> castFunction, Consumer<ItemStack> reelFunction, Consumer<ItemStack> successFunction, Consumer<ItemStack> failureFunction) {
public GearType(String type, Consumer<ItemStack> castFunction, Consumer<ItemStack> reelFunction, Consumer<ItemStack> biteFunction, Consumer<ItemStack> successFunction, Consumer<ItemStack> failureFunction) {
this.type = type;
this.castFunction = castFunction;
this.reelFunction = reelFunction;
this.biteFunction = biteFunction;
this.successFunction = successFunction;
this.failureFunction = failureFunction;
}
@@ -163,6 +201,10 @@ public class FishingGears {
this.reelFunction = reelFunction;
}
public void biteFunction(Consumer<ItemStack> biteFunction) {
this.biteFunction = biteFunction;
}
public void successFunction(Consumer<ItemStack> successFunction) {
this.successFunction = successFunction;
}
@@ -183,5 +225,10 @@ public class FishingGears {
public int hashCode() {
return Objects.hashCode(type);
}
@Override
public String toString() {
return type;
}
}
}

View File

@@ -17,18 +17,18 @@
package net.momirealms.customfishing.api.mechanic.fishing;
import net.momirealms.customfishing.common.plugin.feature.Reloadable;
import org.bukkit.entity.FishHook;
import org.bukkit.entity.Player;
import java.util.Optional;
import java.util.UUID;
public interface FishingManager {
public interface FishingManager extends Reloadable {
Optional<CustomFishingHook> getFishHook(Player player);
Optional<FishHook> getFishHook(Player player);
Optional<FishHook> getFishHook(UUID player);
Optional<CustomFishingHook> getFishHook(UUID player);
Optional<Player> getOwner(FishHook hook);

View File

@@ -1,7 +1,6 @@
package net.momirealms.customfishing.api.mechanic.fishing.hook;
import net.momirealms.customfishing.api.mechanic.effect.Effect;
import org.bukkit.entity.FishHook;
public interface HookMechanic
{

View File

@@ -1,6 +1,49 @@
package net.momirealms.customfishing.api.mechanic.fishing.hook;
public class LavaFishingMechanic {
import net.momirealms.customfishing.api.mechanic.context.Context;
import net.momirealms.customfishing.api.mechanic.context.ContextKeys;
import net.momirealms.customfishing.api.mechanic.effect.Effect;
import net.momirealms.customfishing.api.mechanic.effect.EffectProperties;
import org.bukkit.entity.FishHook;
import org.bukkit.entity.Player;
public class LavaFishingMechanic implements HookMechanic {
private final FishHook hook;
private final Effect gearsEffect;
private final Context<Player> context;
public LavaFishingMechanic(FishHook hook, Effect gearsEffect, Context<Player> context) {
this.hook = hook;
this.gearsEffect = gearsEffect;
this.context = context;
}
@Override
public boolean canStart() {
if (!(boolean) gearsEffect.properties().getOrDefault(EffectProperties.LAVA_FISHING, false)) {
return false;
}
return hook.getLocation().getY() <= hook.getWorld().getMinHeight();
}
@Override
public void preStart() {
this.context.arg(ContextKeys.SURROUNDING, EffectProperties.LAVA_FISHING.key());
}
@Override
public void start(Effect finalEffect) {
}
@Override
public boolean isHooked() {
return false;
}
@Override
public void destroy() {
}
}

View File

@@ -1,31 +1,72 @@
package net.momirealms.customfishing.api.mechanic.fishing.hook;
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
import net.momirealms.customfishing.api.mechanic.context.Context;
import net.momirealms.customfishing.api.mechanic.context.ContextKeys;
import net.momirealms.customfishing.api.mechanic.effect.Effect;
import net.momirealms.customfishing.api.mechanic.effect.EffectProperties;
import net.momirealms.customfishing.common.plugin.scheduler.SchedulerTask;
import net.momirealms.sparrow.heart.SparrowHeart;
import org.bukkit.entity.FishHook;
import org.bukkit.entity.Player;
import java.util.concurrent.ThreadLocalRandom;
public class VanillaMechanic implements HookMechanic {
private final FishHook hook;
private final Context<Player> context;
private SchedulerTask task;
private boolean isHooked = false;
public VanillaMechanic(FishHook hook, Context<Player> context) {
this.hook = hook;
this.context = context;
}
@Override
public boolean canStart() {
return false;
return hook.isInWater();
}
@Override
public void preStart() {
this.context.arg(ContextKeys.SURROUNDING, EffectProperties.WATER_FISHING.key());
}
@Override
public void start(Effect finalEffect) {
setWaitTime(hook, finalEffect);
this.task = BukkitCustomFishingPlugin.getInstance().getScheduler().sync().runRepeating(() -> {
if (isHooked) {
if (!isHooked()) {
isHooked = false;
setWaitTime(hook, finalEffect);
}
} else {
if (isHooked()) {
isHooked = true;
}
}
}, 1, 1, hook.getLocation());
}
private void setWaitTime(FishHook hook, Effect effect) {
BukkitCustomFishingPlugin.getInstance().getScheduler().sync().runLater(() -> {
int before = hook.getWaitTime();
int after = (int) Math.max(1, before * effect.waitTimeMultiplier() + effect.waitTimeAdder());
BukkitCustomFishingPlugin.getInstance().debug("Wait time: " + before + " -> " + after + " ticks");
hook.setWaitTime(after);
}, 1, hook.getLocation());
}
@Override
public boolean isHooked() {
return false;
return SparrowHeart.getInstance().isFishingHookBit(hook);
}
@Override
public void destroy() {
if (this.task != null) this.task.cancel();
}
}

View File

@@ -4,6 +4,7 @@ import net.momirealms.customfishing.api.mechanic.context.Context;
import net.momirealms.customfishing.api.mechanic.context.ContextKeys;
import net.momirealms.customfishing.api.mechanic.effect.Effect;
import net.momirealms.customfishing.api.mechanic.effect.EffectProperties;
import net.momirealms.customfishing.common.plugin.scheduler.SchedulerTask;
import org.bukkit.entity.FishHook;
import org.bukkit.entity.Player;

View File

@@ -58,7 +58,7 @@ public interface ItemManager extends Reloadable {
@Nullable
Item dropItemLoot(@NotNull Context<Player> context);
void decreaseDurability(ItemStack itemStack);
void decreaseDurability(ItemStack itemStack, int amount, boolean incorrectUsage);
ItemFactory<CustomFishingPlugin, RtagItem, ItemStack> getFactory();

View File

@@ -62,9 +62,13 @@ public class MechanicType {
return Objects.equals(type, mechanicType.type);
}
@Override
public int hashCode() {
return Objects.hashCode(type);
}
@Override
public String toString() {
return type;
}
}

View File

@@ -41,6 +41,5 @@ public interface LootManager extends Reloadable {
Map<String, Double> getWeightedLoots(Context<Player> context);
@Nullable
Loot
getNextLoot(Effect effect, Context<Player> context);
Loot getNextLoot(Effect effect, Context<Player> context);
}

View File

@@ -0,0 +1,28 @@
package net.momirealms.customfishing.api.mechanic.requirement;
import java.util.Map;
public class ConditionalElement<E, T> {
private final E element;
private final Map<String, ConditionalElement<E, T>> subElements;
private final Requirement<T>[] requirements;
public ConditionalElement(E element, Map<String, ConditionalElement<E, T>> subElements, Requirement<T>[] requirements) {
this.element = element;
this.subElements = subElements;
this.requirements = requirements;
}
public E getElement() {
return element;
}
public Requirement<T>[] getRequirements() {
return requirements;
}
public Map<String, ConditionalElement<E, T>> getSubElements() {
return subElements;
}
}

View File

@@ -74,7 +74,7 @@ public interface RequirementManager<T> extends Reloadable {
* @return An array of Requirement objects based on the configuration section.
*/
@NotNull
Requirement<T>[] parseRequirements(@NotNull Section section, boolean runActions);
Requirement<T>[] parseRequirements(Section section, boolean runActions);
/**
* Retrieves a Requirement object based on a configuration section and advanced flag.

View File

@@ -15,7 +15,6 @@ subprojects {
repositories {
mavenCentral()
maven("https://jitpack.io/") // sparrow-heart, rtag
maven("https://repo.xenondevs.xyz/releases") // invui
maven("https://papermc.io/repo/repository/maven-public/") // paper
maven("https://oss.sonatype.org/content/repositories/snapshots")
maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") // spigot

View File

@@ -102,6 +102,10 @@ public class VersionHelper {
return version >= 20.0;
}
public static boolean isVersionNewerThan1_20_5() {
return version >= 20.5;
}
public boolean isNewerThan1_20_5() {
return version >= 20.5;
}

View File

@@ -17,6 +17,17 @@ public class AbstractItem<R, I> implements Item<I> {
this.item = item;
}
@Override
public Item<I> damage(Integer data) {
factory.damage(item, data);
return this;
}
@Override
public Optional<Integer> damage() {
return factory.damage(item);
}
@Override
public Item<I> customModelData(Integer data) {
factory.customModelData(item, data);

View File

@@ -9,6 +9,10 @@ public interface Item<I> {
Optional<Integer> customModelData();
Item<I> damage(Integer data);
Optional<Integer> damage();
Item<I> displayName(String displayName);
Optional<String> displayName();

View File

@@ -56,4 +56,8 @@ public abstract class ItemFactory<P extends CustomFishingPlugin, R, I> {
protected abstract Optional<Boolean> glint(R item);
protected abstract void glint(R item, Boolean glint);
protected abstract Optional<Integer> damage(R item);
protected abstract void damage(R item, Integer damage);
}

View File

@@ -0,0 +1,15 @@
package net.momirealms.customfishing.common.util;
import java.util.Objects;
import java.util.function.Function;
public interface TriFunction<T, U, V, R> {
R apply(T var1, U var2, V var3);
default <W> TriFunction<T, U, V, W> andThen(Function<? super R, ? extends W> after) {
Objects.requireNonNull(after);
return (t, u, v) -> {
return after.apply(this.apply(t, u, v));
};
}
}

View File

@@ -25,8 +25,11 @@ import java.util.Map;
/**
* Utility class for selecting random items based on weights.
*/
@SuppressWarnings("DuplicatedCode")
public class WeightUtils {
private WeightUtils() {}
/**
* Get a random item from a list of pairs, each associated with a weight.
*

View File

@@ -9,6 +9,7 @@ repositories {
maven("https://repo.auxilor.io/repository/maven-public/") // eco
maven("https://nexus.betonquest.org/repository/betonquest/") // betonquest
maven("https://repo.dmulloy2.net/repository/public/") // betonquest needs packet wrapper?
maven("https://maven.enginehub.org/repo/") // worldguard
}
dependencies {

View File

@@ -38,9 +38,11 @@ public class CustomFishingItemProvider implements ItemProvider {
public ItemStack buildItem(@NotNull Player player, @NotNull String id) {
String[] split = id.split(":", 2);
String finalID;
if (split.length != 2) {
if (split.length == 1) {
// CustomFishing:ID
finalID = split[0];
} else {
// CustomFishing:TYPE:ID
finalID = split[1];
}
ItemStack itemStack = BukkitCustomFishingPlugin.getInstance().getItemManager().buildInternal(Context.player(player), finalID);

View File

@@ -4,6 +4,10 @@ plugins {
id("io.github.goooler.shadow") version "8.1.7"
}
repositories {
maven("https://repo.xenondevs.xyz/releases") // invui
}
dependencies {
// platform
compileOnly("dev.folia:folia-api:${rootProject.properties["paper_version"]}-R0.1-SNAPSHOT")

Binary file not shown.

View File

@@ -14,6 +14,7 @@ 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.fishing.BukkitFishingManager;
import net.momirealms.customfishing.bukkit.gui.ChatCatcherManager;
import net.momirealms.customfishing.bukkit.hook.BukkitHookManager;
import net.momirealms.customfishing.bukkit.integration.BukkitIntegrationManager;
@@ -59,7 +60,6 @@ public class BukkitCustomFishingPluginImpl extends BukkitCustomFishingPlugin {
this.classPathAppender = new ReflectionClassPathAppender(this);
this.logger = new JavaPluginLogger(getBoostrap().getLogger());
this.dependencyManager = new DependencyManagerImpl(this);
this.debugger = (s) -> {};
}
@Override
@@ -104,6 +104,7 @@ public class BukkitCustomFishingPluginImpl extends BukkitCustomFishingPlugin {
this.statisticsManager = new BukkitStatisticsManager(this);
this.effectManager = new BukkitEffectManager(this);
this.hookManager = new BukkitHookManager(this);
this.fishingManager = new BukkitFishingManager(this);
this.bagManager = new BukkitBagManager(this);
this.totemManager = new BukkitTotemManager(this);
this.translationManager = new TranslationManager(this);
@@ -138,7 +139,7 @@ public class BukkitCustomFishingPluginImpl extends BukkitCustomFishingPlugin {
this.placeholderManager.reload();
this.configManager.reload();
// after ConfigManager
this.debugger = ConfigManager.debug() ? logger::info : (s) -> {};
this.debugger = ConfigManager.debug() ? (s) -> logger.info("[DEBUG] " + s) : (s) -> {};
this.actionManager.reload();
this.requirementManager.reload();
@@ -149,6 +150,7 @@ public class BukkitCustomFishingPluginImpl extends BukkitCustomFishingPlugin {
this.statisticsManager.reload();
this.bagManager.reload();
this.storageManager.reload();
this.fishingManager.reload();
this.itemManager.load();
this.eventManager.load();

View File

@@ -21,6 +21,8 @@ import net.momirealms.customfishing.common.util.ClassUtils;
import net.momirealms.customfishing.common.util.ListUtils;
import net.momirealms.customfishing.common.util.Pair;
import net.momirealms.customfishing.common.util.RandomUtils;
import net.momirealms.sparrow.heart.SparrowHeart;
import net.momirealms.sparrow.heart.feature.armorstand.FakeArmorStand;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
@@ -51,7 +53,6 @@ public class BukkitActionManager implements ActionManager<Player> {
public BukkitActionManager(BukkitCustomFishingPlugin plugin) {
this.plugin = plugin;
this.registerBuiltInActions();
}
@Override
@@ -89,6 +90,7 @@ public class BukkitActionManager implements ActionManager<Player> {
@Override
public Action<Player> parseAction(Section section) {
if (section == null) return EmptyAction.INSTANCE;
ActionFactory<Player> factory = getActionFactory(section.getString("type"));
if (factory == null) {
plugin.getPluginLogger().warn("Action type: " + section.getString("type") + " doesn't exist.");
@@ -100,8 +102,9 @@ public class BukkitActionManager implements ActionManager<Player> {
@NotNull
@Override
@SuppressWarnings("unchecked")
public Action<Player>[] parseActions(@NotNull Section section) {
public Action<Player>[] parseActions(Section section) {
ArrayList<Action<Player>> actionList = new ArrayList<>();
if (section != null)
for (Map.Entry<String, Object> entry : section.getStringRouteMappedValues(false).entrySet()) {
if (entry.getValue() instanceof Section innerSection) {
Action<Player> action = parseAction(innerSection);
@@ -136,6 +139,7 @@ public class BukkitActionManager implements ActionManager<Player> {
this.registerFishFindAction();
this.registerPluginExpAction();
this.registerSoundAction();
this.registerHologramAction();
this.registerTitleAction();
}
@@ -390,7 +394,7 @@ public class BukkitActionManager implements ActionManager<Player> {
itemStack.setAmount(Math.max(0, itemStack.getAmount() + amount));
};
} else {
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at item-amount action which should be Section");
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at item-amount action which is expected to be `Section`");
return EmptyAction.INSTANCE;
}
});
@@ -409,7 +413,7 @@ public class BukkitActionManager implements ActionManager<Player> {
// }
};
} 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 is expected to be `Section`");
return EmptyAction.INSTANCE;
}
});
@@ -432,7 +436,7 @@ public class BukkitActionManager implements ActionManager<Player> {
}
};
} else {
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at give-item action which should be Section");
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at give-item action which is expected to be `Section`");
return EmptyAction.INSTANCE;
}
});
@@ -543,7 +547,7 @@ public class BukkitActionManager implements ActionManager<Player> {
}
};
} else {
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at conditional action which should be Section");
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at conditional action which is expected to be `Section`");
return EmptyAction.INSTANCE;
}
});
@@ -575,7 +579,7 @@ public class BukkitActionManager implements ActionManager<Player> {
}
};
} else {
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at priority action which should be Section");
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at priority action which is expected to be `Section`");
return EmptyAction.INSTANCE;
}
});
@@ -611,7 +615,7 @@ public class BukkitActionManager implements ActionManager<Player> {
context.getHolder().addPotionEffect(potionEffect);
};
} else {
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at potion-effect action which should be Section");
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at potion-effect action which is expected to be `Section`");
return EmptyAction.INSTANCE;
}
});
@@ -632,7 +636,7 @@ public class BukkitActionManager implements ActionManager<Player> {
AdventureHelper.playSound(audience, sound);
};
} else {
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at sound action which should be Section");
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at sound action which is expected to be `Section`");
return EmptyAction.INSTANCE;
}
});
@@ -652,7 +656,7 @@ public class BukkitActionManager implements ActionManager<Player> {
}, () -> plugin.getPluginLogger().warn("Plugin (" + pluginName + "'s) level is not compatible. Please double check if it's a problem caused by pronunciation."));
};
} else {
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at plugin-exp action which should be Section");
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at plugin-exp action which is expected to be `Section`");
return EmptyAction.INSTANCE;
}
});
@@ -677,7 +681,7 @@ public class BukkitActionManager implements ActionManager<Player> {
);
};
} else {
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at title action which should be Section");
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at title action which is expected to be `Section`");
return EmptyAction.INSTANCE;
}
});
@@ -703,7 +707,7 @@ public class BukkitActionManager implements ActionManager<Player> {
);
};
} else {
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at random-title action which should be Section");
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at random-title action which is expected to be `Section`");
return EmptyAction.INSTANCE;
}
});
@@ -735,12 +739,61 @@ public class BukkitActionManager implements ActionManager<Player> {
);
};
} else {
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at title-nearby action which should be Section");
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at title-nearby action which is expected to be `Section`");
return EmptyAction.INSTANCE;
}
});
}
private void registerHologramAction() {
registerAction("hologram", ((args, chance) -> {
if (args instanceof Section section) {
TextValue<Player> text = TextValue.auto(section.getString("text", ""));
MathValue<Player> duration = MathValue.auto(section.get("duration", 20));
boolean position = section.getString("position", "other").equals("other");
MathValue<Player> x = MathValue.auto(section.get("x", 0));
MathValue<Player> y = MathValue.auto(section.get("y", 0));
MathValue<Player> z = MathValue.auto(section.get("z", 0));
int range = section.getInt("range", 16);
return context -> {
if (Math.random() > chance) return;
Player owner = context.getHolder();
Location location = position ? requireNonNull(context.arg(ContextKeys.LOCATION)).clone() : owner.getLocation().clone();
location.add(x.evaluate(context), y.evaluate(context), z.evaluate(context));
FakeArmorStand armorStand = SparrowHeart.getInstance().createFakeArmorStand(location);
armorStand.invisible(true);
armorStand.small(true);
armorStand.name(AdventureHelper.miniMessageToJson(text.render(context)));
ArrayList<Player> viewers = new ArrayList<>();
if (range > 0) {
for (Entity player : location.getWorld().getNearbyEntities(location, range, range, range, entity -> entity instanceof Player)) {
double distance = LocationUtils.getDistance(player.getLocation(), location);
if (distance <= range) {
viewers.add((Player) player);
}
}
} else {
viewers.add(owner);
}
for (Player player : viewers) {
armorStand.spawn(player);
}
plugin.getScheduler().asyncLater(() -> {
for (Player player : viewers) {
if (player.isOnline() && player.isValid()) {
armorStand.destroy(player);
}
}
}, (long) (duration.evaluate(context) * 50), TimeUnit.MILLISECONDS);
};
} else {
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at hologram action which is expected to be `Section`");
return EmptyAction.INSTANCE;
}
}));
}
private void registerFishFindAction() {
registerAction("fish-finder", (args, chance) -> {
return context -> {

View File

@@ -20,6 +20,7 @@ package net.momirealms.customfishing.bukkit.block;
import dev.dejvokep.boostedyaml.block.implementation.Section;
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
import net.momirealms.customfishing.api.integration.BlockProvider;
import net.momirealms.customfishing.api.integration.ExternalProvider;
import net.momirealms.customfishing.api.mechanic.block.*;
import net.momirealms.customfishing.api.mechanic.config.ConfigManager;
import net.momirealms.customfishing.api.mechanic.context.Context;
@@ -92,6 +93,11 @@ public class BukkitBlockManager implements BlockManager, Listener {
public void load() {
Bukkit.getPluginManager().registerEvents(this, plugin.getBoostrap());
this.resetBlockDetectionOrder();
for (BlockProvider provider : blockProviders.values()) {
plugin.debug("Registered BlockProvider: " + provider.identifier());
}
plugin.debug("Loaded " + blocks.size() + " blocks");
plugin.debug("Block order: " + Arrays.toString(Arrays.stream(blockDetectArray).map(ExternalProvider::identifier).toList().toArray(new String[0])));
}
@Override

View File

@@ -67,6 +67,7 @@ public class BukkitCompetitionManager implements CompetitionManager {
1,
TimeUnit.SECONDS
);
plugin.debug("Loaded " + commandConfigMap.size() + " competitions");
}
public void unload() {

View File

@@ -383,7 +383,8 @@ public class BukkitConfigManager extends ConfigManager {
}
}
private List<Pair<String, BiFunction<Context<Player>, Double, Double>>> parseWeightOperation(List<String> ops) {
@Override
public List<Pair<String, BiFunction<Context<Player>, Double, Double>>> parseWeightOperation(List<String> ops) {
List<Pair<String, BiFunction<Context<Player>, Double, Double>>> result = new ArrayList<>();
for (String op : ops) {
String[] split = op.split(":", 2);
@@ -392,7 +393,8 @@ public class BukkitConfigManager extends ConfigManager {
return result;
}
private List<Pair<String, BiFunction<Context<Player>, Double, Double>>> parseGroupWeightOperation(List<String> gops) {
@Override
public List<Pair<String, BiFunction<Context<Player>, Double, Double>>> parseGroupWeightOperation(List<String> gops) {
List<Pair<String, BiFunction<Context<Player>, Double, Double>>> result = new ArrayList<>();
for (String gop : gops) {
String[] split = gop.split(":", 2);

View File

@@ -41,7 +41,7 @@ public class BukkitEffectManager implements EffectManager {
@Override
public void load() {
plugin.debug("Loaded " + effectModifiers.size() + " effects");
}
@Override

View File

@@ -59,6 +59,14 @@ public class BukkitEntityManager implements EntityManager {
});
}
@Override
public void load() {
for (EntityProvider provider : entityProviders.values()) {
plugin.debug("Registered EntityProvider: " + provider.identifier());
}
plugin.debug("Loaded " + entities.size() + " entities");
}
@Override
public void unload() {
this.entities.clear();

View File

@@ -4,43 +4,61 @@ import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
import net.momirealms.customfishing.api.event.RodCastEvent;
import net.momirealms.customfishing.api.mechanic.config.ConfigManager;
import net.momirealms.customfishing.api.mechanic.context.Context;
import net.momirealms.customfishing.api.mechanic.effect.Effect;
import net.momirealms.customfishing.api.mechanic.fishing.FishingGears;
import net.momirealms.customfishing.api.mechanic.fishing.CustomFishingHook;
import net.momirealms.customfishing.api.mechanic.fishing.FishingGears;
import net.momirealms.customfishing.api.mechanic.fishing.FishingManager;
import net.momirealms.customfishing.api.mechanic.fishing.hook.VanillaMechanic;
import net.momirealms.customfishing.api.mechanic.requirement.RequirementManager;
import net.momirealms.customfishing.bukkit.util.EventUtils;
import net.momirealms.customfishing.common.helper.VersionHelper;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.Entity;
import org.bukkit.entity.FishHook;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerFishEvent;
import org.bukkit.event.player.PlayerItemHeldEvent;
import org.bukkit.event.player.PlayerSwapHandItemsEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.persistence.PersistentDataType;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
public class BukkitFishingManager implements FishingManager, Listener {
private BukkitCustomFishingPlugin plugin;
private final ConcurrentHashMap<UUID, FishHook> castHooks = new ConcurrentHashMap<>();
private final ConcurrentHashMap<UUID, FishingGears> gears = new ConcurrentHashMap<>();
private final ConcurrentHashMap<UUID, CustomFishingHook> tasks = new ConcurrentHashMap<>();
private final BukkitCustomFishingPlugin plugin;
private final ConcurrentHashMap<UUID, CustomFishingHook> castHooks = new ConcurrentHashMap<>();
public BukkitFishingManager(BukkitCustomFishingPlugin plugin) {
this.plugin = plugin;
}
@Override
public Optional<FishHook> getFishHook(Player player) {
return Optional.ofNullable(castHooks.get(player.getUniqueId()));
public void unload() {
HandlerList.unregisterAll(this);
}
@Override
public Optional<FishHook> getFishHook(UUID player) {
public void load() {
Bukkit.getPluginManager().registerEvents(this, plugin.getBoostrap());
}
@Override
public Optional<CustomFishingHook> getFishHook(Player player) {
return getFishHook(player.getUniqueId());
}
@Override
public Optional<CustomFishingHook> getFishHook(UUID player) {
return Optional.ofNullable(castHooks.get(player));
}
@@ -105,46 +123,87 @@ public class BukkitFishingManager implements FishingManager, Listener {
private void selectState(PlayerFishEvent event) {
switch (event.getState()) {
case FISHING -> onCastRod(event);
// case REEL_IN -> onReelIn(event);
// case CAUGHT_ENTITY -> onCaughtEntity(event);
// case CAUGHT_FISH -> onCaughtFish(event);
// case BITE -> onBite(event);
// case IN_GROUND -> onInGround(event);
case REEL_IN -> onReelIn(event);
case CAUGHT_ENTITY -> onCaughtEntity(event);
case CAUGHT_FISH -> onCaughtFish(event);
case BITE -> onBite(event);
case IN_GROUND -> onInGround(event);
}
}
private void onCaughtEntity(PlayerFishEvent event) {
final Player player = event.getPlayer();
getFishHook(player).ifPresent(hook -> {
Entity entity = event.getCaught();
if (entity != null && entity.getPersistentDataContainer().get(
Objects.requireNonNull(NamespacedKey.fromString("temp-entity", plugin.getBoostrap())),
PersistentDataType.STRING
) != null) {
}
});
}
private void onReelIn(PlayerFishEvent event) {
Player player = event.getPlayer();
getFishHook(player).ifPresent(hook -> {
hook.onReelIn();
});
}
private void onBite(PlayerFishEvent event) {
Player player = event.getPlayer();
getFishHook(player).ifPresent(hook -> {
hook.onBite();
});
}
private void onCaughtFish(PlayerFishEvent event) {
Player player = event.getPlayer();
getFishHook(player).ifPresent(hook -> {
hook.onReelIn();
});
}
private void onCastRod(PlayerFishEvent event) {
FishHook hook = event.getHook();
Player player = event.getPlayer();
Context<Player> context = Context.player(player);
FishingGears gears = new FishingGears(context);
this.gears.put(player.getUniqueId(), gears);
if (!RequirementManager.isSatisfied(context, ConfigManager.mechanicRequirements())) {
this.destroy(player.getUniqueId());
event.setCancelled(true);
return;
}
RodCastEvent rodCastEvent = new RodCastEvent(event, gears);
Bukkit.getPluginManager().callEvent(rodCastEvent);
if (rodCastEvent.isCancelled()) {
if (EventUtils.fireAndCheckCancel(new RodCastEvent(event, gears))) {
return;
}
plugin.debug(context.toString());
gears.cast();
this.castHooks.put(player.getUniqueId(), hook);
CustomFishingHook customHook = new CustomFishingHook(hook, gears, context);
this.castHooks.put(player.getUniqueId(), customHook);
}
private void onInGround(PlayerFishEvent event) {
if (VersionHelper.isVersionNewerThan1_20_5()) return;
final Player player = event.getPlayer();
if (player.getGameMode() != GameMode.CREATIVE) {
ItemStack itemStack = player.getInventory().getItemInMainHand();
if (itemStack.getType() != Material.FISHING_ROD) itemStack = player.getInventory().getItemInOffHand();
if (itemStack.getType() == Material.FISHING_ROD) {
plugin.getItemManager().decreaseDurability(itemStack, 5, true);
}
}
}
@Override
public void destroy(UUID uuid) {
this.getFishHook(uuid).ifPresent(hook -> {
hook.remove();
hook.destroy();
this.castHooks.remove(uuid);
});
this.gears.remove(uuid);
CustomFishingHook task = this.tasks.remove(uuid);
if (task != null) {
task.cancel();
}
}
}

View File

@@ -34,6 +34,7 @@ public class BukkitHookManager implements HookManager, Listener {
@Override
public void load() {
Bukkit.getPluginManager().registerEvents(this, plugin.getBoostrap());
plugin.debug("Loaded " + hooks.size() + " hooks");
}
@Override

View File

@@ -3,6 +3,7 @@ package net.momirealms.customfishing.bukkit.item;
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
import net.momirealms.customfishing.api.event.FishingLootPreSpawnEvent;
import net.momirealms.customfishing.api.event.FishingLootSpawnEvent;
import net.momirealms.customfishing.api.integration.ExternalProvider;
import net.momirealms.customfishing.api.integration.ItemProvider;
import net.momirealms.customfishing.api.mechanic.config.ConfigManager;
import net.momirealms.customfishing.api.mechanic.context.Context;
@@ -10,6 +11,7 @@ import net.momirealms.customfishing.api.mechanic.context.ContextKeys;
import net.momirealms.customfishing.api.mechanic.item.CustomFishingItem;
import net.momirealms.customfishing.api.mechanic.item.ItemManager;
import net.momirealms.customfishing.api.mechanic.item.MechanicType;
import net.momirealms.customfishing.bukkit.integration.item.CustomFishingItemProvider;
import net.momirealms.customfishing.bukkit.util.ItemUtils;
import net.momirealms.customfishing.bukkit.util.LocationUtils;
import net.momirealms.customfishing.common.item.Item;
@@ -67,6 +69,7 @@ public class BukkitItemManager implements ItemManager, Listener {
return "vanilla";
}
});
this.registerItemProvider(new CustomFishingItemProvider());
}
@Override
@@ -79,6 +82,11 @@ public class BukkitItemManager implements ItemManager, Listener {
public void load() {
Bukkit.getPluginManager().registerEvents(this, plugin.getBoostrap());
this.resetItemDetectionOrder();
for (ItemProvider provider : itemProviders.values()) {
plugin.debug("Registered ItemProvider: " + provider.identifier());
}
plugin.debug("Loaded " + items.size() + " items");
plugin.debug("Item order: " + Arrays.toString(Arrays.stream(itemDetectArray).map(ExternalProvider::identifier).toList().toArray(new String[0])));
}
@Override
@@ -220,7 +228,7 @@ public class BukkitItemManager implements ItemManager, Listener {
}
@Override
public void decreaseDurability(ItemStack itemStack) {
public void decreaseDurability(ItemStack itemStack, int amount, boolean incorrectUsage) {
}

View File

@@ -93,21 +93,38 @@ public class ComponentItemFactory extends BukkitItemFactory {
@Override
protected boolean unbreakable(RtagItem item) {
return false;
return item.isUnbreakable();
}
@Override
protected void unbreakable(RtagItem item, boolean unbreakable) {
item.setUnbreakable(unbreakable);
}
@Override
protected Optional<Boolean> glint(RtagItem item) {
return Optional.empty();
return Optional.ofNullable((Boolean) item.getComponent(ComponentKeys.ENCHANTMENT_GLINT_OVERRIDE));
}
@Override
protected void glint(RtagItem item, Boolean glint) {
item.setComponent(ComponentKeys.ENCHANTMENT_GLINT_OVERRIDE, glint);
}
@Override
protected Optional<Integer> damage(RtagItem item) {
if (!item.hasComponent(ComponentKeys.DAMAGE)) return Optional.empty();
return Optional.ofNullable(
(Integer) ComponentType.encodeJava(
ComponentKeys.DAMAGE,
item.getComponent(ComponentKeys.DAMAGE)
).orElse(null)
);
}
@Override
protected void damage(RtagItem item, Integer damage) {
if (damage == null) damage = 0;
item.setComponent(ComponentKeys.DAMAGE, damage);
}
}

View File

@@ -70,21 +70,32 @@ public class UniversalItemFactory extends BukkitItemFactory {
@Override
protected boolean unbreakable(RtagItem item) {
return false;
return item.isUnbreakable();
}
@Override
protected void unbreakable(RtagItem item, boolean unbreakable) {
item.setUnbreakable(unbreakable);
}
@Override
protected Optional<Boolean> glint(RtagItem item) {
return Optional.empty();
return Optional.of(false);
}
@Override
protected void glint(RtagItem item, Boolean glint) {
throw new UnsupportedOperationException("This feature is only available on 1.20.5+");
}
@Override
protected Optional<Integer> damage(RtagItem item) {
if (!item.hasTag("Damage")) return Optional.empty();
return Optional.of(item.get("Damage"));
}
@Override
protected void damage(RtagItem item, Integer damage) {
item.set(damage, "Damage");
}
}

View File

@@ -1,24 +1,30 @@
package net.momirealms.customfishing.bukkit.loot;
import dev.dejvokep.boostedyaml.YamlDocument;
import dev.dejvokep.boostedyaml.block.implementation.Section;
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
import net.momirealms.customfishing.api.mechanic.context.Context;
import net.momirealms.customfishing.api.mechanic.effect.Effect;
import net.momirealms.customfishing.api.mechanic.loot.Loot;
import net.momirealms.customfishing.api.mechanic.loot.LootManager;
import net.momirealms.customfishing.api.mechanic.requirement.ConditionalElement;
import net.momirealms.customfishing.api.mechanic.requirement.RequirementManager;
import net.momirealms.customfishing.common.util.Pair;
import net.momirealms.customfishing.common.util.WeightUtils;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Optional;
import java.io.File;
import java.util.*;
import java.util.function.BiFunction;
public class BukkitLootManager implements LootManager {
private final BukkitCustomFishingPlugin plugin;
private final HashMap<String, Loot> lootMap = new HashMap<>();
private final HashMap<String, List<String>> groupMembersMap = new HashMap<>();
private final LinkedHashMap<String, ConditionalElement<List<Pair<String, BiFunction<Context<Player>, Double, Double>>>, Player>> lootConditions = new LinkedHashMap<>();
public BukkitLootManager(BukkitCustomFishingPlugin plugin) {
this.plugin = plugin;
@@ -28,11 +34,48 @@ public class BukkitLootManager implements LootManager {
public void unload() {
this.lootMap.clear();
this.groupMembersMap.clear();
this.lootConditions.clear();
}
@Override
public void load() {
plugin.debug("Loaded " + lootMap.size() + " loots");
for (Map.Entry<String, List<String>> entry : groupMembersMap.entrySet()) {
plugin.debug("Group: {" + entry.getKey() + "} Members: " + entry.getValue());
}
File file = new File(plugin.getDataFolder(), "loot-conditions.yml");
if (!file.exists()) {
plugin.getBoostrap().saveResource("loot-conditions.yml", false);
}
YamlDocument lootConditionsConfig = plugin.getConfigManager().loadData(file);
for (Map.Entry<String, Object> entry : lootConditionsConfig.getStringRouteMappedValues(false).entrySet()) {
if (entry.getValue() instanceof Section section) {
lootConditions.put(entry.getKey(), parseLootConditions(section));
}
}
}
private ConditionalElement<List<Pair<String, BiFunction<Context<Player>, Double, Double>>>, Player> parseLootConditions(Section section) {
Section subSection = section.getSection("sub-groups");
if (subSection == null) {
return new ConditionalElement<>(
plugin.getConfigManager().parseWeightOperation(section.getStringList("list")),
Map.of(),
plugin.getRequirementManager().parseRequirements(section.getSection("conditions"), false)
);
} else {
HashMap<String, ConditionalElement<List<Pair<String, BiFunction<Context<Player>, Double, Double>>>, Player>> subElements = new HashMap<>();
for (Map.Entry<String, Object> entry : subSection.getStringRouteMappedValues(false).entrySet()) {
if (entry.getValue() instanceof Section innerSection) {
subElements.put(entry.getKey(), parseLootConditions(innerSection));
}
}
return new ConditionalElement<>(
plugin.getConfigManager().parseWeightOperation(section.getStringList("list")),
subElements,
plugin.getRequirementManager().parseRequirements(section.getSection("conditions"), false)
);
}
}
@Override
@@ -73,6 +116,33 @@ public class BukkitLootManager implements LootManager {
@Nullable
@Override
public Loot getNextLoot(Effect effect, Context<Player> context) {
return null;
HashMap<String, Double> lootWeightMap = new HashMap<>();
for (ConditionalElement<List<Pair<String, BiFunction<Context<Player>, Double, Double>>>, Player> conditionalElement : lootConditions.values()) {
modifyWeightMap(lootWeightMap, context, conditionalElement);
}
for (Pair<String, BiFunction<Context<Player>, Double, Double>> pair : effect.weightOperations()) {
double previous = lootWeightMap.getOrDefault(pair.left(), 0d);
if (previous > 0)
lootWeightMap.put(pair.left(), pair.right().apply(context, previous));
}
for (Pair<String, BiFunction<Context<Player>, Double, Double>> pair : effect.weightOperationsIgnored()) {
double previous = lootWeightMap.getOrDefault(pair.left(), 0d);
lootWeightMap.put(pair.left(), pair.right().apply(context, previous));
}
String lootID = WeightUtils.getRandom(lootWeightMap);
return getLoot(lootID).orElseThrow(() -> new RuntimeException("Could not find loot " + lootID));
}
private void modifyWeightMap(Map<String, Double> weightMap, Context<Player> context, ConditionalElement<List<Pair<String, BiFunction<Context<Player>, Double, Double>>>, Player> conditionalElement) {
if (conditionalElement == null) return;
if (RequirementManager.isSatisfied(context, conditionalElement.getRequirements())) {
for (Pair<String, BiFunction<Context<Player>, Double, Double>> modifierPair : conditionalElement.getElement()) {
double previous = weightMap.getOrDefault(modifierPair.left(), 0d);
weightMap.put(modifierPair.left(), modifierPair.right().apply(context, previous));
}
for (ConditionalElement<List<Pair<String, BiFunction<Context<Player>, Double, Double>>>, Player> sub : conditionalElement.getSubElements().values()) {
modifyWeightMap(weightMap, context, sub);
}
}
}
}

View File

@@ -26,6 +26,7 @@ import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.NotNull;
@@ -85,8 +86,9 @@ public class BukkitRequirementManager implements RequirementManager<Player> {
@NotNull
@Override
@SuppressWarnings("unchecked")
public Requirement<Player>[] parseRequirements(@NotNull Section section, boolean runActions) {
public Requirement<Player>[] parseRequirements(Section section, boolean runActions) {
List<Requirement<Player>> requirements = new ArrayList<>();
if (section != null)
for (Map.Entry<String, Object> entry : section.getStringRouteMappedValues(false).entrySet()) {
String typeOrName = entry.getKey();
if (hasRequirement(typeOrName)) {
@@ -164,6 +166,7 @@ public class BukkitRequirementManager implements RequirementManager<Player> {
this.registerInBagRequirement();
this.registerCompetitionRequirement();
this.registerPluginLevelRequirement();
this.registerItemInHandRequirement();
}
private void registerCompetitionRequirement() {
@@ -191,7 +194,7 @@ public class BukkitRequirementManager implements RequirementManager<Player> {
return false;
};
} else {
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at competition requirement which should be Section");
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at competition requirement which is expected be `Section`");
return EmptyRequirement.INSTANCE;
}
});
@@ -209,6 +212,28 @@ public class BukkitRequirementManager implements RequirementManager<Player> {
});
}
private void registerItemInHandRequirement() {
registerRequirement("item-in-hand", (args, actions, advanced) -> {
if (args instanceof Section section) {
boolean mainOrOff = section.getString("hand","main").equalsIgnoreCase("main");
int amount = section.getInt("amount", 1);
List<String> items = ListUtils.toList(section.get("item"));
return context -> {
ItemStack itemStack = mainOrOff ?
context.getHolder().getInventory().getItemInMainHand()
: context.getHolder().getInventory().getItemInOffHand();
String id = plugin.getItemManager().getItemID(itemStack);
if (items.contains(id) && itemStack.getAmount() >= amount) return true;
if (advanced) ActionManager.trigger(context, actions);
return false;
};
} else {
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at item-in-hand requirement which is expected be `Section`");
return EmptyRequirement.INSTANCE;
}
});
}
private void registerPluginLevelRequirement() {
registerRequirement("plugin-level", (args, actions, advanced) -> {
if (args instanceof Section section) {
@@ -227,7 +252,7 @@ public class BukkitRequirementManager implements RequirementManager<Player> {
return false;
};
} else {
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at plugin-level requirement which should be Section");
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at plugin-level requirement which is expected be `Section`");
return EmptyRequirement.INSTANCE;
}
});
@@ -283,7 +308,7 @@ public class BukkitRequirementManager implements RequirementManager<Player> {
return false;
};
} else {
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at || requirement which should be Section");
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at || requirement which is expected be `Section`");
return EmptyRequirement.INSTANCE;
}
});
@@ -304,7 +329,7 @@ public class BukkitRequirementManager implements RequirementManager<Player> {
return false;
};
} else {
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at && requirement which should be Section");
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at && requirement which is expected be `Section`");
return EmptyRequirement.INSTANCE;
}
});
@@ -335,11 +360,19 @@ public class BukkitRequirementManager implements RequirementManager<Player> {
}
private void registerInLavaRequirement() {
// Deprecated requirement type
registerRequirement("lava-fishing", (args, actions, advanced) -> {
boolean inLava = (boolean) args;
if (!inLava) {
throw new IllegalArgumentException("");
// in water
return context -> {
boolean in_water = Optional.ofNullable(context.arg(ContextKeys.SURROUNDING)).orElse("").equals(EffectProperties.WATER_FISHING.key());
if (in_water) return true;
if (advanced) ActionManager.trigger(context, actions);
return false;
};
}
// in lava
return context -> {
boolean in_lava = Optional.ofNullable(context.arg(ContextKeys.SURROUNDING)).orElse("").equals(EffectProperties.LAVA_FISHING.key());
if (in_lava) return true;
@@ -768,7 +801,7 @@ public class BukkitRequirementManager implements RequirementManager<Player> {
return false;
};
} else {
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at cooldown requirement which should be Section");
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at cooldown requirement which is expected be `Section`");
return EmptyRequirement.INSTANCE;
}
});
@@ -839,7 +872,7 @@ public class BukkitRequirementManager implements RequirementManager<Player> {
return false;
};
} else {
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at < requirement which should be Section");
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at < requirement which is expected be `Section`");
return EmptyRequirement.INSTANCE;
}
});
@@ -853,7 +886,7 @@ public class BukkitRequirementManager implements RequirementManager<Player> {
return false;
};
} else {
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at <= requirement which should be Section");
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at <= requirement which is expected be `Section`");
return EmptyRequirement.INSTANCE;
}
});
@@ -867,7 +900,7 @@ public class BukkitRequirementManager implements RequirementManager<Player> {
return false;
};
} else {
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at != requirement which should be Section");
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at != requirement which is expected be `Section`");
return EmptyRequirement.INSTANCE;
}
});
@@ -881,7 +914,7 @@ public class BukkitRequirementManager implements RequirementManager<Player> {
return false;
};
} else {
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at == requirement which should be Section");
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at == requirement which is expected be `Section`");
return EmptyRequirement.INSTANCE;
}
});
@@ -895,7 +928,7 @@ public class BukkitRequirementManager implements RequirementManager<Player> {
return false;
};
} else {
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at >= requirement which should be Section");
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at >= requirement which is expected be `Section`");
return EmptyRequirement.INSTANCE;
}
});
@@ -909,7 +942,7 @@ public class BukkitRequirementManager implements RequirementManager<Player> {
return false;
};
} else {
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at > requirement which should be Section");
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at > requirement which is expected be `Section`");
return EmptyRequirement.INSTANCE;
}
});
@@ -923,7 +956,7 @@ public class BukkitRequirementManager implements RequirementManager<Player> {
return false;
};
} else {
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at regex requirement which should be Section");
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at regex requirement which is expected be `Section`");
return EmptyRequirement.INSTANCE;
}
});
@@ -937,7 +970,7 @@ public class BukkitRequirementManager implements RequirementManager<Player> {
return false;
};
} else {
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at startsWith requirement which should be Section");
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at startsWith requirement which is expected be `Section`");
return EmptyRequirement.INSTANCE;
}
});
@@ -951,7 +984,7 @@ public class BukkitRequirementManager implements RequirementManager<Player> {
return false;
};
} else {
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at !startsWith requirement which should be Section");
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at !startsWith requirement which is expected be `Section`");
return EmptyRequirement.INSTANCE;
}
});
@@ -965,7 +998,7 @@ public class BukkitRequirementManager implements RequirementManager<Player> {
return false;
};
} else {
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at endsWith requirement which should be Section");
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at endsWith requirement which is expected be `Section`");
return EmptyRequirement.INSTANCE;
}
});
@@ -979,7 +1012,7 @@ public class BukkitRequirementManager implements RequirementManager<Player> {
return false;
};
} else {
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at !endsWith requirement which should be Section");
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at !endsWith requirement which is expected be `Section`");
return EmptyRequirement.INSTANCE;
}
});
@@ -993,7 +1026,7 @@ public class BukkitRequirementManager implements RequirementManager<Player> {
return false;
};
} else {
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at contains requirement which should be Section");
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at contains requirement which is expected be `Section`");
return EmptyRequirement.INSTANCE;
}
});
@@ -1007,7 +1040,7 @@ public class BukkitRequirementManager implements RequirementManager<Player> {
return false;
};
} else {
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at !contains requirement which should be Section");
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at !contains requirement which is expected be `Section`");
return EmptyRequirement.INSTANCE;
}
});
@@ -1021,7 +1054,7 @@ public class BukkitRequirementManager implements RequirementManager<Player> {
return false;
};
} else {
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at in-list requirement which should be Section");
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at in-list requirement which is expected be `Section`");
return EmptyRequirement.INSTANCE;
}
});
@@ -1035,7 +1068,7 @@ public class BukkitRequirementManager implements RequirementManager<Player> {
return false;
};
} else {
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at !in-list requirement which should be Section");
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at !in-list requirement which is expected be `Section`");
return EmptyRequirement.INSTANCE;
}
});
@@ -1049,7 +1082,7 @@ public class BukkitRequirementManager implements RequirementManager<Player> {
return false;
};
} else {
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at equals requirement which should be Section");
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at equals requirement which is expected be `Section`");
return EmptyRequirement.INSTANCE;
}
});
@@ -1063,7 +1096,7 @@ public class BukkitRequirementManager implements RequirementManager<Player> {
return false;
};
} else {
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at !equals requirement which should be Section");
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at !equals requirement which is expected be `Section`");
return EmptyRequirement.INSTANCE;
}
});

View File

@@ -37,6 +37,9 @@ public class BukkitStatisticsManager implements StatisticsManager {
@Override
public void load() {
this.loadCategoriesFromPluginFolder();
for (Map.Entry<String, List<String>> entry : categoryMap.entrySet()) {
plugin.debug("Category: {" + entry.getKey() + "} Members: " + entry.getValue());
}
}
@Override

View File

@@ -79,6 +79,7 @@ public class BukkitTotemManager implements TotemManager, Listener {
activatedTotems.remove(simpleLocation);
}
}, 1, 1, TimeUnit.SECONDS);
plugin.debug("Loaded " + id2Totem.size() + " totems");
}
@Override

View File

@@ -0,0 +1,36 @@
/*
* 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 org.bukkit.Bukkit;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
public class EventUtils {
public static void fireAndForget(Event event) {
Bukkit.getPluginManager().callEvent(event);
}
public static boolean fireAndCheckCancel(Event event) {
if (!(event instanceof Cancellable cancellable))
throw new IllegalArgumentException("Only cancellable events are allowed here");
Bukkit.getPluginManager().callEvent(event);
return cancellable.isCancelled();
}
}

View File

@@ -350,6 +350,12 @@ mechanics:
# Lava fishing settings
# To modify vanilla fishing time, you should edit paper-world-defaults.yml where there's a section called fishing-time-range
lava-fishing:
enable: true
# ticks
min-wait-time: 100
max-wait-time: 600
void-fishing:
enable: true
# ticks
min-wait-time: 100
max-wait-time: 600

View File

@@ -16,8 +16,8 @@ jar_relocator_version=1.7
h2_driver_version=2.2.224
sqlite_driver_version=3.46.0.0
adventure_bundle_version=4.17.0
adventure_platform_version=4.3.2
sparrow_heart_version=0.16
adventure_platform_version=4.3.3
sparrow_heart_version=0.20
cloud_core_version=2.0.0-rc.2
cloud_services_version=2.0.0-rc.2
cloud_brigadier_version=2.0.0-beta.8
@@ -38,8 +38,8 @@ caffeine_version=3.1.8
rtag_version=1.5.3
jedis_version=5.1.2
exp4j_version=0.4.8
placeholder_api_version=2.11.5
invui_version=1.31
placeholder_api_version=2.11.6
invui_version=1.32
vault_version=1.7
guava_version=33.2.0-jre