mirror of
https://github.com/Xiao-MoMi/Custom-Crops.git
synced 2025-12-19 15:09:25 +00:00
3.6.14
This commit is contained in:
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import net.momirealms.customcrops.api.core.BuiltInBlockMechanics;
|
||||
import net.momirealms.customcrops.api.core.ExistenceForm;
|
||||
import net.momirealms.customcrops.api.core.FurnitureRotation;
|
||||
import net.momirealms.customcrops.api.core.Registries;
|
||||
import net.momirealms.customcrops.api.core.block.BreakReason;
|
||||
import net.momirealms.customcrops.api.core.block.CropBlock;
|
||||
import net.momirealms.customcrops.api.core.mechanic.crop.CropConfig;
|
||||
import net.momirealms.customcrops.api.core.mechanic.crop.CropStageConfig;
|
||||
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.util.DummyCancellable;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
public class BukkitCustomCropsAPI implements CustomCropsAPI {
|
||||
|
||||
private static CustomCropsAPI instance;
|
||||
|
||||
private final BukkitCustomCropsPlugin plugin;
|
||||
|
||||
public BukkitCustomCropsAPI(BukkitCustomCropsPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
instance = this;
|
||||
}
|
||||
|
||||
public static CustomCropsAPI get() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pos3 adapt(Location location) {
|
||||
return Pos3.from(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable CustomCropsWorld<?> getCustomCropsWorld(String name) {
|
||||
return plugin.getWorldManager().getWorld(name).orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable CustomCropsWorld<?> getCustomCropsWorld(World world) {
|
||||
return plugin.getWorldManager().getWorld(world).orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean placeCrop(Location location, String id, int point) {
|
||||
CropConfig cropConfig = Registries.CROP.get(id);
|
||||
if (cropConfig == null) {
|
||||
return false;
|
||||
}
|
||||
Optional<CustomCropsWorld<?>> optionalWorld = plugin.getWorldManager().getWorld(location.getWorld());
|
||||
if (optionalWorld.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
CustomCropsWorld<?> world = optionalWorld.get();
|
||||
CropBlock cropBlock = (CropBlock) BuiltInBlockMechanics.CROP.mechanic();
|
||||
CustomCropsBlockState state = BuiltInBlockMechanics.CROP.createBlockState();
|
||||
cropBlock.id(state, id);
|
||||
cropBlock.point(state, point);
|
||||
CropStageConfig stageConfigWithModel = cropConfig.stageWithModelByPoint(cropBlock.point(state));
|
||||
world.addBlockState(Pos3.from(location), state);
|
||||
plugin.getScheduler().sync().run(() -> {
|
||||
plugin.getItemManager().remove(location, ExistenceForm.ANY);
|
||||
plugin.getItemManager().place(location, stageConfigWithModel.existenceForm(), requireNonNull(stageConfigWithModel.stageID()), cropConfig.rotation() ? FurnitureRotation.random() : FurnitureRotation.NONE);
|
||||
}, location);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void simulatePlayerBreakCrop(
|
||||
Player player,
|
||||
EquipmentSlot hand,
|
||||
Location location,
|
||||
BreakReason reason
|
||||
) {
|
||||
Optional<CustomCropsWorld<?>> optionalWorld = plugin.getWorldManager().getWorld(location.getWorld());
|
||||
if (optionalWorld.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
Pos3 pos3 = Pos3.from(location);
|
||||
CustomCropsWorld<?> world = optionalWorld.get();
|
||||
Optional<CustomCropsBlockState> optionalState = world.getBlockState(pos3);
|
||||
if (optionalState.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
CustomCropsBlockState state = optionalState.get();
|
||||
if (!(state.type() instanceof CropBlock cropBlock)) {
|
||||
return;
|
||||
}
|
||||
CropConfig config = cropBlock.config(state);
|
||||
if (config == null) {
|
||||
return;
|
||||
}
|
||||
CropStageConfig stageConfig = config.stageWithModelByPoint(cropBlock.point(state));
|
||||
DummyCancellable dummyCancellable = new DummyCancellable();
|
||||
if (player != null) {
|
||||
ItemStack itemStack = player.getInventory().getItem(hand);
|
||||
state.type().onBreak(new WrappedBreakEvent(player, null, hand, location, stageConfig.stageID(), itemStack, plugin.getItemManager().id(itemStack), reason, world, dummyCancellable));
|
||||
} else {
|
||||
state.type().onBreak(new WrappedBreakEvent(null, null, null, location, stageConfig.stageID(), null, null, reason, world, dummyCancellable));
|
||||
}
|
||||
if (dummyCancellable.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
world.removeBlockState(pos3);
|
||||
plugin.getItemManager().remove(location, ExistenceForm.ANY);
|
||||
}
|
||||
}
|
||||
@@ -60,6 +60,7 @@ public abstract class BukkitCustomCropsPlugin implements CustomCropsPlugin {
|
||||
protected WorldManager worldManager;
|
||||
protected RegistryAccess registryAccess;
|
||||
protected SenderFactory<BukkitCustomCropsPlugin, CommandSender> senderFactory;
|
||||
protected CustomCropsAPI api;
|
||||
|
||||
protected final Map<Class<?>, ActionManager<?>> actionManagers = new HashMap<>();
|
||||
protected final Map<Class<?>, RequirementManager<?>> requirementManagers = new HashMap<>();
|
||||
@@ -74,6 +75,7 @@ public abstract class BukkitCustomCropsPlugin implements CustomCropsPlugin {
|
||||
throw new IllegalArgumentException("CustomCrops plugin requires custom crops plugin");
|
||||
}
|
||||
this.bootstrap = bootstrap;
|
||||
this.api = new BukkitCustomCropsAPI(this);
|
||||
instance = this;
|
||||
}
|
||||
|
||||
@@ -200,6 +202,15 @@ public abstract class BukkitCustomCropsPlugin implements CustomCropsPlugin {
|
||||
return registryAccess;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the API instance
|
||||
*
|
||||
* @return API
|
||||
*/
|
||||
public CustomCropsAPI getAPI() {
|
||||
return api;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves an ActionManager for a specific type.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import net.momirealms.customcrops.api.core.block.BreakReason;
|
||||
import net.momirealms.customcrops.api.core.world.CustomCropsWorld;
|
||||
import net.momirealms.customcrops.api.core.world.Pos3;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface CustomCropsAPI {
|
||||
|
||||
/**
|
||||
* Adapts a Bukkit Location to a Pos3
|
||||
*
|
||||
* @param location location
|
||||
* @return pos3
|
||||
*/
|
||||
Pos3 adapt(Location location);
|
||||
|
||||
/**
|
||||
* Gets the CustomCrops world
|
||||
*
|
||||
* @param name world name
|
||||
* @return the world
|
||||
*/
|
||||
@Nullable CustomCropsWorld<?> getCustomCropsWorld(String name);
|
||||
|
||||
/**
|
||||
* Gets the CustomCrops world
|
||||
*
|
||||
* @param world Bukkit world
|
||||
* @return the world
|
||||
*/
|
||||
@Nullable CustomCropsWorld<?> getCustomCropsWorld(World world);
|
||||
|
||||
/**
|
||||
* Places a crop regardless of planting conditions such as pots.
|
||||
*
|
||||
* @param location location
|
||||
* @param id crop id
|
||||
* @param point point
|
||||
* @return success or not
|
||||
*/
|
||||
boolean placeCrop(Location location, String id, int point);
|
||||
|
||||
/**
|
||||
* Performs actions to destroy crops on behalf of the player.
|
||||
*
|
||||
* @param player player
|
||||
* @param hand hand
|
||||
* @param location location
|
||||
* @param reason reason
|
||||
*/
|
||||
void simulatePlayerBreakCrop(Player player, EquipmentSlot hand, Location location, BreakReason reason);
|
||||
}
|
||||
@@ -50,7 +50,6 @@ import org.bukkit.inventory.ItemStack;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class CropBlock extends AbstractCustomCropsBlock {
|
||||
|
||||
@@ -345,25 +344,7 @@ public class CropBlock extends AbstractCustomCropsBlock {
|
||||
World bukkitWorld = world.bukkitWorld();
|
||||
Location bukkitLocation = location.toLocation(bukkitWorld);
|
||||
|
||||
CompletableFuture<Boolean> future = new CompletableFuture<>();
|
||||
if (ConfigManager.doubleCheck()) {
|
||||
plugin.getScheduler().sync().run(() -> {
|
||||
CropStageConfig nearest = config.stageWithModelByPoint(previousPoint);
|
||||
String blockID = plugin.getItemManager().id(location.toLocation(bukkitWorld), nearest.existenceForm());
|
||||
if (!config.stageIDs().contains(blockID)) {
|
||||
plugin.getPluginLogger().warn("Crop[" + config.id() + "] is removed at location[" + world.worldName() + "," + location + "] because the id of the block is [" + blockID + "]");
|
||||
world.removeBlockState(location);
|
||||
future.complete(false);
|
||||
return;
|
||||
}
|
||||
future.complete(true);
|
||||
}, bukkitLocation);
|
||||
} else {
|
||||
future.complete(true);
|
||||
}
|
||||
|
||||
future.thenAcceptAsync((run) -> {
|
||||
if (!run) return;
|
||||
Runnable task = () -> {
|
||||
Context<CustomCropsBlockState> context = Context.block(state, bukkitLocation).arg(ContextKeys.OFFLINE, offline);
|
||||
for (DeathCondition deathCondition : config.deathConditions()) {
|
||||
if (deathCondition.isMet(context)) {
|
||||
@@ -430,7 +411,22 @@ public class CropBlock extends AbstractCustomCropsBlock {
|
||||
}
|
||||
}
|
||||
}, bukkitLocation);
|
||||
}, world.scheduler().async());
|
||||
};
|
||||
|
||||
if (ConfigManager.doubleCheck()) {
|
||||
plugin.getScheduler().sync().run(() -> {
|
||||
CropStageConfig nearest = config.stageWithModelByPoint(previousPoint);
|
||||
String blockID = plugin.getItemManager().id(location.toLocation(bukkitWorld), nearest.existenceForm());
|
||||
if (!config.stageIDs().contains(blockID)) {
|
||||
plugin.getPluginLogger().warn("Crop[" + config.id() + "] is removed at location[" + world.worldName() + "," + location + "] because the id of the block is [" + blockID + "]");
|
||||
world.removeBlockState(location);
|
||||
return;
|
||||
}
|
||||
world.scheduler().async().execute(task);
|
||||
}, bukkitLocation);
|
||||
} else {
|
||||
task.run();
|
||||
}
|
||||
}
|
||||
|
||||
public int point(CustomCropsBlockState state) {
|
||||
|
||||
@@ -29,10 +29,7 @@ import net.momirealms.customcrops.api.core.block.ScarecrowBlock;
|
||||
import net.momirealms.customcrops.api.core.mechanic.crop.CrowAttack;
|
||||
import net.momirealms.customcrops.api.core.mechanic.fertilizer.Fertilizer;
|
||||
import net.momirealms.customcrops.api.core.mechanic.fertilizer.FertilizerConfig;
|
||||
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.world.Season;
|
||||
import net.momirealms.customcrops.api.core.world.*;
|
||||
import net.momirealms.customcrops.api.misc.value.MathValue;
|
||||
import net.momirealms.customcrops.api.misc.value.TextValue;
|
||||
import net.momirealms.customcrops.api.util.MoonPhase;
|
||||
@@ -988,7 +985,11 @@ public abstract class AbstractRequirementManager<T> implements RequirementManage
|
||||
for (int i = -range; i <= range; i++) {
|
||||
for (int j = -range; j <= range; j++) {
|
||||
for (int k : new int[]{0,-1,1}) {
|
||||
Optional<CustomCropsBlockState> optionalState = customCropsWorld.getBlockState(pos3.add(i, k, j));
|
||||
Pos3 tempPos3 = pos3.add(i, k, j);
|
||||
Optional<CustomCropsChunk> optionalChunk = customCropsWorld.getLoadedChunk(tempPos3.toChunkPos());
|
||||
if (optionalChunk.isPresent()) {
|
||||
CustomCropsChunk chunk = optionalChunk.get();
|
||||
Optional<CustomCropsBlockState> optionalState = chunk.getBlockState(pos3);
|
||||
if (optionalState.isPresent() && optionalState.get().type() instanceof ScarecrowBlock) {
|
||||
if (advanced) ActionManager.trigger(context, actions);
|
||||
return false;
|
||||
@@ -996,6 +997,7 @@ public abstract class AbstractRequirementManager<T> implements RequirementManage
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (customCropsWorld.doesChunkHaveBlock(pos3, ScarecrowBlock.class)) {
|
||||
if (advanced) ActionManager.trigger(context, actions);
|
||||
|
||||
@@ -41,7 +41,7 @@ public class MMOItemsItemProvider implements ItemProvider {
|
||||
@NotNull
|
||||
@Override
|
||||
public ItemStack buildItem(@NotNull Player player, @NotNull String id) {
|
||||
String[] split = id.split(":");
|
||||
String[] split = id.split(":", 2);
|
||||
MMOItem mmoItem = MMOItems.plugin.getMMOItem(Type.get(split[0]), split[1].toUpperCase(Locale.ENGLISH));
|
||||
return mmoItem == null ? new ItemStack(Material.AIR) : requireNonNull(mmoItem.newBuilder().build());
|
||||
}
|
||||
@@ -50,6 +50,10 @@ public class MMOItemsItemProvider implements ItemProvider {
|
||||
public String itemID(@NotNull ItemStack itemStack) {
|
||||
NBTItem nbtItem = NBTItem.get(itemStack);
|
||||
if (!nbtItem.hasTag("MMOITEMS_ITEM_ID")) return null;
|
||||
if (nbtItem.hasType()) {
|
||||
return nbtItem.getType() + ":" + nbtItem.getString("MMOITEMS_ITEM_ID");
|
||||
} else {
|
||||
return nbtItem.getString("MMOITEMS_ITEM_ID");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Project settings
|
||||
# Rule: [major update].[feature update].[bug fix]
|
||||
project_version=3.6.13
|
||||
project_version=3.6.14
|
||||
config_version=41
|
||||
project_group=net.momirealms
|
||||
|
||||
|
||||
@@ -223,6 +223,7 @@ public class BukkitCustomCropsPluginImpl extends BukkitCustomCropsPlugin {
|
||||
this.coolDownManager.reload();
|
||||
this.translationManager.reload();
|
||||
this.hologramManager.reload();
|
||||
this.itemManager.reload();
|
||||
|
||||
this.actionManagers.values().forEach(Reloadable::reload);
|
||||
this.requirementManagers.values().forEach(Reloadable::reload);
|
||||
|
||||
@@ -196,7 +196,7 @@ public class BukkitWorldAdaptor extends AbstractWorldAdaptor<World> {
|
||||
if (parentDir != null && !parentDir.exists()) {
|
||||
parentDir.mkdirs();
|
||||
}
|
||||
try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file))) {
|
||||
try (FileOutputStream fos = new FileOutputStream(file); BufferedOutputStream bos = new BufferedOutputStream(fos)) {
|
||||
bos.write(serializeRegion(region));
|
||||
long time2 = System.currentTimeMillis();
|
||||
BukkitCustomCropsPlugin.getInstance().debug(() -> "[" + world.worldName() + "] Took " + (time2-time1) + "ms to save region " + region.regionPos());
|
||||
|
||||
@@ -328,7 +328,9 @@ public class BukkitItemManager extends AbstractItemManager {
|
||||
if (itemStack == null || itemStack.getType() == Material.AIR) return "AIR";
|
||||
String id = provider.itemID(itemStack);
|
||||
if (id != null) return id;
|
||||
plugin.debug(() -> "Start checking ID from external plugins");
|
||||
for (ItemProvider p : itemDetectArray) {
|
||||
plugin.debug(p::identifier);
|
||||
id = p.itemID(itemStack);
|
||||
if (id != null) return p.identifier() + ":" + id;
|
||||
}
|
||||
@@ -458,6 +460,8 @@ public class BukkitItemManager extends AbstractItemManager {
|
||||
}
|
||||
|
||||
private void handleInteractEvent(String blockID, WrappedInteractEvent wrapped) {
|
||||
plugin.debug(() -> "Player [" + wrapped.player().getName() + "] interacted [" + blockID + "] with [" + wrapped.itemID() + "] at " + wrapped.location());
|
||||
|
||||
CustomCropsItem customCropsItem = Registries.ITEMS.get(wrapped.itemID());
|
||||
if (customCropsItem != null) {
|
||||
InteractionResult result = customCropsItem.interactAt(wrapped);
|
||||
|
||||
@@ -134,6 +134,12 @@ public class BukkitWorldManager implements WorldManager, Listener {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unload() {
|
||||
HandlerList.unregisterAll(this);
|
||||
this.worldSettings.clear();
|
||||
}
|
||||
|
||||
private void loadConfig() {
|
||||
YamlDocument config = BukkitConfigManager.getMainConfig();
|
||||
|
||||
@@ -170,12 +176,6 @@ public class BukkitWorldManager implements WorldManager, Listener {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unload() {
|
||||
HandlerList.unregisterAll(this);
|
||||
this.worldSettings.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disable() {
|
||||
this.unload();
|
||||
|
||||
Reference in New Issue
Block a user