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

Improved location context

This commit is contained in:
XiaoMoMi
2024-09-05 22:52:20 +08:00
parent 62bc8f6b21
commit 7fc14dfa9b
25 changed files with 415 additions and 90 deletions

View File

@@ -27,7 +27,10 @@ import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public abstract class AbstractActionManager<T> implements ActionManager<T> {
@@ -54,6 +57,7 @@ public abstract class AbstractActionManager<T> implements ActionManager<T> {
this.registerHologramAction();
this.registerPlantAction();
this.registerBreakAction();
this.registerSpawnEntity();
}
@Override
@@ -303,4 +307,15 @@ public abstract class AbstractActionManager<T> implements ActionManager<T> {
protected void registerBreakAction() {
this.registerAction((args, chance) -> new ActionBreak<>(plugin, args, chance), "break");
}
protected void registerSpawnEntity() {
this.registerAction((args, chance) -> {
if (args instanceof Section section) {
return new ActionSpawnEntity<>(plugin, section, chance);
} else {
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at spawn-entity action which is expected to be `Section`");
return Action.empty();
}
}, "spawn-entity", "spawn-mob");
}
}

View File

@@ -12,23 +12,6 @@ import net.momirealms.customcrops.api.misc.value.TextValue;
import net.momirealms.customcrops.api.util.LocationUtils;
import net.momirealms.customcrops.common.helper.AdventureHelper;
import org.bukkit.Location;
/*
* 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/>.
*/
import org.bukkit.entity.Player;
import java.util.ArrayList;

View File

@@ -0,0 +1,76 @@
/*
* 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.action.builtin;
import dev.dejvokep.boostedyaml.block.implementation.Section;
import net.momirealms.customcrops.api.BukkitCustomCropsPlugin;
import net.momirealms.customcrops.api.context.Context;
import net.momirealms.customcrops.api.context.ContextKeys;
import net.momirealms.customcrops.api.integration.EntityProvider;
import org.bukkit.Location;
import java.util.HashMap;
import java.util.Map;
import static java.util.Objects.requireNonNull;
public class ActionSpawnEntity<T> extends AbstractBuiltInAction<T> {
private final String id;
private final Map<String, Object> properties;
public ActionSpawnEntity(
BukkitCustomCropsPlugin plugin,
Section section,
double chance
) {
super(plugin, chance);
this.id = section.getString("id");
Section proeprtySection = section.getSection("properties");
this.properties = proeprtySection == null ? new HashMap<>() : proeprtySection.getStringRouteMappedValues(false);
}
@Override
protected void triggerAction(Context<T> context) {
Location location = requireNonNull(context.arg(ContextKeys.LOCATION));
String finalID;
EntityProvider provider;
if (id.contains(":")) {
String[] split = id.split(":", 2);
String providerID = split[0];
finalID = split[1];
provider = BukkitCustomCropsPlugin.getInstance().getIntegrationManager().getEntityProvider(providerID);
} else {
finalID = id;
provider = BukkitCustomCropsPlugin.getInstance().getIntegrationManager().getEntityProvider("vanilla");
}
if (provider == null) {
plugin.getPluginLogger().warn("Failed to spawn entity: " + id);
return;
}
provider.spawn(location, finalID, properties());
}
public String id() {
return id;
}
public Map<String, Object> properties() {
return properties;
}
}

View File

@@ -18,12 +18,14 @@
package net.momirealms.customcrops.api.context;
import net.momirealms.customcrops.api.core.world.CustomCropsBlockState;
import org.bukkit.Location;
import org.jetbrains.annotations.NotNull;
public class BlockContextImpl extends AbstractContext<CustomCropsBlockState> {
public BlockContextImpl(@NotNull CustomCropsBlockState block, boolean sync) {
public BlockContextImpl(@NotNull CustomCropsBlockState block, Location location, boolean sync) {
super(block, sync);
updateLocation(location);
}
@Override

View File

@@ -18,6 +18,7 @@
package net.momirealms.customcrops.api.context;
import net.momirealms.customcrops.api.core.world.CustomCropsBlockState;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -122,10 +123,11 @@ public interface Context<T> {
* Creates a block-specific context.
*
* @param block the block to be used as the holder of the context.
* @param location the location of the block
* @return a new Context instance with the specified block as the holder.
*/
static Context<CustomCropsBlockState> block(@NotNull CustomCropsBlockState block) {
return new BlockContextImpl(block, false);
static Context<CustomCropsBlockState> block(@NotNull CustomCropsBlockState block, @NotNull Location location) {
return new BlockContextImpl(block, location, false);
}
/**
@@ -143,10 +145,24 @@ public interface Context<T> {
* Creates a block-specific context.
*
* @param block the block to be used as the holder of the context.
* @param location the location of the block
* @param threadSafe is the created map thread safe
* @return a new Context instance with the specified block as the holder.
*/
static Context<CustomCropsBlockState> block(@NotNull CustomCropsBlockState block, boolean threadSafe) {
return new BlockContextImpl(block, threadSafe);
static Context<CustomCropsBlockState> block(@NotNull CustomCropsBlockState block, @NotNull Location location, boolean threadSafe) {
return new BlockContextImpl(block, location, threadSafe);
}
/**
* Updates location for the context
*
* @param location location
*/
default void updateLocation(Location location) {
arg(ContextKeys.LOCATION, location)
.arg(ContextKeys.X, location.getBlockX())
.arg(ContextKeys.Y, location.getBlockY())
.arg(ContextKeys.Z, location.getBlockZ())
.arg(ContextKeys.WORLD, location.getWorld().getName());
}
}

View File

@@ -18,7 +18,6 @@
package net.momirealms.customcrops.api.context;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.inventory.EquipmentSlot;
import java.util.Objects;
@@ -45,7 +44,6 @@ public class ContextKeys<T> {
public static final ContextKeys<String> ICON = of("icon", String.class);
public static final ContextKeys<Integer> MAX_TIMES = of("max_times", Integer.class);
public static final ContextKeys<Integer> LEFT_TIMES = of("left_times", Integer.class);
public static final ContextKeys<Player> PLAYER_INSTANCE = of("player_instance", Player.class);
private final String key;
private final Class<T> type;

View File

@@ -27,12 +27,8 @@ public final class PlayerContextImpl extends AbstractContext<Player> {
super(player, sync);
if (player == null) return;
final Location location = player.getLocation();
arg(ContextKeys.PLAYER, player.getName())
.arg(ContextKeys.LOCATION, location)
.arg(ContextKeys.X, location.getBlockX())
.arg(ContextKeys.Y, location.getBlockY())
.arg(ContextKeys.Z, location.getBlockZ())
.arg(ContextKeys.WORLD, location.getWorld().getName());
arg(ContextKeys.PLAYER, player.getName());
updateLocation(location);
}
@Override

View File

@@ -20,7 +20,6 @@ package net.momirealms.customcrops.api.core;
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.block.CropBlock;
import net.momirealms.customcrops.api.core.mechanic.crop.BoneMeal;
import net.momirealms.customcrops.api.core.mechanic.crop.CropConfig;
@@ -32,7 +31,6 @@ import net.momirealms.customcrops.api.core.world.CustomCropsWorld;
import net.momirealms.customcrops.api.core.world.Pos3;
import net.momirealms.customcrops.api.event.BoneMealDispenseEvent;
import net.momirealms.customcrops.api.util.EventUtils;
import net.momirealms.customcrops.api.util.LocationUtils;
import net.momirealms.customcrops.common.helper.VersionHelper;
import org.bukkit.Location;
import org.bukkit.Material;
@@ -383,13 +381,12 @@ public abstract class AbstractCustomEventListener implements Listener {
String id = itemManager.id(storage);
if (id.equals(itemID)) {
storage.setAmount(storage.getAmount() - 1);
Context<Player> context = Context.player(null);
context.arg(ContextKeys.LOCATION, location);
boneMeal.triggerActions(context);
Context<Player> playerContext = Context.player(null);
playerContext.updateLocation(location);
boneMeal.triggerActions(playerContext);
int afterPoints = Math.min(point + boneMeal.rollPoint(), cropConfig.maxPoints());
cropBlock.point(state, afterPoints);
Context<CustomCropsBlockState> blockContext = Context.block(state);
blockContext.arg(ContextKeys.LOCATION, LocationUtils.toBlockLocation(location));
Context<CustomCropsBlockState> blockContext = Context.block(state, location);
for (int i = point + 1; i <= afterPoints; i++) {
CropStageConfig stage = cropConfig.stageByPoint(i);
if (stage != null) {
@@ -399,12 +396,11 @@ public abstract class AbstractCustomEventListener implements Listener {
CropStageConfig currentStage = cropConfig.stageWithModelByPoint(point);
CropStageConfig afterStage = cropConfig.stageWithModelByPoint(afterPoints);
if (currentStage == afterStage) return;
Location bukkitLocation = location.toLocation(world.bukkitWorld());
FurnitureRotation rotation = BukkitCustomCropsPlugin.getInstance().getItemManager().remove(bukkitLocation, ExistenceForm.ANY);
FurnitureRotation rotation = BukkitCustomCropsPlugin.getInstance().getItemManager().remove(location, ExistenceForm.ANY);
if (rotation == FurnitureRotation.NONE && cropConfig.rotation()) {
rotation = FurnitureRotation.random();
}
BukkitCustomCropsPlugin.getInstance().getItemManager().place(bukkitLocation, afterStage.existenceForm(), Objects.requireNonNull(afterStage.stageID()), rotation);
BukkitCustomCropsPlugin.getInstance().getItemManager().place(location, afterStage.existenceForm(), Objects.requireNonNull(afterStage.stageID()), rotation);
}
}
}

View File

@@ -76,7 +76,8 @@ public class CropBlock extends AbstractCustomCropsBlock {
public void onBreak(WrappedBreakEvent event) {
List<CropConfig> configs = Registries.STAGE_TO_CROP_UNSAFE.get(event.brokenID());
CustomCropsWorld<?> world = event.world();
Pos3 pos3 = Pos3.from(event.location());
Location location = LocationUtils.toBlockLocation(event.location());
Pos3 pos3 = Pos3.from(location);
if (configs == null || configs.isEmpty()) {
world.removeBlockState(pos3);
return;
@@ -102,7 +103,8 @@ public class CropBlock extends AbstractCustomCropsBlock {
final Player player = event.playerBreaker();
Context<Player> context = Context.player(player);
context.arg(ContextKeys.LOCATION, LocationUtils.toBlockLocation(event.location()));
context.updateLocation(location);
// check requirements
if (!RequirementManager.isSatisfied(context, cropConfig.breakRequirements())) {
@@ -169,7 +171,7 @@ public class CropBlock extends AbstractCustomCropsBlock {
// data first
CustomCropsWorld<?> world = event.world();
Location location = event.location();
Location location = LocationUtils.toBlockLocation(event.location());
Pos3 pos3 = Pos3.from(location);
// fix if possible
CustomCropsBlockState state = fixOrGetState(world, pos3, event.relatedID());
@@ -198,7 +200,7 @@ public class CropBlock extends AbstractCustomCropsBlock {
String blockBelowID = BukkitCustomCropsPlugin.getInstance().getItemManager().blockID(potLocation.getBlock());
PotConfig potConfig = Registries.ITEM_TO_POT.get(blockBelowID);
if (potConfig != null) {
context.arg(ContextKeys.LOCATION, LocationUtils.toBlockLocation(potLocation));
context.updateLocation(potLocation);
PotBlock potBlock = (PotBlock) BuiltInBlockMechanics.POT.mechanic();
assert potBlock != null;
// fix or get data
@@ -207,7 +209,7 @@ public class CropBlock extends AbstractCustomCropsBlock {
return;
}
context.arg(ContextKeys.LOCATION, LocationUtils.toBlockLocation(location));
context.updateLocation(location);
if (point < cropConfig.maxPoints()) {
for (BoneMeal boneMeal : cropConfig.boneMeals()) {
if (boneMeal.requiredItem().equals(event.itemID()) && boneMeal.amountOfRequiredItem() <= itemInHand.getAmount()) {
@@ -230,8 +232,7 @@ public class CropBlock extends AbstractCustomCropsBlock {
CropStageConfig nextStage = cropConfig.stageWithModelByPoint(afterPoints);
Context<CustomCropsBlockState> blockContext = Context.block(state);
blockContext.arg(ContextKeys.LOCATION, LocationUtils.toBlockLocation(location));
Context<CustomCropsBlockState> blockContext = Context.block(state, location);
for (int i = point + 1; i <= afterPoints; i++) {
CropStageConfig stage = cropConfig.stageByPoint(i);
if (stage != null) {
@@ -240,12 +241,11 @@ public class CropBlock extends AbstractCustomCropsBlock {
}
if (Objects.equals(nextStage.stageID(), event.relatedID())) return;
Location bukkitLocation = location.toLocation(world.bukkitWorld());
FurnitureRotation rotation = BukkitCustomCropsPlugin.getInstance().getItemManager().remove(bukkitLocation, ExistenceForm.ANY);
FurnitureRotation rotation = BukkitCustomCropsPlugin.getInstance().getItemManager().remove(location, ExistenceForm.ANY);
if (rotation == FurnitureRotation.NONE && cropConfig.rotation()) {
rotation = FurnitureRotation.random();
}
BukkitCustomCropsPlugin.getInstance().getItemManager().place(bukkitLocation, nextStage.existenceForm(), Objects.requireNonNull(nextStage.stageID()), rotation);
BukkitCustomCropsPlugin.getInstance().getItemManager().place(location, nextStage.existenceForm(), Objects.requireNonNull(nextStage.stageID()), rotation);
return;
}
}
@@ -307,9 +307,8 @@ public class CropBlock extends AbstractCustomCropsBlock {
}
}
Context<CustomCropsBlockState> context = Context.block(state).arg(ContextKeys.OFFLINE, offline);
Location bukkitLocation = location.toLocation(bukkitWorld);
context.arg(ContextKeys.LOCATION, bukkitLocation);
Context<CustomCropsBlockState> context = Context.block(state, bukkitLocation).arg(ContextKeys.OFFLINE, offline);
for (DeathCondition deathCondition : config.deathConditions()) {
if (deathCondition.isMet(context)) {
BukkitCustomCropsPlugin.getInstance().getScheduler().sync().runLater(() -> {

View File

@@ -48,14 +48,14 @@ public class DeadCrop extends AbstractCustomCropsBlock {
Context<Player> context = Context.player(player);
// data first
CustomCropsWorld<?> world = event.world();
Location location = event.location();
Location location = LocationUtils.toBlockLocation(event.location());
context.arg(ContextKeys.SLOT, event.hand());
// check pot below
Location potLocation = location.clone().subtract(0,1,0);
String blockBelowID = BukkitCustomCropsPlugin.getInstance().getItemManager().blockID(potLocation.getBlock());
PotConfig potConfig = Registries.ITEM_TO_POT.get(blockBelowID);
if (potConfig != null) {
context.arg(ContextKeys.LOCATION, LocationUtils.toBlockLocation(potLocation));
context.updateLocation(potLocation);
PotBlock potBlock = (PotBlock) BuiltInBlockMechanics.POT.mechanic();
assert potBlock != null;
// fix or get data

View File

@@ -84,7 +84,7 @@ public class PotBlock extends AbstractCustomCropsBlock {
@Override
public void onBreak(WrappedBreakEvent event) {
CustomCropsWorld<?> world = event.world();
Location location = event.location();
Location location = LocationUtils.toBlockLocation(event.location());
Pos3 pos3 = Pos3.from(location);
PotConfig config = Registries.ITEM_TO_POT.get(event.brokenID());
if (config == null) {
@@ -95,7 +95,7 @@ public class PotBlock extends AbstractCustomCropsBlock {
final Player player = event.playerBreaker();
Context<Player> context = Context.player(player);
context.arg(ContextKeys.LOCATION, location);
context.updateLocation(location);
if (!RequirementManager.isSatisfied(context, config.breakRequirements())) {
event.setCancelled(true);
return;
@@ -130,7 +130,7 @@ public class PotBlock extends AbstractCustomCropsBlock {
cropConfig = cropConfigs.get(0);
}
context.arg(ContextKeys.LOCATION, upperLocation);
context.updateLocation(upperLocation);
if (!RequirementManager.isSatisfied(context, cropConfig.breakRequirements())) {
event.setCancelled(true);
return;
@@ -171,7 +171,7 @@ public class PotBlock extends AbstractCustomCropsBlock {
BukkitCustomCropsPlugin.getInstance().getItemManager().remove(upperLocation, ExistenceForm.ANY);
}
context.arg(ContextKeys.LOCATION, location);
context.updateLocation(location);
ActionManager.trigger(context, config.breakActions());
world.removeBlockState(pos3);
@@ -231,7 +231,7 @@ public class PotBlock extends AbstractCustomCropsBlock {
return;
}
Location location = event.location();
Location location = LocationUtils.toBlockLocation(event.location());
Pos3 pos3 = Pos3.from(location);
CustomCropsWorld<?> world = event.world();
@@ -241,7 +241,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));
context.updateLocation(location);
// check use requirements
if (!RequirementManager.isSatisfied(context, potConfig.useRequirements())) {
@@ -407,17 +407,17 @@ public class PotBlock extends AbstractCustomCropsBlock {
boolean fertilizerChanged = tickFertilizer(state);
Location bukkitLocation = location.toLocation(bukkitWorld);
if (fertilizerChanged || waterChanged) {
boolean finalHasNaturalWater = hasNaturalWater;
Location bukkitLocation = location.toLocation(bukkitWorld);
BukkitCustomCropsPlugin.getInstance().getScheduler().sync().run(() -> {
updateBlockAppearance(bukkitLocation, config, finalHasNaturalWater, fertilizers(state));
}, bukkitLocation);
}
ActionManager.trigger(Context.block(state)
.arg(ContextKeys.OFFLINE, offline)
.arg(ContextKeys.LOCATION, location.toLocation(bukkitWorld)),
ActionManager.trigger(Context.block(state, bukkitLocation)
.arg(ContextKeys.OFFLINE, offline),
config.tickActions()
);
}

View File

@@ -74,7 +74,8 @@ public class SprinklerBlock extends AbstractCustomCropsBlock {
@Override
public void onBreak(WrappedBreakEvent event) {
CustomCropsWorld<?> world = event.world();
Pos3 pos3 = Pos3.from(event.location());
Location location = LocationUtils.toBlockLocation(event.location());
Pos3 pos3 = Pos3.from(location);
SprinklerConfig config = Registries.ITEM_TO_SPRINKLER.get(event.brokenID());
if (config == null) {
world.removeBlockState(pos3);
@@ -83,14 +84,14 @@ public class SprinklerBlock extends AbstractCustomCropsBlock {
final Player player = event.playerBreaker();
Context<Player> context = Context.player(player);
context.arg(ContextKeys.LOCATION, LocationUtils.toBlockLocation(event.location()));
context.updateLocation(location);
CustomCropsBlockState state = fixOrGetState(world, pos3, config, event.brokenID());
if (!RequirementManager.isSatisfied(context, config.breakRequirements())) {
event.setCancelled(true);
return;
}
SprinklerBreakEvent breakEvent = new SprinklerBreakEvent(event.entityBreaker(), event.blockBreaker(), event.location(), state, config, event.reason());
SprinklerBreakEvent breakEvent = new SprinklerBreakEvent(event.entityBreaker(), event.blockBreaker(), location, state, config, event.reason());
if (EventUtils.fireAndCheckCancel(breakEvent)) {
event.setCancelled(true);
return;
@@ -110,7 +111,8 @@ public class SprinklerBlock extends AbstractCustomCropsBlock {
final Player player = event.player();
Context<Player> context = Context.player(player);
context.arg(ContextKeys.LOCATION, LocationUtils.toBlockLocation(event.location()));
Location location = LocationUtils.toBlockLocation(event.location());
context.updateLocation(location);
if (!RequirementManager.isSatisfied(context, config.placeRequirements())) {
event.setCancelled(true);
return;
@@ -156,7 +158,7 @@ public class SprinklerBlock extends AbstractCustomCropsBlock {
Location location = LocationUtils.toBlockLocation(event.location());
Context<Player> context = Context.player(player);
context.arg(ContextKeys.SLOT, event.hand());
context.arg(ContextKeys.LOCATION, location);
context.updateLocation(location);
CustomCropsBlockState state = fixOrGetState(event.world(), Pos3.from(location), config, event.relatedID());
if (!RequirementManager.isSatisfied(context, config.useRequirements())) {
return;
@@ -257,10 +259,9 @@ public class SprinklerBlock extends AbstractCustomCropsBlock {
updateState = false;
}
Context<CustomCropsBlockState> context = Context.block(state).arg(ContextKeys.OFFLINE, offline);
World bukkitWorld = world.bukkitWorld();
Location bukkitLocation = location.toLocation(bukkitWorld);
context.arg(ContextKeys.LOCATION, bukkitLocation);
Context<CustomCropsBlockState> context = Context.block(state, bukkitLocation).arg(ContextKeys.OFFLINE, offline);
CompletableFuture<Boolean> syncCheck = new CompletableFuture<>();

View File

@@ -77,7 +77,7 @@ public class FertilizerItem extends AbstractCustomCropsItem {
targetBlockID = BukkitCustomCropsPlugin.getInstance().getItemManager().blockID(targetLocation);
}
context.arg(ContextKeys.LOCATION, targetLocation);
context.updateLocation(targetLocation);
// if the clicked block is a pot
PotConfig potConfig = Registries.ITEM_TO_POT.get(targetBlockID);

View File

@@ -67,7 +67,7 @@ public class SeedItem extends AbstractCustomCropsItem {
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);
context.updateLocation(seedLocation);
// check pot whitelist
if (!cropConfig.potWhitelist().contains(potConfig.id())) {
ActionManager.trigger(context, cropConfig.wrongPotActions());

View File

@@ -20,7 +20,6 @@ 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.mechanic.sprinkler.SprinklerConfig;
@@ -78,7 +77,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);
context.updateLocation(targetLocation);
// check requirements
if (!RequirementManager.isSatisfied(context, config.placeRequirements())) {
return InteractionResult.COMPLETE;

View File

@@ -133,7 +133,7 @@ public class WateringCanItem extends AbstractCustomCropsItem {
return;
final Vector vector = result.getHitPosition();
// for old config compatibility
context.arg(ContextKeys.LOCATION, new Location(player.getWorld(), vector.getX() - 0.5,vector.getY() - 1, vector.getZ() - 0.5));
context.updateLocation(new Location(player.getWorld(), vector.getX() - 0.5,vector.getY() - 1, vector.getZ() - 0.5));
final ItemStack itemInHand = event.itemInHand();
int water = getCurrentWater(itemInHand);
@@ -202,7 +202,7 @@ public class WateringCanItem extends AbstractCustomCropsItem {
Location targetLocation = LocationUtils.toBlockLocation(event.location());
final Context<Player> context = Context.player(player);
context.arg(ContextKeys.SLOT, event.hand());
context.arg(ContextKeys.LOCATION, targetLocation);
context.updateLocation(targetLocation);
// check watering can requirements
if (!RequirementManager.isSatisfied(context, wateringCanConfig.requirements())) {
@@ -315,7 +315,7 @@ public class WateringCanItem extends AbstractCustomCropsItem {
if (potBlock.addWater(potState, potConfig, wateringCanConfig.wateringAmount())) {
potBlock.updateBlockAppearance(temp, potConfig, true, potBlock.fertilizers(potState));
}
context.arg(ContextKeys.LOCATION, temp);
context.updateLocation(temp);
ActionManager.trigger(context, potConfig.addWaterActions());
}
@@ -332,7 +332,7 @@ public class WateringCanItem extends AbstractCustomCropsItem {
return InteractionResult.COMPLETE;
final Vector vector = result.getHitPosition();
// for old config compatibility
context.arg(ContextKeys.LOCATION, new Location(player.getWorld(), vector.getX() - 0.5,vector.getY() - 1, vector.getZ() - 0.5));
context.updateLocation(new Location(player.getWorld(), vector.getX() - 0.5,vector.getY() - 1, vector.getZ() - 0.5));
String blockID = BukkitCustomCropsPlugin.getInstance().getItemManager().blockID(targetBlock);
BukkitCustomCropsPlugin.getInstance().debug(blockID);

View File

@@ -0,0 +1,49 @@
/*
* 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.integration;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.Map;
/**
* The EntityProvider interface defines methods to interact with external entity
* spawning systems, allowing the spawning of entities at specified locations with
* given properties. Implementations of this interface should provide the logic
* for spawning entities and managing their properties.
*/
public interface EntityProvider extends ExternalProvider {
/**
* Spawns an entity at the specified location with the given properties.
*
* @param location The location where the entity will be spawned.
* @param id The identifier of the entity to be spawned.
* @param propertyMap A map containing additional properties for the entity.
* @return The spawned entity.
*/
@NotNull
Entity spawn(@NotNull Location location, @NotNull String id, @NotNull Map<String, Object> propertyMap);
default Entity spawn(@NotNull Location location, @NotNull String id) {
return spawn(location, id, new HashMap<>());
}
}

View File

@@ -75,4 +75,29 @@ public interface IntegrationManager extends Reloadable {
* @return true if unregistration is successful, false otherwise.
*/
boolean unregisterItemProvider(@NotNull String id);
/**
* Registers an EntityProvider.
*
* @param entityProvider the EntityProvider to register
* @return true if registration is successful, false otherwise.
*/
boolean registerEntityProvider(@NotNull EntityProvider entityProvider);
/**
* Unregisters an EntityProvider by its ID.
*
* @param id the ID of the EntityProvider to unregister
* @return true if unregistration is successful, false otherwise.
*/
boolean unregisterEntityProvider(@NotNull String id);
/**
* Retrieves a registered EntityProvider by its ID.
*
* @param id the ID of the EntityProvider to retrieve
* @return the EntityProvider if found, or null if not found
*/
@Nullable
EntityProvider getEntityProvider(String id);
}

View File

@@ -875,7 +875,7 @@ public abstract class AbstractRequirementManager<T> implements RequirementManage
if (advanced) ActionManager.trigger(context, actions);
return false;
};
}, "natural-light");
}, "natural-light", "skylight");
registerRequirement((args, actions, advanced) -> {
int value = (int) args;
return context -> {
@@ -885,7 +885,7 @@ public abstract class AbstractRequirementManager<T> implements RequirementManage
if (advanced) ActionManager.trigger(context, actions);
return false;
};
}, "skylight_more_than", "skylight-more-than");
}, "skylight_more_than", "skylight-more-than", "natural_light_more_than", "natural-light-more-than");
registerRequirement((args, actions, advanced) -> {
int value = (int) args;
return context -> {
@@ -895,7 +895,7 @@ public abstract class AbstractRequirementManager<T> implements RequirementManage
if (advanced) ActionManager.trigger(context, actions);
return false;
};
}, "skylight_less_than", "skylight-less-than");
}, "skylight_less_than", "skylight-less-than", "natural_light_less_than", "natural-light-less-than");
registerRequirement((args, actions, advanced) -> {
int value = (int) args;
return context -> {

View File

@@ -50,6 +50,7 @@ dependencies {
compileOnly("pers.neige.neigeitems:NeigeItems:1.17.13")
compileOnly("io.lumine:Mythic-Dist:5.6.2")
compileOnly("com.github.Xiao-MoMi:Custom-Fishing:2.2.19")
compileOnly("com.github.LoneDev6:api-itemsadder:3.6.3-beta-14")
// eco
compileOnly("com.willfp:eco:6.70.1")
compileOnly("com.willfp:EcoJobs:3.56.1")

View File

@@ -0,0 +1,47 @@
/*
* 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.bukkit.integration.entity;
import dev.lone.itemsadder.api.CustomEntity;
import net.momirealms.customcrops.api.integration.EntityProvider;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.jetbrains.annotations.NotNull;
import java.util.Map;
public class ItemsAdderEntityProvider implements EntityProvider {
@Override
public String identifier() {
return "ItemsAdder";
}
@NotNull
@Override
public Entity spawn(@NotNull Location location, @NotNull String id, @NotNull Map<String, Object> propertyMap) {
CustomEntity customEntity = CustomEntity.spawn(
id,
location,
(Boolean) propertyMap.getOrDefault("frustumCulling", true),
(Boolean) propertyMap.getOrDefault("noBase", false),
(Boolean) propertyMap.getOrDefault("noHitbox", false)
);
return customEntity.getEntity();
}
}

View File

@@ -0,0 +1,58 @@
/*
* 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.bukkit.integration.entity;
import io.lumine.mythic.api.adapters.AbstractLocation;
import io.lumine.mythic.api.mobs.MythicMob;
import io.lumine.mythic.bukkit.MythicBukkit;
import io.lumine.mythic.bukkit.utils.serialize.Position;
import io.lumine.mythic.core.mobs.ActiveMob;
import net.momirealms.customcrops.api.integration.EntityProvider;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.jetbrains.annotations.NotNull;
import java.util.Map;
import java.util.Optional;
public class MythicEntityProvider implements EntityProvider {
private MythicBukkit mythicBukkit;
@Override
public String identifier() {
return "MythicMobs";
}
@NotNull
@Override
public Entity spawn(@NotNull Location location, @NotNull String id, @NotNull Map<String, Object> propertyMap) {
if (this.mythicBukkit == null || mythicBukkit.isClosed()) {
this.mythicBukkit = MythicBukkit.inst();
}
Optional<MythicMob> mythicMob = mythicBukkit.getMobManager().getMythicMob(id);
if (mythicMob.isPresent()) {
MythicMob theMob = mythicMob.get();
Position position = Position.of(location);
AbstractLocation abstractLocation = new AbstractLocation(position);
ActiveMob activeMob = theMob.spawn(abstractLocation, (double) propertyMap.getOrDefault("level", 0d));
return activeMob.getEntity().getBukkitEntity();
}
throw new NullPointerException("MythicMobs: " + id + " doesn't exist.");
}
}

View File

@@ -0,0 +1,41 @@
/*
* 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.bukkit.integration.entity;
import net.momirealms.customcrops.api.integration.EntityProvider;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.jetbrains.annotations.NotNull;
import java.util.Locale;
import java.util.Map;
public class VanillaEntityProvider implements EntityProvider {
@Override
public String identifier() {
return "vanilla";
}
@NotNull
@Override
public Entity spawn(@NotNull Location location, @NotNull String id, @NotNull Map<String, Object> propertyMap) {
return location.getWorld().spawnEntity(location, EntityType.valueOf(id.toUpperCase(Locale.ENGLISH)));
}
}

View File

@@ -18,10 +18,10 @@
package net.momirealms.customcrops.bukkit.integration;
import net.momirealms.customcrops.api.BukkitCustomCropsPlugin;
import net.momirealms.customcrops.api.integration.IntegrationManager;
import net.momirealms.customcrops.api.integration.ItemProvider;
import net.momirealms.customcrops.api.integration.LevelerProvider;
import net.momirealms.customcrops.api.integration.SeasonProvider;
import net.momirealms.customcrops.api.integration.*;
import net.momirealms.customcrops.bukkit.integration.entity.ItemsAdderEntityProvider;
import net.momirealms.customcrops.bukkit.integration.entity.MythicEntityProvider;
import net.momirealms.customcrops.bukkit.integration.entity.VanillaEntityProvider;
import net.momirealms.customcrops.bukkit.integration.item.*;
import net.momirealms.customcrops.bukkit.integration.level.*;
import net.momirealms.customcrops.bukkit.integration.papi.CustomCropsPapi;
@@ -43,6 +43,7 @@ public class BukkitIntegrationManager implements IntegrationManager {
private final BukkitCustomCropsPlugin plugin;
private final HashMap<String, LevelerProvider> levelerProviders = new HashMap<>();
private final HashMap<String, EntityProvider> entityProviders = new HashMap<>();
public BukkitIntegrationManager(BukkitCustomCropsPlugin plugin) {
this.plugin = plugin;
@@ -60,6 +61,7 @@ public class BukkitIntegrationManager implements IntegrationManager {
@Override
public void load() {
registerEntityProvider(new VanillaEntityProvider());
if (isHooked("MMOItems")) {
registerItemProvider(new MMOItemsItemProvider());
}
@@ -69,11 +71,15 @@ public class BukkitIntegrationManager implements IntegrationManager {
if (isHooked("NeigeItems")) {
registerItemProvider(new NeigeItemsItemProvider());
}
if (isHooked("ItemsAdder")) {
registerEntityProvider(new ItemsAdderEntityProvider());
}
if (isHooked("CustomFishing", "2.2", "2.3", "2.4")) {
registerItemProvider(new CustomFishingItemProvider());
}
if (isHooked("MythicMobs", "5")) {
registerItemProvider(new MythicMobsItemProvider());
registerEntityProvider(new MythicEntityProvider());
}
if (isHooked("EcoJobs")) {
registerLevelerProvider(new EcoJobsLevelerProvider());
@@ -157,8 +163,8 @@ public class BukkitIntegrationManager implements IntegrationManager {
@Override
@Nullable
public LevelerProvider getLevelerProvider(String plugin) {
return levelerProviders.get(plugin);
public LevelerProvider getLevelerProvider(String id) {
return levelerProviders.get(id);
}
@Override
@@ -175,4 +181,22 @@ public class BukkitIntegrationManager implements IntegrationManager {
public boolean unregisterItemProvider(@NotNull String id) {
return ((BukkitItemManager) plugin.getItemManager()).unregisterItemProvider(id);
}
@Override
public boolean registerEntityProvider(@NotNull EntityProvider entity) {
if (entityProviders.containsKey(entity.identifier())) return false;
entityProviders.put(entity.identifier(), entity);
return true;
}
@Override
public boolean unregisterEntityProvider(@NotNull String id) {
return entityProviders.remove(id) != null;
}
@Nullable
@Override
public EntityProvider getEntityProvider(String id) {
return entityProviders.get(id);
}
}

View File

@@ -30,7 +30,6 @@ import net.momirealms.customcrops.api.core.world.adaptor.AbstractWorldAdaptor;
import net.momirealms.customcrops.api.util.StringUtils;
import net.momirealms.customcrops.common.helper.GsonHelper;
import net.momirealms.customcrops.common.helper.VersionHelper;
import net.momirealms.customcrops.common.util.FileUtils;
import net.momirealms.customcrops.common.util.Key;
import org.bukkit.Bukkit;
import org.bukkit.NamespacedKey;