9
0
mirror of https://github.com/Xiao-MoMi/Custom-Crops.git synced 2025-12-28 03:19:15 +00:00

Fix some logics

This commit is contained in:
XiaoMoMi
2024-09-01 16:39:25 +08:00
parent 139cd9649d
commit 37688940ca
36 changed files with 248 additions and 174 deletions

View File

@@ -19,6 +19,7 @@ package net.momirealms.customcrops.api.action;
import dev.dejvokep.boostedyaml.block.implementation.Section;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.text.Component;
import net.momirealms.customcrops.api.BukkitCustomCropsPlugin;
import net.momirealms.customcrops.api.context.Context;
import net.momirealms.customcrops.api.context.ContextKeys;
@@ -32,6 +33,7 @@ import net.momirealms.customcrops.api.core.world.CustomCropsWorld;
import net.momirealms.customcrops.api.core.world.Pos3;
import net.momirealms.customcrops.api.core.wrapper.WrappedBreakEvent;
import net.momirealms.customcrops.api.event.CropPlantEvent;
import net.momirealms.customcrops.api.misc.HologramManager;
import net.momirealms.customcrops.api.misc.placeholder.BukkitPlaceholderManager;
import net.momirealms.customcrops.api.misc.value.MathValue;
import net.momirealms.customcrops.api.misc.value.TextValue;
@@ -40,7 +42,10 @@ import net.momirealms.customcrops.api.util.*;
import net.momirealms.customcrops.common.helper.AdventureHelper;
import net.momirealms.customcrops.common.helper.VersionHelper;
import net.momirealms.customcrops.common.plugin.scheduler.SchedulerTask;
import net.momirealms.customcrops.common.util.*;
import net.momirealms.customcrops.common.util.ClassUtils;
import net.momirealms.customcrops.common.util.ListUtils;
import net.momirealms.customcrops.common.util.Pair;
import net.momirealms.customcrops.common.util.RandomUtils;
import net.momirealms.sparrow.heart.SparrowHeart;
import net.momirealms.sparrow.heart.feature.entity.FakeEntity;
import net.momirealms.sparrow.heart.feature.entity.armorstand.FakeArmorStand;
@@ -83,6 +88,7 @@ public abstract class AbstractActionManager<T> implements ActionManager<T> {
this.registerDropItemsAction();
this.registerLegacyDropItemsAction();
this.registerFakeItemAction();
this.registerHologramAction();
this.registerPlantAction();
this.registerBreakAction();
}
@@ -725,21 +731,84 @@ public abstract class AbstractActionManager<T> implements ActionManager<T> {
}, "drop-items");
}
private void registerFakeItemAction() {
protected void registerHologramAction() {
registerAction(((args, chance) -> {
if (args instanceof Section section) {
TextValue<T> text = TextValue.auto(section.getString("text", ""));
MathValue<T> duration = MathValue.auto(section.get("duration", 20));
boolean other = section.getString("position", "other").equals("other");
MathValue<T> x = MathValue.auto(section.get("x", 0));
MathValue<T> y = MathValue.auto(section.get("y", 0));
MathValue<T> z = MathValue.auto(section.get("z", 0));
boolean applyCorrection = section.getBoolean("apply-correction", false);
boolean onlyShowToOne = !section.getBoolean("visible-to-all", false);
int range = section.getInt("range", 32);
return context -> {
if (context.holder() == null) return;
if (Math.random() > chance) return;
Player owner = null;
if (context.holder() instanceof Player p) {
owner = p;
}
Location location = other ? requireNonNull(context.arg(ContextKeys.LOCATION)).clone() : owner.getLocation().clone();
Pos3 pos3 = Pos3.from(location).add(0,1,0);
location.add(x.evaluate(context), y.evaluate(context), z.evaluate(context));
Optional<CustomCropsWorld<?>> optionalWorld = plugin.getWorldManager().getWorld(location.getWorld());
if (optionalWorld.isEmpty()) {
return;
}
if (applyCorrection) {
Optional<CustomCropsBlockState> optionalState = optionalWorld.get().getBlockState(pos3);
if (optionalState.isPresent()) {
if (optionalState.get().type() instanceof CropBlock cropBlock) {
CropConfig config = cropBlock.config(optionalState.get());
int point = cropBlock.point(optionalState.get());
if (config != null) {
CropStageConfig stageConfig = config.stageWithModelByPoint(point);
location.add(0,stageConfig.displayInfoOffset(),0);
}
}
}
}
ArrayList<Player> viewers = new ArrayList<>();
if (onlyShowToOne) {
if (owner == null) return;
viewers.add(owner);
} else {
for (Player player : location.getWorld().getPlayers()) {
if (LocationUtils.getDistance(player.getLocation(), location) <= range) {
viewers.add(player);
}
}
}
if (viewers.isEmpty()) return;
Component component = AdventureHelper.miniMessage(text.render(context));
for (Player viewer : viewers) {
HologramManager.getInstance().showHologram(viewer, location, AdventureHelper.componentToJson(component), (int) (duration.evaluate(context) * 50));
}
};
} else {
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at hologram action which is expected to be `Section`");
return Action.empty();
}
}), "hologram");
}
protected void registerFakeItemAction() {
registerAction(((args, chance) -> {
if (args instanceof Section section) {
String itemID = section.getString("item", "");
String[] split = itemID.split(":");
if (split.length >= 2) itemID = split[split.length - 1];
MathValue<T> duration = MathValue.auto(section.get("duration", 20));
boolean position = !section.getString("position", "player").equals("player");
boolean other = section.getString("position", "other").equals("other");
MathValue<T> x = MathValue.auto(section.get("x", 0));
MathValue<T> y = MathValue.auto(section.get("y", 0));
MathValue<T> z = MathValue.auto(section.get("z", 0));
MathValue<T> yaw = MathValue.auto(section.get("yaw", 0));
int range = section.getInt("range", 0);
int range = section.getInt("range", 32);
boolean visibleToAll = section.getBoolean("visible-to-all", true);
boolean useItemDisplay = section.getBoolean("use-item-display", false);
boolean onlyShowToOne = !section.getBoolean("visible-to-all", true);
String finalItemID = itemID;
return context -> {
if (Math.random() > chance) return;
@@ -748,8 +817,8 @@ public abstract class AbstractActionManager<T> implements ActionManager<T> {
if (context.holder() instanceof Player p) {
owner = p;
}
Location location = position ? requireNonNull(context.arg(ContextKeys.LOCATION)).clone() : requireNonNull(owner).getLocation().clone();
location.add(x.evaluate(context), y.evaluate(context) - 1, z.evaluate(context));
Location location = other ? requireNonNull(context.arg(ContextKeys.LOCATION)).clone() : requireNonNull(owner).getLocation().clone();
location.add(x.evaluate(context), y.evaluate(context), z.evaluate(context));
location.setPitch(0);
location.setYaw((float) yaw.evaluate(context));
FakeEntity fakeEntity;
@@ -765,19 +834,18 @@ public abstract class AbstractActionManager<T> implements ActionManager<T> {
fakeEntity = armorStand;
}
ArrayList<Player> viewers = new ArrayList<>();
if (onlyShowToOne) {
viewers.add(owner);
} else {
if (range > 0) {
for (Player player : location.getWorld().getPlayers()) {
if (LocationUtils.getDistance(player.getLocation(), location) <= range) {
viewers.add(player);
}
if (range > 0 && visibleToAll) {
for (Player player : location.getWorld().getPlayers()) {
if (LocationUtils.getDistance(player.getLocation(), location) <= range) {
viewers.add(player);
}
} else {
}
} else {
if (owner != null) {
viewers.add(owner);
}
}
if (viewers.isEmpty()) return;
for (Player player : viewers) {
fakeEntity.spawn(player);
}

View File

@@ -18,6 +18,7 @@
package net.momirealms.customcrops.api.context;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.inventory.EquipmentSlot;
import java.util.Objects;
@@ -41,6 +42,7 @@ public class ContextKeys<T> {
public static final ContextKeys<EquipmentSlot> SLOT = of("slot", EquipmentSlot.class);
public static final ContextKeys<String> TEMP_NEAR_PLAYER = of("near", String.class);
public static final ContextKeys<Boolean> OFFLINE = of("offline", Boolean.class);
public static final ContextKeys<Player> PLAYER_INSTANCE = of("player_instance", Player.class);
private final String key;
private final Class<T> type;

View File

@@ -17,8 +17,8 @@
package net.momirealms.customcrops.api.core;
import net.momirealms.customcrops.common.util.Key;
import net.momirealms.customcrops.api.core.item.CustomCropsItem;
import net.momirealms.customcrops.common.util.Key;
public class BuiltInItemMechanics {

View File

@@ -16,9 +16,9 @@ import net.momirealms.customcrops.api.core.block.*;
import net.momirealms.customcrops.api.core.item.FertilizerConfig;
import net.momirealms.customcrops.api.core.item.FertilizerType;
import net.momirealms.customcrops.api.core.item.WateringCanConfig;
import net.momirealms.customcrops.api.core.world.CustomCropsBlockState;
import net.momirealms.customcrops.api.misc.water.FillMethod;
import net.momirealms.customcrops.api.misc.water.WateringMethod;
import net.momirealms.customcrops.api.core.world.CustomCropsBlockState;
import net.momirealms.customcrops.api.util.PluginUtils;
import net.momirealms.customcrops.common.config.ConfigLoader;
import net.momirealms.customcrops.common.plugin.feature.Reloadable;

View File

@@ -17,10 +17,10 @@
package net.momirealms.customcrops.api.core;
import net.momirealms.customcrops.common.util.Key;
import net.momirealms.customcrops.api.core.block.CustomCropsBlock;
import net.momirealms.customcrops.api.core.item.CustomCropsItem;
import net.momirealms.customcrops.api.core.item.FertilizerType;
import net.momirealms.customcrops.common.util.Key;
public interface RegistryAccess {

View File

@@ -17,11 +17,11 @@
package net.momirealms.customcrops.api.core;
import net.momirealms.customcrops.common.util.Key;
import net.momirealms.customcrops.api.BukkitCustomCropsPlugin;
import net.momirealms.customcrops.api.core.block.CustomCropsBlock;
import net.momirealms.customcrops.api.core.item.CustomCropsItem;
import net.momirealms.customcrops.api.core.item.FertilizerType;
import net.momirealms.customcrops.common.util.Key;
public class SimpleRegistryAccess implements RegistryAccess {

View File

@@ -21,13 +21,13 @@ import com.flowpowered.nbt.CompoundMap;
import com.flowpowered.nbt.IntTag;
import com.flowpowered.nbt.StringTag;
import com.flowpowered.nbt.Tag;
import net.momirealms.customcrops.common.util.Key;
import net.momirealms.customcrops.api.core.world.CustomCropsBlockState;
import net.momirealms.customcrops.api.core.world.CustomCropsWorld;
import net.momirealms.customcrops.api.core.world.Pos3;
import net.momirealms.customcrops.api.core.wrapper.WrappedBreakEvent;
import net.momirealms.customcrops.api.core.wrapper.WrappedInteractEvent;
import net.momirealms.customcrops.api.core.wrapper.WrappedPlaceEvent;
import net.momirealms.customcrops.common.util.Key;
public abstract class AbstractCustomCropsBlock implements CustomCropsBlock {

View File

@@ -99,6 +99,7 @@ public class CropBlock extends AbstractCustomCropsBlock {
final Player player = event.playerBreaker();
Context<Player> context = Context.player(player);
context.arg(ContextKeys.LOCATION, LocationUtils.toBlockLocation(event.location()));
// check requirements
if (!RequirementManager.isSatisfied(context, cropConfig.breakRequirements())) {
@@ -156,6 +157,7 @@ public class CropBlock extends AbstractCustomCropsBlock {
public void onInteract(WrappedInteractEvent event) {
final Player player = event.player();
Context<Player> context = Context.player(player);
context.arg(ContextKeys.SLOT, event.hand());
// data first
CustomCropsWorld<?> world = event.world();
@@ -171,7 +173,8 @@ public class CropBlock extends AbstractCustomCropsBlock {
}
int point = point(state);
CropStageConfig stageConfig = cropConfig.getFloorStageEntry(point).getValue();
CropStageConfig stageConfig = cropConfig.stageByID(event.relatedID());
assert stageConfig != null;
if (!RequirementManager.isSatisfied(context, stageConfig.interactRequirements())) {
return;
}

View File

@@ -18,13 +18,13 @@
package net.momirealms.customcrops.api.core.block;
import com.flowpowered.nbt.CompoundMap;
import net.momirealms.customcrops.common.util.Key;
import net.momirealms.customcrops.api.core.world.CustomCropsBlockState;
import net.momirealms.customcrops.api.core.world.CustomCropsWorld;
import net.momirealms.customcrops.api.core.world.Pos3;
import net.momirealms.customcrops.api.core.wrapper.WrappedBreakEvent;
import net.momirealms.customcrops.api.core.wrapper.WrappedInteractEvent;
import net.momirealms.customcrops.api.core.wrapper.WrappedPlaceEvent;
import net.momirealms.customcrops.common.util.Key;
public interface CustomCropsBlock {

View File

@@ -25,7 +25,6 @@ import net.momirealms.customcrops.api.context.ContextKeys;
import net.momirealms.customcrops.api.core.*;
import net.momirealms.customcrops.api.core.item.Fertilizer;
import net.momirealms.customcrops.api.core.item.FertilizerConfig;
import net.momirealms.customcrops.api.misc.water.WateringMethod;
import net.momirealms.customcrops.api.core.world.CustomCropsBlockState;
import net.momirealms.customcrops.api.core.world.CustomCropsWorld;
import net.momirealms.customcrops.api.core.world.Pos3;
@@ -33,6 +32,7 @@ import net.momirealms.customcrops.api.core.wrapper.WrappedBreakEvent;
import net.momirealms.customcrops.api.core.wrapper.WrappedInteractEvent;
import net.momirealms.customcrops.api.core.wrapper.WrappedPlaceEvent;
import net.momirealms.customcrops.api.event.*;
import net.momirealms.customcrops.api.misc.water.WateringMethod;
import net.momirealms.customcrops.api.requirement.RequirementManager;
import net.momirealms.customcrops.api.util.EventUtils;
import net.momirealms.customcrops.api.util.LocationUtils;
@@ -222,6 +222,7 @@ public class PotBlock extends AbstractCustomCropsBlock {
final Player player = event.player();
Context<Player> context = Context.player(player);
context.arg(ContextKeys.SLOT, event.hand());
context.arg(ContextKeys.LOCATION, LocationUtils.toBlockLocation(location));
// check use requirements

View File

@@ -19,9 +19,9 @@ package net.momirealms.customcrops.api.core.block;
import net.momirealms.customcrops.api.action.Action;
import net.momirealms.customcrops.api.core.item.FertilizerType;
import net.momirealms.customcrops.api.misc.water.WateringMethod;
import net.momirealms.customcrops.api.core.world.CustomCropsBlockState;
import net.momirealms.customcrops.api.misc.water.WaterBar;
import net.momirealms.customcrops.api.misc.water.WateringMethod;
import net.momirealms.customcrops.api.requirement.Requirement;
import net.momirealms.customcrops.common.util.Pair;
import org.bukkit.entity.Player;

View File

@@ -20,9 +20,9 @@ package net.momirealms.customcrops.api.core.block;
import net.momirealms.customcrops.api.action.Action;
import net.momirealms.customcrops.api.core.ExistenceForm;
import net.momirealms.customcrops.api.core.item.FertilizerType;
import net.momirealms.customcrops.api.misc.water.WateringMethod;
import net.momirealms.customcrops.api.core.world.CustomCropsBlockState;
import net.momirealms.customcrops.api.misc.water.WaterBar;
import net.momirealms.customcrops.api.misc.water.WateringMethod;
import net.momirealms.customcrops.api.requirement.Requirement;
import net.momirealms.customcrops.common.util.Pair;
import org.bukkit.entity.Player;

View File

@@ -26,7 +26,9 @@ import net.momirealms.customcrops.api.core.world.Pos3;
import net.momirealms.customcrops.api.core.wrapper.WrappedBreakEvent;
import net.momirealms.customcrops.api.core.wrapper.WrappedInteractEvent;
import net.momirealms.customcrops.api.core.wrapper.WrappedPlaceEvent;
import net.momirealms.customcrops.api.event.*;
import net.momirealms.customcrops.api.event.ScarecrowBreakEvent;
import net.momirealms.customcrops.api.event.ScarecrowInteractEvent;
import net.momirealms.customcrops.api.event.ScarecrowPlaceEvent;
import net.momirealms.customcrops.api.util.EventUtils;
import java.util.Optional;

View File

@@ -18,11 +18,12 @@
package net.momirealms.customcrops.api.core.block;
import com.flowpowered.nbt.IntTag;
import com.flowpowered.nbt.Tag;
import net.momirealms.customcrops.api.BukkitCustomCropsPlugin;
import net.momirealms.customcrops.api.action.ActionManager;
import net.momirealms.customcrops.api.context.Context;
import net.momirealms.customcrops.api.context.ContextKeys;
import net.momirealms.customcrops.api.core.*;
import net.momirealms.customcrops.api.misc.water.WateringMethod;
import net.momirealms.customcrops.api.core.world.CustomCropsBlockState;
import net.momirealms.customcrops.api.core.world.CustomCropsWorld;
import net.momirealms.customcrops.api.core.world.Pos3;
@@ -33,8 +34,10 @@ import net.momirealms.customcrops.api.event.SprinklerBreakEvent;
import net.momirealms.customcrops.api.event.SprinklerFillEvent;
import net.momirealms.customcrops.api.event.SprinklerInteractEvent;
import net.momirealms.customcrops.api.event.SprinklerPlaceEvent;
import net.momirealms.customcrops.api.misc.water.WateringMethod;
import net.momirealms.customcrops.api.requirement.RequirementManager;
import net.momirealms.customcrops.api.util.EventUtils;
import net.momirealms.customcrops.api.util.LocationUtils;
import net.momirealms.customcrops.api.util.PlayerUtils;
import org.bukkit.GameMode;
import org.bukkit.Location;
@@ -77,6 +80,7 @@ public class SprinklerBlock extends AbstractCustomCropsBlock {
final Player player = event.playerBreaker();
Context<Player> context = Context.player(player);
context.arg(ContextKeys.LOCATION, LocationUtils.toBlockLocation(event.location()));
CustomCropsBlockState state = fixOrGetState(world, pos3, config, event.brokenID());
if (!RequirementManager.isSatisfied(context, config.breakRequirements())) {
event.setCancelled(true);
@@ -103,6 +107,7 @@ public class SprinklerBlock extends AbstractCustomCropsBlock {
final Player player = event.player();
Context<Player> context = Context.player(player);
context.arg(ContextKeys.LOCATION, LocationUtils.toBlockLocation(event.location()));
if (!RequirementManager.isSatisfied(context, config.placeRequirements())) {
event.setCancelled(true);
return;
@@ -140,8 +145,11 @@ public class SprinklerBlock extends AbstractCustomCropsBlock {
}
final Player player = event.player();
Location location = LocationUtils.toBlockLocation(event.location());
Context<Player> context = Context.player(player);
CustomCropsBlockState state = fixOrGetState(event.world(), Pos3.from(event.location()), config, event.relatedID());
context.arg(ContextKeys.SLOT, event.hand());
context.arg(ContextKeys.LOCATION, location);
CustomCropsBlockState state = fixOrGetState(event.world(), Pos3.from(location), config, event.relatedID());
if (!RequirementManager.isSatisfied(context, config.useRequirements())) {
return;
}
@@ -149,14 +157,20 @@ public class SprinklerBlock extends AbstractCustomCropsBlock {
int waterInSprinkler = water(state);
String itemID = event.itemID();
ItemStack itemInHand = event.itemInHand();
context.arg(ContextKeys.STORAGE, config.storage());
if (!config.infinite()) {
for (WateringMethod method : config.wateringMethods()) {
if (method.getUsed().equals(itemID) && method.getUsedAmount() <= itemInHand.getAmount()) {
if (method.checkRequirements(context)) {
if (waterInSprinkler >= config.storage()) {
context.arg(ContextKeys.CURRENT_WATER, waterInSprinkler);
context.arg(ContextKeys.WATER_BAR, Optional.ofNullable(config.waterBar()).map(it -> it.getWaterBar(waterInSprinkler, config.storage())).orElse(""));
ActionManager.trigger(context, config.fullWaterActions());
ActionManager.trigger(context, config.interactActions());
} else {
SprinklerFillEvent waterEvent = new SprinklerFillEvent(player, itemInHand, event.hand(), event.location(), method, state, config);
SprinklerFillEvent waterEvent = new SprinklerFillEvent(player, itemInHand, event.hand(), location, method, state, config);
if (EventUtils.fireAndCheckCancel(waterEvent))
return;
if (player.getGameMode() != GameMode.CREATIVE) {
@@ -168,8 +182,16 @@ public class SprinklerBlock extends AbstractCustomCropsBlock {
}
}
}
int currentWater = Math.min(config.storage(), waterInSprinkler + method.amountOfWater());
context.arg(ContextKeys.CURRENT_WATER, currentWater);
context.arg(ContextKeys.WATER_BAR, Optional.ofNullable(config.waterBar()).map(it -> it.getWaterBar(currentWater, config.storage())).orElse(""));
if (addWater(state, config, method.amountOfWater()) && !config.threeDItem().equals(config.threeDItemWithWater())) {
updateBlockAppearance(location, config, false);
}
method.triggerActions(context);
ActionManager.trigger(context, config.addWaterActions());
ActionManager.trigger(context, config.interactActions());
}
}
return;
@@ -177,7 +199,10 @@ public class SprinklerBlock extends AbstractCustomCropsBlock {
}
}
SprinklerInteractEvent interactEvent = new SprinklerInteractEvent(player, event.itemInHand(), event.location(), config, state, event.hand());
context.arg(ContextKeys.WATER_BAR, Optional.ofNullable(config.waterBar()).map(it -> it.getWaterBar(waterInSprinkler, config.storage())).orElse(""));
context.arg(ContextKeys.CURRENT_WATER, waterInSprinkler);
SprinklerInteractEvent interactEvent = new SprinklerInteractEvent(player, itemInHand, location, config, state, event.hand());
if (EventUtils.fireAndCheckCancel(interactEvent)) {
return;
}
@@ -220,8 +245,7 @@ public class SprinklerBlock extends AbstractCustomCropsBlock {
if (water <= 0) {
return;
}
water(state, --water);
updateState = water == 0;
updateState = water(state, config, water - 1);
} else {
updateState = false;
}
@@ -229,6 +253,7 @@ public class SprinklerBlock extends AbstractCustomCropsBlock {
Context<CustomCropsBlockState> context = Context.block(state);
World bukkitWorld = world.bukkitWorld();
Location bukkitLocation = location.toLocation(bukkitWorld);
context.arg(ContextKeys.LOCATION, bukkitLocation);
CompletableFuture<Boolean> syncCheck = new CompletableFuture<>();
@@ -300,7 +325,11 @@ public class SprinklerBlock extends AbstractCustomCropsBlock {
}
public int water(CustomCropsBlockState state) {
return state.get("water").getAsIntTag().map(IntTag::getValue).orElse(0);
Tag<?> tag = state.get("water");
if (tag == null) {
return 0;
}
return tag.getAsIntTag().map(IntTag::getValue).orElse(0);
}
public boolean water(CustomCropsBlockState state, int water) {

View File

@@ -19,9 +19,9 @@ package net.momirealms.customcrops.api.core.block;
import net.momirealms.customcrops.api.action.Action;
import net.momirealms.customcrops.api.core.ExistenceForm;
import net.momirealms.customcrops.api.misc.water.WateringMethod;
import net.momirealms.customcrops.api.core.world.CustomCropsBlockState;
import net.momirealms.customcrops.api.misc.water.WaterBar;
import net.momirealms.customcrops.api.misc.water.WateringMethod;
import net.momirealms.customcrops.api.requirement.Requirement;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;

View File

@@ -19,9 +19,9 @@ package net.momirealms.customcrops.api.core.block;
import net.momirealms.customcrops.api.action.Action;
import net.momirealms.customcrops.api.core.ExistenceForm;
import net.momirealms.customcrops.api.misc.water.WateringMethod;
import net.momirealms.customcrops.api.core.world.CustomCropsBlockState;
import net.momirealms.customcrops.api.misc.water.WaterBar;
import net.momirealms.customcrops.api.misc.water.WateringMethod;
import net.momirealms.customcrops.api.requirement.Requirement;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;

View File

@@ -17,10 +17,10 @@
package net.momirealms.customcrops.api.core.item;
import net.momirealms.customcrops.common.util.Key;
import net.momirealms.customcrops.api.core.InteractionResult;
import net.momirealms.customcrops.api.core.wrapper.WrappedInteractAirEvent;
import net.momirealms.customcrops.api.core.wrapper.WrappedInteractEvent;
import net.momirealms.customcrops.common.util.Key;
public abstract class AbstractCustomCropsItem implements CustomCropsItem {

View File

@@ -17,10 +17,10 @@
package net.momirealms.customcrops.api.core.item;
import net.momirealms.customcrops.common.util.Key;
import net.momirealms.customcrops.api.core.InteractionResult;
import net.momirealms.customcrops.api.core.wrapper.WrappedInteractAirEvent;
import net.momirealms.customcrops.api.core.wrapper.WrappedInteractEvent;
import net.momirealms.customcrops.common.util.Key;
public interface CustomCropsItem {

View File

@@ -20,6 +20,7 @@ package net.momirealms.customcrops.api.core.item;
import net.momirealms.customcrops.api.BukkitCustomCropsPlugin;
import net.momirealms.customcrops.api.action.ActionManager;
import net.momirealms.customcrops.api.context.Context;
import net.momirealms.customcrops.api.context.ContextKeys;
import net.momirealms.customcrops.api.core.BuiltInBlockMechanics;
import net.momirealms.customcrops.api.core.BuiltInItemMechanics;
import net.momirealms.customcrops.api.core.InteractionResult;
@@ -35,6 +36,7 @@ import net.momirealms.customcrops.api.core.wrapper.WrappedInteractEvent;
import net.momirealms.customcrops.api.event.FertilizerUseEvent;
import net.momirealms.customcrops.api.requirement.RequirementManager;
import net.momirealms.customcrops.api.util.EventUtils;
import net.momirealms.customcrops.api.util.LocationUtils;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.entity.Player;
@@ -56,12 +58,14 @@ public class FertilizerItem extends AbstractCustomCropsItem {
return InteractionResult.COMPLETE;
}
Location targetLocation = LocationUtils.toBlockLocation(event.location());
final Player player = event.player();
final Context<Player> context = Context.player(player);
context.arg(ContextKeys.SLOT, event.hand());
final CustomCropsWorld<?> world = event.world();
final ItemStack itemInHand = event.itemInHand();
String targetBlockID = event.relatedID();
Location targetLocation = event.location();
// if the clicked block is a crop, correct the target block
List<CropConfig> cropConfigs = Registries.STAGE_TO_CROP_UNSAFE.get(event.relatedID());
@@ -71,6 +75,8 @@ public class FertilizerItem extends AbstractCustomCropsItem {
targetBlockID = BukkitCustomCropsPlugin.getInstance().getItemManager().blockID(targetLocation);
}
context.arg(ContextKeys.LOCATION, targetLocation);
// if the clicked block is a pot
PotConfig potConfig = Registries.ITEM_TO_POT.get(targetBlockID);
if (potConfig != null) {

View File

@@ -64,7 +64,10 @@ public class SeedItem extends AbstractCustomCropsItem {
if (event.clickedBlockFace() != BlockFace.UP)
return InteractionResult.PASS;
final Player player = event.player();
Location seedLocation = LocationUtils.toBlockLocation(event.location().add(0, 1, 0));
Context<Player> context = Context.player(player);
context.arg(ContextKeys.SLOT, event.hand());
context.arg(ContextKeys.LOCATION, seedLocation);
// check pot whitelist
if (!cropConfig.potWhitelist().contains(potConfig.id())) {
ActionManager.trigger(context, cropConfig.wrongPotActions());
@@ -74,7 +77,6 @@ public class SeedItem extends AbstractCustomCropsItem {
return InteractionResult.COMPLETE;
}
// check if the block is empty
Location seedLocation = event.location().add(0, 1, 0);
if (!suitableForSeed(seedLocation)) {
return InteractionResult.COMPLETE;
}
@@ -112,7 +114,7 @@ public class SeedItem extends AbstractCustomCropsItem {
if (player.getGameMode() != GameMode.CREATIVE)
itemInHand.setAmount(itemInHand.getAmount() - 1);
// place model
BukkitCustomCropsPlugin.getInstance().getItemManager().place(seedLocation, form, stageID, cropConfig.rotation() ? FurnitureRotation.random() : FurnitureRotation.NONE);
BukkitCustomCropsPlugin.getInstance().getItemManager().place(LocationUtils.toSurfaceCenterLocation(seedLocation), form, stageID, cropConfig.rotation() ? FurnitureRotation.random() : FurnitureRotation.NONE);
cropBlock.point(state, point);
world.addBlockState(pos3, state).ifPresent(previous -> {
BukkitCustomCropsPlugin.getInstance().debug(

View File

@@ -20,6 +20,7 @@ package net.momirealms.customcrops.api.core.item;
import net.momirealms.customcrops.api.BukkitCustomCropsPlugin;
import net.momirealms.customcrops.api.action.ActionManager;
import net.momirealms.customcrops.api.context.Context;
import net.momirealms.customcrops.api.context.ContextKeys;
import net.momirealms.customcrops.api.core.*;
import net.momirealms.customcrops.api.core.block.SprinklerBlock;
import net.momirealms.customcrops.api.core.block.SprinklerConfig;
@@ -54,7 +55,7 @@ public class SprinklerItem extends AbstractCustomCropsItem {
// should be place on block
if (event.existenceForm() != ExistenceForm.BLOCK)
return InteractionResult.PASS;
SprinklerConfig config = Registries.SPRINKLER.get(event.itemID());
SprinklerConfig config = Registries.ITEM_TO_SPRINKLER.get(event.itemID());
if (config == null) {
return InteractionResult.COMPLETE;
}
@@ -68,7 +69,7 @@ public class SprinklerItem extends AbstractCustomCropsItem {
return InteractionResult.PASS;
if (!clicked.isSolid())
return InteractionResult.PASS;
targetLocation = event.location().clone().add(0,1,0);
targetLocation = LocationUtils.toBlockLocation(event.location().clone().add(0,1,0));
if (!suitableForSprinkler(targetLocation)) {
return InteractionResult.PASS;
}
@@ -77,6 +78,7 @@ public class SprinklerItem extends AbstractCustomCropsItem {
final Player player = event.player();
final ItemStack itemInHand = event.itemInHand();
Context<Player> context = Context.player(player);
context.arg(ContextKeys.LOCATION, targetLocation);
// check requirements
if (!RequirementManager.isSatisfied(context, config.placeRequirements())) {
return InteractionResult.COMPLETE;
@@ -100,11 +102,11 @@ public class SprinklerItem extends AbstractCustomCropsItem {
SprinklerPlaceEvent placeEvent = new SprinklerPlaceEvent(player, itemInHand, event.hand(), targetLocation.clone(), config, state);
if (EventUtils.fireAndCheckCancel(placeEvent))
return InteractionResult.COMPLETE;
// clear replaceable block
targetLocation.getBlock().setType(Material.AIR, false);
if (player.getGameMode() != GameMode.CREATIVE)
itemInHand.setAmount(itemInHand.getAmount() - 1);
// place the sprinkler
BukkitCustomCropsPlugin.getInstance().getItemManager().place(LocationUtils.toSurfaceCenterLocation(targetLocation), config.existenceForm(), config.threeDItem(), FurnitureRotation.NONE);
world.addBlockState(pos3, state).ifPresent(previous -> {

View File

@@ -18,9 +18,9 @@
package net.momirealms.customcrops.api.core.item;
import net.momirealms.customcrops.api.action.Action;
import net.momirealms.customcrops.api.misc.value.TextValue;
import net.momirealms.customcrops.api.misc.water.FillMethod;
import net.momirealms.customcrops.api.misc.water.WaterBar;
import net.momirealms.customcrops.api.misc.value.TextValue;
import net.momirealms.customcrops.api.requirement.Requirement;
import org.bukkit.entity.Player;

View File

@@ -18,9 +18,9 @@
package net.momirealms.customcrops.api.core.item;
import net.momirealms.customcrops.api.action.Action;
import net.momirealms.customcrops.api.misc.value.TextValue;
import net.momirealms.customcrops.api.misc.water.FillMethod;
import net.momirealms.customcrops.api.misc.water.WaterBar;
import net.momirealms.customcrops.api.misc.value.TextValue;
import net.momirealms.customcrops.api.requirement.Requirement;
import org.bukkit.entity.Player;

View File

@@ -25,7 +25,6 @@ import net.momirealms.customcrops.api.context.Context;
import net.momirealms.customcrops.api.context.ContextKeys;
import net.momirealms.customcrops.api.core.*;
import net.momirealms.customcrops.api.core.block.*;
import net.momirealms.customcrops.api.misc.water.FillMethod;
import net.momirealms.customcrops.api.core.world.CustomCropsBlockState;
import net.momirealms.customcrops.api.core.world.CustomCropsWorld;
import net.momirealms.customcrops.api.core.world.Pos3;
@@ -35,8 +34,10 @@ import net.momirealms.customcrops.api.event.WateringCanFillEvent;
import net.momirealms.customcrops.api.event.WateringCanWaterPotEvent;
import net.momirealms.customcrops.api.event.WateringCanWaterSprinklerEvent;
import net.momirealms.customcrops.api.misc.value.TextValue;
import net.momirealms.customcrops.api.misc.water.FillMethod;
import net.momirealms.customcrops.api.requirement.RequirementManager;
import net.momirealms.customcrops.api.util.EventUtils;
import net.momirealms.customcrops.api.util.LocationUtils;
import net.momirealms.customcrops.common.helper.AdventureHelper;
import net.momirealms.customcrops.common.item.Item;
import net.momirealms.customcrops.common.util.Pair;
@@ -112,6 +113,7 @@ public class WateringCanItem extends AbstractCustomCropsItem {
final Player player = event.player();;
Context<Player> context = Context.player(player);
context.arg(ContextKeys.SLOT, event.hand());
// check requirements
if (!RequirementManager.isSatisfied(context, config.requirements()))
return;
@@ -166,7 +168,10 @@ public class WateringCanItem extends AbstractCustomCropsItem {
return InteractionResult.COMPLETE;
final Player player = event.player();
Location targetLocation = LocationUtils.toBlockLocation(event.location());
final Context<Player> context = Context.player(player);
context.arg(ContextKeys.SLOT, event.hand());
context.arg(ContextKeys.LOCATION, targetLocation);
// check watering can requirements
if (!RequirementManager.isSatisfied(context, wateringCanConfig.requirements())) {
@@ -176,7 +181,7 @@ public class WateringCanItem extends AbstractCustomCropsItem {
final CustomCropsWorld<?> world = event.world();
final ItemStack itemInHand = event.itemInHand();
String targetBlockID = event.relatedID();
Location targetLocation = event.location();
BlockFace blockFace = event.clickedBlockFace();
int waterInCan = getCurrentWater(itemInHand);

View File

@@ -18,8 +18,8 @@
package net.momirealms.customcrops.api.event;
import net.momirealms.customcrops.api.core.block.PotConfig;
import net.momirealms.customcrops.api.misc.water.WateringMethod;
import net.momirealms.customcrops.api.core.world.CustomCropsBlockState;
import net.momirealms.customcrops.api.misc.water.WateringMethod;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;

View File

@@ -18,8 +18,8 @@
package net.momirealms.customcrops.api.event;
import net.momirealms.customcrops.api.core.block.SprinklerConfig;
import net.momirealms.customcrops.api.misc.water.WateringMethod;
import net.momirealms.customcrops.api.core.world.CustomCropsBlockState;
import net.momirealms.customcrops.api.misc.water.WateringMethod;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;

View File

@@ -0,0 +1,157 @@
/*
* Copyright (C) <2024> <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.customcrops.api.misc;
import net.momirealms.customcrops.api.BukkitCustomCropsPlugin;
import net.momirealms.customcrops.common.helper.VersionHelper;
import net.momirealms.customcrops.common.plugin.feature.Reloadable;
import net.momirealms.customcrops.common.plugin.scheduler.SchedulerTask;
import net.momirealms.customcrops.common.util.Pair;
import net.momirealms.sparrow.heart.SparrowHeart;
import net.momirealms.sparrow.heart.feature.entity.FakeNamedEntity;
import net.momirealms.sparrow.heart.feature.entity.armorstand.FakeArmorStand;
import net.momirealms.sparrow.heart.feature.entity.display.FakeTextDisplay;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerQuitEvent;
import java.util.ArrayList;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
public class HologramManager implements Listener, Reloadable {
private final ConcurrentHashMap<UUID, HologramCache> hologramMap = new ConcurrentHashMap<>();
private final BukkitCustomCropsPlugin plugin;
private SchedulerTask cacheCheckTask;
private static HologramManager manager;
public static HologramManager getInstance() {
return manager;
}
public HologramManager(BukkitCustomCropsPlugin plugin) {
this.plugin = plugin;
manager = this;
}
@Override
public void load() {
Bukkit.getPluginManager().registerEvents(this, plugin.getBoostrap());
this.cacheCheckTask = plugin.getScheduler().asyncRepeating(() -> {
ArrayList<UUID> removed = new ArrayList<>();
long current = System.currentTimeMillis();
for (Map.Entry<UUID, HologramCache> entry : hologramMap.entrySet()) {
Player player = Bukkit.getPlayer(entry.getKey());
if (player == null || !player.isOnline()) {
removed.add(entry.getKey());
} else {
entry.getValue().removeOutDated(current, player);
}
}
for (UUID uuid : removed) {
hologramMap.remove(uuid);
}
}, 100, 100, TimeUnit.MILLISECONDS);
}
@Override
public void unload() {
HandlerList.unregisterAll(this);
for (Map.Entry<UUID, HologramCache> entry : hologramMap.entrySet()) {
Player player = Bukkit.getPlayer(entry.getKey());
if (player != null && player.isOnline()) {
entry.getValue().removeAll(player);
}
}
if (cacheCheckTask != null) cacheCheckTask.cancel();
this.hologramMap.clear();
}
@EventHandler
public void onQuit(PlayerQuitEvent event) {
this.hologramMap.remove(event.getPlayer().getUniqueId());
}
public void showHologram(Player player, Location location, String json, int millis) {
HologramCache hologramCache = hologramMap.get(player.getUniqueId());
if (hologramCache != null) {
hologramCache.showHologram(player, location, json, millis);
} else {
hologramCache = new HologramCache();
hologramCache.showHologram(player, location, json, millis);
hologramMap.put(player.getUniqueId(), hologramCache);
}
}
public static class HologramCache {
private final ConcurrentHashMap<Location, Pair<FakeNamedEntity, Long>> cache = new ConcurrentHashMap<>();
public void removeOutDated(long current, Player player) {
ArrayList<Location> removed = new ArrayList<>();
for (Map.Entry<Location, Pair<FakeNamedEntity, Long>> entry : cache.entrySet()) {
if (entry.getValue().right() < current) {
entry.getValue().left().destroy(player);
removed.add(entry.getKey());
}
}
for (Location location : removed) {
cache.remove(location);
}
}
public void showHologram(Player player, Location location, String json, int millis) {
Pair<FakeNamedEntity, Long> pair = cache.get(location);
if (pair != null) {
pair.left().name(json);
pair.left().updateMetaData(player);
pair.right(System.currentTimeMillis() + millis);
} else {
long removeTime = System.currentTimeMillis() + millis;
if (VersionHelper.isVersionNewerThan1_19_4()) {
FakeTextDisplay fakeEntity = SparrowHeart.getInstance().createFakeTextDisplay(location.clone().add(0,1.25,0));
fakeEntity.name(json);
fakeEntity.rgba(0, 0, 0, 0);
fakeEntity.spawn(player);
this.cache.put(location, Pair.of(fakeEntity, removeTime));
} else {
FakeArmorStand fakeEntity = SparrowHeart.getInstance().createFakeArmorStand(location);
fakeEntity.name(json);
fakeEntity.small(true);
fakeEntity.invisible(true);
fakeEntity.spawn(player);
this.cache.put(location, Pair.of(fakeEntity, removeTime));
}
}
}
public void removeAll(Player player) {
for (Map.Entry<Location, Pair<FakeNamedEntity, Long>> entry : this.cache.entrySet()) {
entry.getValue().left().destroy(player);
}
cache.clear();
}
}
}