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

add comments

This commit is contained in:
XiaoMoMi
2024-09-04 01:42:37 +08:00
parent 31976acc2a
commit 32f01f1aec
55 changed files with 3048 additions and 310 deletions

View File

@@ -36,10 +36,12 @@ import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;
public abstract class BukkitCustomCropsPlugin implements CustomCropsPlugin {
@@ -75,7 +77,7 @@ public abstract class BukkitCustomCropsPlugin implements CustomCropsPlugin {
}
/**
* Retrieves the singleton instance of BukkitCustomFishingPlugin.
* Retrieves the singleton instance of BukkitCustomCropsPlugin.
*
* @return the singleton instance
* @throws IllegalArgumentException if the plugin is not initialized
@@ -116,31 +118,117 @@ public abstract class BukkitCustomCropsPlugin implements CustomCropsPlugin {
return translationManager;
}
/**
* Retrieves the ItemManager.
*
* @return the {@link AbstractItemManager}
*/
@NotNull
public AbstractItemManager getItemManager() {
return itemManager;
}
/**
* Retrieves the SchedulerAdapter.
*
* @return the {@link SchedulerAdapter}
*/
@Override
@NotNull
public SchedulerAdapter<Location, World> getScheduler() {
return scheduler;
}
/**
* Retrieves the SenderFactory.
*
* @return the {@link SenderFactory}
*/
@NotNull
public SenderFactory<BukkitCustomCropsPlugin, CommandSender> getSenderFactory() {
return senderFactory;
}
/**
* Retrieves the WorldManager.
*
* @return the {@link WorldManager}
*/
@NotNull
public WorldManager getWorldManager() {
return worldManager;
}
/**
* Retrieves the IntegrationManager.
*
* @return the {@link IntegrationManager}
*/
@NotNull
public IntegrationManager getIntegrationManager() {
return integrationManager;
}
/**
* Retrieves the PlaceholderManager.
*
* @return the {@link PlaceholderManager}
*/
@NotNull
public PlaceholderManager getPlaceholderManager() {
return placeholderManager;
}
/**
* Retrieves the CoolDownManager.
*
* @return the {@link CoolDownManager}
*/
@NotNull
public CoolDownManager getCoolDownManager() {
return coolDownManager;
}
/**
* Retrieves the RegistryAccess.
*
* @return the {@link RegistryAccess}
*/
@NotNull
public RegistryAccess getRegistryAccess() {
return registryAccess;
}
/**
* Retrieves an ActionManager for a specific type.
*
* @param type the class type of the action
* @return the {@link ActionManager} for the specified type
* @throws IllegalArgumentException if the type is null
*/
@SuppressWarnings("unchecked")
public <T> ActionManager<T> getActionManager(Class<T> type) {
if (type == null) {
throw new IllegalArgumentException("Type cannot be null");
}
return (ActionManager<T>) actionManagers.get(type);
}
/**
* Retrieves a RequirementManager for a specific type.
*
* @param type the class type of the requirement
* @return the {@link RequirementManager} for the specified type
* @throws IllegalArgumentException if the type is null
*/
@SuppressWarnings("unchecked")
public <T> RequirementManager<T> getRequirementManager(Class<T> type) {
if (type == null) {
throw new IllegalArgumentException("Type cannot be null");
}
return (RequirementManager<T>) instance.requirementManagers.get(type);
}
/**
* Logs a debug message.
*
@@ -148,31 +236,19 @@ public abstract class BukkitCustomCropsPlugin implements CustomCropsPlugin {
*/
public abstract void debug(Object message);
/**
* Logs a debug message using a {@link Supplier}.
*
* @param message the message supplier to log
*/
public abstract void debug(Supplier<Object> message);
/**
* Retrieves the data folder for the plugin.
*
* @return the data folder as a {@link File}
*/
public File getDataFolder() {
return boostrap.getDataFolder();
}
public RegistryAccess getRegistryAccess() {
return registryAccess;
}
@SuppressWarnings("unchecked")
public <T> ActionManager<T> getActionManager(Class<T> type) {
if (type == null) {
throw new IllegalArgumentException("Type cannot be null");
}
return (ActionManager<T>) actionManagers.get(type);
}
@SuppressWarnings("unchecked")
public <T> RequirementManager<T> getRequirementManager(Class<T> type) {
if (type == null) {
throw new IllegalArgumentException("Type cannot be null");
}
return (RequirementManager<T>) instance.requirementManagers.get(type);
}
public CoolDownManager getCoolDownManager() {
return coolDownManager;
}
}

View File

@@ -24,6 +24,9 @@ import net.momirealms.customcrops.common.util.Key;
import java.util.Objects;
/**
* BuiltInBlockMechanics defines a set of standard block mechanics for the Custom Crops plugin.
*/
public class BuiltInBlockMechanics {
public static final BuiltInBlockMechanics CROP = create("crop");
@@ -35,26 +38,58 @@ public class BuiltInBlockMechanics {
private final Key key;
public BuiltInBlockMechanics(Key key) {
/**
* Constructs a new BuiltInBlockMechanics with a unique key.
*
* @param key the unique key for this mechanic
*/
private BuiltInBlockMechanics(Key key) {
this.key = key;
}
/**
* Factory method to create a new BuiltInBlockMechanics instance with the specified ID.
*
* @param id the ID of the mechanic
* @return a new BuiltInBlockMechanics instance
*/
static BuiltInBlockMechanics create(String id) {
return new BuiltInBlockMechanics(Key.key("customcrops", id));
return new BuiltInBlockMechanics(Key.key("customcrops", id));
}
/**
* Retrieves the unique key associated with this block mechanic.
*
* @return the key
*/
public Key key() {
return key;
}
/**
* Creates a new CustomCropsBlockState using the associated block mechanic.
*
* @return a new CustomCropsBlockState
*/
public CustomCropsBlockState createBlockState() {
return mechanic().createBlockState();
}
/**
* Creates a new CustomCropsBlockState using the associated block mechanic and provided data.
*
* @param data the compound map data for the block state
* @return a new CustomCropsBlockState
*/
public CustomCropsBlockState createBlockState(CompoundMap data) {
return mechanic().createBlockState(data);
}
/**
* Retrieves the CustomCropsBlock associated with this block mechanic.
*
* @return the CustomCropsBlock
*/
public CustomCropsBlock mechanic() {
return Objects.requireNonNull(Registries.BLOCK.get(key));
}

View File

@@ -20,6 +20,9 @@ package net.momirealms.customcrops.api.core;
import net.momirealms.customcrops.api.core.item.CustomCropsItem;
import net.momirealms.customcrops.common.util.Key;
/**
* BuiltInItemMechanics defines a set of standard item mechanics for the Custom Crops plugin.
*/
public class BuiltInItemMechanics {
public static final BuiltInItemMechanics WATERING_CAN = create("watering_can");
@@ -29,18 +32,39 @@ public class BuiltInItemMechanics {
private final Key key;
public BuiltInItemMechanics(Key key) {
/**
* Constructs a new BuiltInItemMechanics with a unique key.
*
* @param key the unique key for this mechanic
*/
private BuiltInItemMechanics(Key key) {
this.key = key;
}
/**
* Factory method to create a new BuiltInItemMechanics instance with the specified ID.
*
* @param id the ID of the mechanic
* @return a new BuiltInItemMechanics instance
*/
static BuiltInItemMechanics create(String id) {
return new BuiltInItemMechanics(Key.key("customcrops", id));
return new BuiltInItemMechanics(Key.key("customcrops", id));
}
/**
* Retrieves the unique key associated with this item mechanic.
*
* @return the key
*/
public Key key() {
return key;
}
/**
* Retrieves the CustomCropsItem associated with this item mechanic.
*
* @return the CustomCropsItem
*/
public CustomCropsItem mechanic() {
return Registries.ITEM.get(key);
}

View File

@@ -19,16 +19,33 @@ package net.momirealms.customcrops.api.core;
import net.momirealms.customcrops.common.util.Key;
/**
* ClearableMappedRegistry is a concrete implementation of the ClearableRegistry interface.
* It extends MappedRegistry and provides the capability to clear all entries.
*
* @param <K> the type of keys maintained by this registry
* @param <T> the type of mapped values
*/
public class ClearableMappedRegistry<K, T> extends MappedRegistry<K, T> implements ClearableRegistry<K, T> {
/**
* Constructs a new ClearableMappedRegistry with a unique key.
*
* @param key the unique key for this registry
*/
public ClearableMappedRegistry(Key key) {
super(key);
}
/**
* Clears all entries from the registry.
* This operation removes all key-value mappings from the registry,
* leaving it empty.
*/
@Override
public void clear() {
super.byID.clear();
super.byKey.clear();
super.byValue.clear();
super.byID.clear(); // Clears the list of values indexed by ID
super.byKey.clear(); // Clears the map of keys to values
super.byValue.clear(); // Clears the map of values to keys
}
}
}

View File

@@ -17,7 +17,19 @@
package net.momirealms.customcrops.api.core;
/**
* The ClearableRegistry interface extends WriteableRegistry and provides
* an additional method to clear all entries from the registry.
*
* @param <K> the type of keys maintained by this registry
* @param <T> the type of mapped values
*/
public interface ClearableRegistry<K, T> extends WriteableRegistry<K, T> {
/**
* Clears all entries from the registry.
* This operation removes all key-value mappings from the registry,
* leaving it empty.
*/
void clear();
}
}

View File

@@ -247,14 +247,44 @@ public abstract class ConfigManager implements ConfigLoader, Reloadable {
return configFile;
}
/**
* Registers a new WateringCan configuration to the plugin.
* Call this method in {@link net.momirealms.customcrops.api.event.CustomCropsReloadEvent} otherwise the config would lose on each reload
*
* @param config the WateringCanConfig object to register
*/
public abstract void registerWateringCanConfig(WateringCanConfig config);
/**
* Registers a new Fertilizer configuration to the plugin.
* Call this method in {@link net.momirealms.customcrops.api.event.CustomCropsReloadEvent} otherwise the config would lose on each reload
*
* @param config the FertilizerConfig object to register
*/
public abstract void registerFertilizerConfig(FertilizerConfig config);
/**
* Registers a new Crop configuration to the plugin.
* Call this method in {@link net.momirealms.customcrops.api.event.CustomCropsReloadEvent} otherwise the config would lose on each reload
*
* @param config the CropConfig object to register
*/
public abstract void registerCropConfig(CropConfig config);
/**
* Registers a new Pot configuration to the plugin.
* Call this method in {@link net.momirealms.customcrops.api.event.CustomCropsReloadEvent} otherwise the config would lose on each reload
*
* @param config the PotConfig object to register
*/
public abstract void registerPotConfig(PotConfig config);
/**
* Registers a new Sprinkler configuration to the plugin.
* Call this method in {@link net.momirealms.customcrops.api.event.CustomCropsReloadEvent} otherwise the config would lose on each reload
*
* @param config the SprinklerConfig object to register
*/
public abstract void registerSprinklerConfig(SprinklerConfig config);
public WateringMethod[] getWateringMethods(Section section) {

View File

@@ -24,28 +24,90 @@ import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* Interface defining methods for managing custom items, blocks, and furniture in the CustomCrops plugin.
* This interface provides methods for placing and removing custom blocks and furniture, as well as
* retrieving IDs and ItemStacks associated with custom items.
*/
public interface CustomItemProvider {
/**
* Removes a custom block at the specified location.
*
* @param location The location from which to remove the custom block.
* @return true if the block was successfully removed, false otherwise.
*/
boolean removeCustomBlock(Location location);
/**
* Places a custom block at the specified location.
*
* @param location The location where the custom block should be placed.
* @param id The ID of the custom block to place.
* @return true if the block was successfully placed, false otherwise.
*/
boolean placeCustomBlock(Location location, String id);
/**
* Places a piece of custom furniture at the specified location.
*
* @param location The location where the furniture should be placed.
* @param id The ID of the furniture to place.
* @return The entity representing the placed furniture, or null if placement failed.
*/
@Nullable
Entity placeFurniture(Location location, String id);
/**
* Removes a piece of custom furniture represented by the specified entity.
*
* @param entity The entity representing the furniture to remove.
* @return true if the furniture was successfully removed, false otherwise.
*/
boolean removeFurniture(Entity entity);
/**
* Retrieves the ID of a custom block at the specified block.
*
* @param block The block to check.
* @return The ID of the custom block, or null if no custom block is found.
*/
@Nullable
String blockID(Block block);
/**
* Retrieves the ID of a custom item represented by the provided ItemStack.
*
* @param itemStack The ItemStack to check.
* @return The ID of the custom item, or null if no custom item is found.
*/
@Nullable
String itemID(ItemStack itemStack);
/**
* Creates an ItemStack for a custom item based on the given item ID and player.
*
* @param player The player for whom the item is being created.
* @param id The ID of the custom item.
* @return The constructed ItemStack, or null if creation fails.
*/
@Nullable
ItemStack itemStack(Player player, String id);
/**
* Retrieves the ID of a custom furniture item associated with the specified entity.
*
* @param entity The entity to check.
* @return The ID of the furniture, or null if no furniture is found.
*/
@Nullable
String furnitureID(Entity entity);
/**
* Determines if the specified entity is a piece of custom furniture.
*
* @param entity The entity to check.
* @return true if the entity is a piece of custom furniture, false otherwise.
*/
boolean isFurniture(Entity entity);
}

View File

@@ -44,9 +44,6 @@ public enum FurnitureRotation {
public static FurnitureRotation getByRotation(Rotation rotation) {
switch (rotation) {
default -> {
return FurnitureRotation.SOUTH;
}
case CLOCKWISE -> {
return FurnitureRotation.WEST;
}
@@ -56,6 +53,9 @@ public enum FurnitureRotation {
case FLIPPED -> {
return FurnitureRotation.NORTH;
}
default -> {
return FurnitureRotation.SOUTH;
}
}
}

View File

@@ -17,16 +17,45 @@
package net.momirealms.customcrops.api.core;
import javax.annotation.Nullable;
import org.jetbrains.annotations.Nullable;
/**
* The IdMap interface defines a structure for managing and retrieving objects
* by their unique identifiers (IDs).
*
* @param <T> the type of objects managed by this IdMap
*/
public interface IdMap<T> extends Iterable<T> {
/**
* The default value used to indicate that no ID is assigned or available.
*/
int DEFAULT = -1;
/**
* Retrieves the unique identifier associated with a given object.
*
* @param value the object whose ID is to be retrieved
* @return the unique identifier of the object, or -1 if not found
*/
int getId(T value);
/**
* Retrieves an object by its unique identifier.
*
* @param index the unique identifier of the object
* @return the object associated with the given ID, or null if not present
*/
@Nullable
T byId(int index);
/**
* Retrieves an object by its unique identifier or throws an exception if not found.
*
* @param index the unique identifier of the object
* @return the object associated with the given ID
* @throws IllegalArgumentException if no object with the given ID exists
*/
default T byIdOrThrow(int index) {
T object = this.byId(index);
if (object == null) {
@@ -36,6 +65,13 @@ public interface IdMap<T> extends Iterable<T> {
}
}
/**
* Retrieves the unique identifier associated with a given object or throws an exception if not found.
*
* @param value the object whose ID is to be retrieved
* @return the unique identifier of the object
* @throws IllegalArgumentException if no ID for the given object exists
*/
default int getIdOrThrow(T value) {
int i = this.getId(value);
if (i == -1) {
@@ -45,5 +81,10 @@ public interface IdMap<T> extends Iterable<T> {
}
}
/**
* Returns the total number of entries in this IdMap.
*
* @return the number of entries
*/
int size();
}
}

View File

@@ -27,55 +27,186 @@ import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Interface defining methods for managing custom items, blocks, and furniture in the CustomCrops plugin.
* It includes methods for placing and removing items and blocks, interacting with custom events, and managing item data.
*/
public interface ItemManager extends Reloadable {
/**
* Places an item at the specified location.
*
* @param location The location where the item should be placed.
* @param form The existence form of the item (e.g., block or furniture).
* @param id The ID of the item to place.
* @param rotation The rotation of the furniture, if applicable.
*/
void place(@NotNull Location location, @NotNull ExistenceForm form, @NotNull String id, FurnitureRotation rotation);
/**
* Removes an item from the specified location.
*
* @param location The location from which the item should be removed.
* @param form The existence form of the item (e.g., block or furniture).
* @return The rotation of the removed furniture, or NONE if no furniture was found.
*/
@NotNull
FurnitureRotation remove(@NotNull Location location, @NotNull ExistenceForm form);
/**
* Places a custom block at the specified location.
*
* @param location The location where the block should be placed.
* @param id The ID of the block to place.
*/
void placeBlock(@NotNull Location location, @NotNull String id);
/**
* Places a piece of furniture at the specified location.
*
* @param location The location where the furniture should be placed.
* @param id The ID of the furniture to place.
* @param rotation The rotation of the furniture.
*/
void placeFurniture(@NotNull Location location, @NotNull String id, FurnitureRotation rotation);
/**
* Removes a custom block from the specified location.
*
* @param location The location from which the block should be removed.
*/
void removeBlock(@NotNull Location location);
@Nullable
/**
* Removes furniture from the specified location.
*
* @param location The location from which the furniture should be removed.
* @return The rotation of the removed furniture, or NONE if no furniture was found.
*/
@NotNull
FurnitureRotation removeFurniture(@NotNull Location location);
/**
* Retrieves the ID of the custom block at the specified location.
*
* @param location The location of the block.
* @return The ID of the block.
*/
@NotNull
default String blockID(@NotNull Location location) {
return blockID(location.getBlock());
}
/**
* Retrieves the ID of the custom block at the specified block.
*
* @param block The block to check.
* @return The ID of the block.
*/
@NotNull
String blockID(@NotNull Block block);
/**
* Retrieves the ID of the furniture attached to the specified entity.
*
* @param entity The entity to check.
* @return The ID of the furniture, or null if not applicable.
*/
@Nullable
String furnitureID(@NotNull Entity entity);
/**
* Retrieves the ID of the custom entity.
*
* @param entity The entity to check.
* @return The ID of the entity.
*/
@NotNull String entityID(@NotNull Entity entity);
/**
* Retrieves the ID of the furniture at the specified location.
*
* @param location The location to check.
* @return The ID of the furniture, or null if no furniture is found.
*/
@Nullable
String furnitureID(Location location);
/**
* Retrieves the ID of any custom item at the specified location.
*
* @param location The location to check.
* @return The ID of any custom item.
*/
@NotNull
String anyID(Location location);
/**
* Retrieves the ID of the item at the specified location based on the existence form.
*
* @param location The location to check.
* @param form The existence form of the item.
* @return The ID of the item, or null if not found.
*/
@Nullable
String id(Location location, ExistenceForm form);
/**
* Sets a custom event listener for handling custom item events.
*
* @param listener The custom event listener to set.
*/
void setCustomEventListener(@NotNull AbstractCustomEventListener listener);
/**
* Sets a custom item provider for managing custom items.
*
* @param provider The custom item provider to set.
*/
void setCustomItemProvider(@NotNull CustomItemProvider provider);
String id(ItemStack itemStack);
/**
* Retrieves the ID of the custom item represented by the provided ItemStack.
*
* @param itemStack The ItemStack to check.
* @return The ID of the custom item.
*/
@NotNull
String id(@Nullable ItemStack itemStack);
/**
* Builds an ItemStack for the player based on the given item ID.
*
* @param player The player for whom the item is being built.
* @param id The ID of the item to build.
* @return The constructed ItemStack, or null if construction fails.
*/
@Nullable
ItemStack build(Player player, String id);
ItemStack build(@Nullable Player player, @NotNull String id);
Item<ItemStack> wrap(ItemStack itemStack);
/**
* Wraps an ItemStack into a custom item wrapper.
*
* @param itemStack The ItemStack to wrap.
* @return The wrapped custom item.
*/
Item<ItemStack> wrap(@NotNull ItemStack itemStack);
/**
* Decreases the damage on the provided item.
*
* @param player The item.
* @param itemStack The item to modify.
* @param amount The amount of damage to decrease.
*/
void decreaseDamage(Player player, ItemStack itemStack, int amount);
/**
* Increases the damage on the provided item.
*
* @param holder The item.
* @param itemStack The item to modify.
* @param amount The amount of damage to increase.
*/
void increaseDamage(Player holder, ItemStack itemStack, int amount);
}

View File

@@ -23,6 +23,13 @@ import org.jetbrains.annotations.Nullable;
import java.util.*;
/**
* A registry implementation that supports mapping keys to values and provides
* methods for registration, lookup, and iteration.
*
* @param <K> the type of the keys used for lookup
* @param <T> the type of the values stored in the registry
*/
public class MappedRegistry<K, T> implements WriteableRegistry<K, T> {
protected final Map<K, T> byKey = new HashMap<>(1024);
@@ -30,54 +37,111 @@ public class MappedRegistry<K, T> implements WriteableRegistry<K, T> {
protected final ArrayList<T> byID = new ArrayList<>(1024);
private final Key key;
/**
* Constructs a new MappedRegistry with a given unique key.
*
* @param key the unique key for this registry
*/
public MappedRegistry(Key key) {
this.key = key;
}
/**
* Registers a new key-value pair in the registry.
*
* @param key the key associated with the value
* @param value the value to be registered
*/
@Override
public void register(K key, T value) {
if (byKey.containsKey(key)) return;
byKey.put(key, value);
byValue.put(value, key);
byID.add(value);
}
/**
* Gets the unique key identifier for this registry.
*
* @return the key of the registry
*/
@Override
public Key key() {
return key;
}
/**
* Retrieves the index (ID) of a given value in the registry.
*
* @param value the value to look up
* @return the index of the value, or -1 if not found
*/
@Override
public int getId(@Nullable T value) {
return byID.indexOf(value);
}
/**
* Retrieves a value from the registry by its index (ID).
*
* @param index the index of the value
* @return the value at the specified index, or null if out of bounds
*/
@Nullable
@Override
public T byId(int index) {
return byID.get(index);
}
/**
* Gets the number of entries in the registry.
*
* @return the size of the registry
*/
@Override
public int size() {
return byKey.size();
}
/**
* Retrieves a value from the registry by its key.
*
* @param key the key of the value
* @return the value associated with the key, or null if not found
*/
@Nullable
@Override
public T get(@Nullable K key) {
return byKey.get(key);
}
/**
* Checks if the registry contains a given key.
*
* @param key the key to check
* @return true if the key exists, false otherwise
*/
@Override
public boolean containsKey(@Nullable K key) {
return byKey.containsKey(key);
}
/**
* Checks if the registry contains a given value.
*
* @param value the value to check
* @return true if the value exists, false otherwise
*/
@Override
public boolean containsValue(@Nullable T value) {
return byValue.containsKey(value);
}
/**
* Provides an iterator over the values in the registry.
*
* @return an iterator for the registry values
*/
@NotNull
@Override
public Iterator<T> iterator() {

View File

@@ -18,20 +18,56 @@
package net.momirealms.customcrops.api.core;
import net.momirealms.customcrops.common.util.Key;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.annotation.Nullable;
/**
* The Registry interface defines a structure for a key-value mapping system
* that supports efficient retrieval and management of entries.
*
* @param <K> the type of keys maintained by this registry
* @param <T> the type of values that the keys map to
*/
public interface Registry<K, T> extends IdMap<T> {
/**
* Retrieves the unique key associated with this registry.
*
* @return the unique {@link Key} of this registry
*/
Key key();
/**
* Retrieves the unique identifier associated with a value.
*
* @param value the value whose identifier is to be retrieved
* @return the unique identifier of the value, or -1 if not present
*/
@Override
int getId(@Nullable T value);
int getId(@NotNull T value);
/**
* Retrieves a value mapped to the specified key.
*
* @param key the key associated with the value to be retrieved
* @return the value mapped to the specified key, or null if no mapping exists
*/
@Nullable
T get(@Nullable K key);
T get(@NotNull K key);
boolean containsKey(@Nullable K key);
/**
* Checks if the registry contains a mapping for the specified key.
*
* @param key the key to check for existence
* @return true if the registry contains a mapping for the key, false otherwise
*/
boolean containsKey(@NotNull K key);
boolean containsValue(@Nullable T value);
}
/**
* Checks if the registry contains the specified value.
*
* @param value the value to check for existence
* @return true if the registry contains the specified value, false otherwise
*/
boolean containsValue(@NotNull T value);
}

View File

@@ -22,17 +22,51 @@ import net.momirealms.customcrops.api.core.item.CustomCropsItem;
import net.momirealms.customcrops.api.core.mechanic.fertilizer.FertilizerType;
import net.momirealms.customcrops.common.util.Key;
/**
* Interface defining methods for registering and accessing different types of custom crop mechanics
* such as blocks, items, and fertilizer types in the CustomCrops plugin.
*/
public interface RegistryAccess {
/**
* Registers a new custom crop block mechanic.
*
* @param block The custom crop block to register.
*/
void registerBlockMechanic(CustomCropsBlock block);
/**
* Registers a new custom crop item mechanic.
*
* @param item The custom crop item to register.
*/
void registerItemMechanic(CustomCropsItem item);
/**
* Registers a new fertilizer type mechanic.
*
* @param type The fertilizer type to register.
*/
void registerFertilizerType(FertilizerType type);
/**
* Retrieves the registry containing all registered custom crop blocks.
*
* @return the block registry
*/
Registry<Key, CustomCropsBlock> getBlockRegistry();
/**
* Retrieves the registry containing all registered custom crop items.
*
* @return the item registry
*/
Registry<Key, CustomCropsItem> getItemRegistry();
/**
* Retrieves the registry containing all registered fertilizer types.
*
* @return the fertilizer type registry
*/
Registry<String, FertilizerType> getFertilizerTypeRegistry();
}

View File

@@ -1,26 +0,0 @@
/*
* 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.core;
import net.momirealms.customcrops.api.context.Context;
@FunctionalInterface
public interface StatedItem<T> {
String currentState(Context<T> context);
}

View File

@@ -28,6 +28,10 @@ import java.util.StringJoiner;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* A thread-safe wrapper around a CompoundMap that provides synchronized access
* to the underlying map for reading and writing operations.
*/
public class SynchronizedCompoundMap {
private final CompoundMap compoundMap;
@@ -35,14 +39,30 @@ public class SynchronizedCompoundMap {
private final java.util.concurrent.locks.Lock readLock = rwLock.readLock();
private final java.util.concurrent.locks.Lock writeLock = rwLock.writeLock();
/**
* Constructs a new SynchronizedCompoundMap with the specified CompoundMap.
*
* @param compoundMap the underlying CompoundMap to wrap
*/
public SynchronizedCompoundMap(CompoundMap compoundMap) {
this.compoundMap = compoundMap;
}
/**
* Returns the original underlying CompoundMap.
*
* @return the original CompoundMap
*/
public CompoundMap originalMap() {
return compoundMap;
}
/**
* Retrieves a Tag from the map using the specified key.
*
* @param key the key to look up
* @return the Tag associated with the key, or null if not found
*/
public Tag<?> get(String key) {
readLock.lock();
try {
@@ -52,6 +72,14 @@ public class SynchronizedCompoundMap {
}
}
/**
* Puts a Tag into the map with the specified key, returning the previous
* value associated with the key, if any.
*
* @param key the key to associate with the Tag
* @param tag the Tag to insert
* @return the previous Tag associated with the key, or null if none
*/
public Tag<?> put(String key, Tag<?> tag) {
writeLock.lock();
try {
@@ -61,6 +89,12 @@ public class SynchronizedCompoundMap {
}
}
/**
* Removes a Tag from the map with the specified key.
*
* @param key the key whose mapping is to be removed
* @return the Tag previously associated with the key, or null if none
*/
public Tag<?> remove(String key) {
writeLock.lock();
try {
@@ -83,13 +117,22 @@ public class SynchronizedCompoundMap {
return compoundMapToString("BlockData", compoundMap);
}
/**
* Recursively converts a CompoundMap to a string representation.
*
* @param key the key associated with the CompoundMap
* @param compoundMap the CompoundMap to convert
* @return a string representation of the CompoundMap
*/
@SuppressWarnings("unchecked")
private String compoundMapToString(String key, CompoundMap compoundMap) {
StringJoiner joiner = new StringJoiner(", ");
for (Map.Entry<String, Tag<?>> entry : compoundMap.entrySet()) {
Tag<?> tag = entry.getValue();
String tagValue;
switch (tag.getType()) {
case TAG_STRING, TAG_BYTE, TAG_DOUBLE, TAG_FLOAT, TAG_INT, TAG_INT_ARRAY, TAG_LONG, TAG_SHORT, TAG_SHORT_ARRAY, TAG_LONG_ARRAY, TAG_BYTE_ARRAY ->
case TAG_STRING, TAG_BYTE, TAG_DOUBLE, TAG_FLOAT, TAG_INT, TAG_INT_ARRAY,
TAG_LONG, TAG_SHORT, TAG_SHORT_ARRAY, TAG_LONG_ARRAY, TAG_BYTE_ARRAY ->
tagValue = tag.getValue().toString();
case TAG_LIST -> {
List<Tag<?>> list = (List<Tag<?>>) tag.getValue();
@@ -105,7 +148,7 @@ public class SynchronizedCompoundMap {
}
case TAG_COMPOUND -> tagValue = compoundMapToString(tag.getName(), (CompoundMap) tag.getValue());
default -> {
continue;
continue; // skip unsupported tag types
}
}
joiner.add("\"" + entry.getKey() + "\":\"" + tagValue + "\"");

View File

@@ -17,7 +17,22 @@
package net.momirealms.customcrops.api.core;
/**
* The WriteableRegistry interface extends the Registry interface, adding the capability
* to register new key-value pairs. This interface is used to define registries that
* allow modifications.
*
* @param <K> the type of the keys used for lookup
* @param <T> the type of the values stored in the registry
*/
public interface WriteableRegistry<K, T> extends Registry<K, T> {
/**
* Registers a new key-value pair in the registry.
* This method allows adding new entries to the registry dynamically.
*
* @param key the key associated with the value
* @param value the value to be registered
*/
void register(K key, T value);
}
}

View File

@@ -409,6 +409,9 @@ public class PotBlock extends AbstractCustomCropsBlock {
updateBlockAppearance(bukkitLocation, config, finalHasNaturalWater, fertilizers(state));
}, bukkitLocation);
}
ActionManager.trigger(Context.block(state)
.arg(ContextKeys.LOCATION, location.toLocation(bukkitWorld)), config.tickActions());
}
public int water(CustomCropsBlockState state) {

View File

@@ -249,10 +249,10 @@ public class SprinklerBlock extends AbstractCustomCropsBlock {
boolean updateState;
if (!config.infinite()) {
int water = water(state);
if (water <= 0) {
if (water < config.sprinklingAmount()) {
return;
}
updateState = water(state, config, water - 1);
updateState = water(state, config, water - config.sprinklingAmount());
} else {
updateState = false;
}
@@ -303,7 +303,7 @@ public class SprinklerBlock extends AbstractCustomCropsBlock {
if (anotherState.type() instanceof PotBlock potBlock) {
PotConfig potConfig = potBlock.config(anotherState);
if (config.potWhitelist().contains(potConfig.id())) {
if (potBlock.addWater(anotherState, potConfig, config.sprinklingAmount())) {
if (potBlock.addWater(anotherState, potConfig, config.wateringAmount())) {
BukkitCustomCropsPlugin.getInstance().getScheduler().sync().run(
() -> potBlock.updateBlockAppearance(
pos3.toLocation(world.bukkitWorld()),

View File

@@ -25,6 +25,9 @@ import org.bukkit.entity.Player;
import java.util.List;
/**
* Represents the configuration and behavior of bone meal in the crop mechanic.
*/
public class BoneMeal {
private final String item;
@@ -35,6 +38,18 @@ public class BoneMeal {
private final Action<Player>[] actions;
private final boolean dispenserAllowed;
/**
* Constructs a new BoneMeal instance with the specified properties.
*
* @param item The identifier for the item required to use this bone meal.
* @param requiredAmount The amount of the required item needed for applying bone meal.
* @param returned The identifier for the item returned after bone meal usage.
* @param returnedAmount The amount of the returned item given back after using bone meal.
* @param dispenserAllowed Whether this bone meal can be used by a dispenser.
* @param pointGainList A list of pairs representing the probability and the corresponding
* points to gain when bone meal is applied.
* @param actions An array of {@link Action} instances to trigger when bone meal is used.
*/
public BoneMeal(
String item,
int requiredAmount,
@@ -53,14 +68,30 @@ public class BoneMeal {
this.dispenserAllowed = dispenserAllowed;
}
/**
* Retrieves the identifier of the item required for using this bone meal.
*
* @return The required item identifier.
*/
public String requiredItem() {
return item;
}
/**
* Retrieves the identifier of the item returned after using this bone meal.
*
* @return The returned item identifier.
*/
public String returnedItem() {
return returned;
}
/**
* Randomly determines the points gained from applying the bone meal,
* based on the defined probability and point pairs.
*
* @return The points gained from applying the bone meal.
*/
public int rollPoint() {
for (Pair<Double, Integer> pair : pointGainList) {
if (Math.random() < pair.left()) {
@@ -70,18 +101,38 @@ public class BoneMeal {
return 0;
}
/**
* Triggers the associated actions when the bone meal is applied.
*
* @param context The context in which the actions are triggered.
*/
public void triggerActions(Context<Player> context) {
ActionManager.trigger(context, actions);
}
/**
* Retrieves the amount of the required item needed to use this bone meal.
*
* @return The required item amount.
*/
public int amountOfRequiredItem() {
return requiredAmount;
}
/**
* Retrieves the amount of the returned item after using this bone meal.
*
* @return The returned item amount.
*/
public int amountOfReturnItem() {
return returnedAmount;
}
/**
* Checks if this bone meal can be used by a dispenser.
*
* @return True if the bone meal is dispenser allowed; false otherwise.
*/
public boolean isDispenserAllowed() {
return dispenserAllowed;
}

View File

@@ -27,95 +27,333 @@ import java.util.Collection;
import java.util.Map;
import java.util.Set;
/**
* Represents the configuration settings for a crop in the CustomCrops plugin.
*/
public interface CropConfig {
/**
* Gets the unique identifier for this crop configuration.
*
* @return The unique ID of the crop as a {@link String}.
*/
String id();
/**
* Gets the seed item ID associated with this crop.
*
* @return The seed item ID as a {@link String}.
*/
String seed();
/**
* Gets the maximum growth points for this crop.
*
* @return The maximum points as an integer.
*/
int maxPoints();
/**
* Retrieves the requirements that must be met to plant this crop.
*
* @return An array of {@link Requirement} objects for planting the crop.
*/
Requirement<Player>[] plantRequirements();
/**
* Retrieves the requirements that must be met to break this crop.
*
* @return An array of {@link Requirement} objects for breaking the crop.
*/
Requirement<Player>[] breakRequirements();
/**
* Retrieves the requirements that must be met to interact with this crop.
*
* @return An array of {@link Requirement} objects for interacting with the crop.
*/
Requirement<Player>[] interactRequirements();
/**
* Retrieves the growth conditions that must be met for this crop to grow.
*
* @return An array of {@link GrowCondition} objects for crop growth.
*/
GrowCondition[] growConditions();
/**
* Retrieves the actions to be performed when the crop is placed in the wrong pot.
*
* @return An array of {@link Action} objects for wrong pot usage.
*/
Action<Player>[] wrongPotActions();
/**
* Retrieves the actions to be performed when interacting with the crop.
*
* @return An array of {@link Action} objects for crop interaction.
*/
Action<Player>[] interactActions();
/**
* Retrieves the actions to be performed when breaking the crop.
*
* @return An array of {@link Action} objects for breaking the crop.
*/
Action<Player>[] breakActions();
/**
* Retrieves the actions to be performed when planting the crop.
*
* @return An array of {@link Action} objects for planting the crop.
*/
Action<Player>[] plantActions();
/**
* Retrieves the actions to be performed when the crop reaches its growth limit.
*
* @return An array of {@link Action} objects for reaching the growth limit.
*/
Action<Player>[] reachLimitActions();
/**
* Retrieves the actions to be performed when the crop dies.
*
* @return An array of {@link Action} objects for crop death.
*/
Action<CustomCropsBlockState>[] deathActions();
/**
* Retrieves the conditions that determine when the crop dies.
*
* @return An array of {@link DeathCondition} objects for crop death.
*/
DeathCondition[] deathConditions();
/**
* Retrieves the bone meal effects that can be applied to this crop.
*
* @return An array of {@link BoneMeal} objects representing bone meal effects.
*/
BoneMeal[] boneMeals();
/**
* Indicates whether the crop should consider rotation during placement.
*
* @return True if rotation is considered, false otherwise.
*/
boolean rotation();
/**
* Gets the set of pot IDs that this crop is allowed to be planted in.
*
* @return A set of pot IDs as {@link String} objects.
*/
Set<String> potWhitelist();
/**
* Gets the crop stage configuration based on the growth point value.
*
* @param point The growth points to check.
* @return The {@link CropStageConfig} corresponding to the provided point.
*/
CropStageConfig stageByPoint(int point);
/**
* Gets the crop stage configuration based on a stage model identifier.
*
* @param stageModel The stage model identifier.
* @return The {@link CropStageConfig} corresponding to the provided model ID, or null if not found.
*/
@Nullable
CropStageConfig stageByID(String stageModel);
/**
* Gets the crop stage configuration with a model based on the growth point value.
*
* @param point The growth points to check.
* @return The {@link CropStageConfig} with a model corresponding to the provided point.
*/
CropStageConfig stageWithModelByPoint(int point);
/**
* Retrieves all the crop stage configurations for this crop.
*
* @return A collection of {@link CropStageConfig} objects representing all stages.
*/
Collection<CropStageConfig> stages();
/**
* Retrieves all the crop stage IDs for this crop.
*
* @return A collection of stage IDs as {@link String} objects.
*/
Collection<String> stageIDs();
/**
* Gets the closest lower or equal stage configuration based on the provided growth points.
*
* @param previousPoint The growth points to check.
* @return A {@link Map.Entry} containing the point and corresponding {@link CropStageConfig}.
*/
Map.Entry<Integer, CropStageConfig> getFloorStageEntry(int previousPoint);
/**
* Creates a new builder instance for constructing a {@link CropConfig}.
*
* @return A new {@link Builder} instance.
*/
static Builder builder() {
return new CropConfigImpl.BuilderImpl();
}
/**
* Builder interface for constructing instances of {@link CropConfig}.
*/
interface Builder {
/**
* Builds a new {@link CropConfig} instance with the specified settings.
*
* @return A new {@link CropConfig} instance.
*/
CropConfig build();
/**
* Sets the unique identifier for this crop configuration.
*
* @param id The unique ID of the crop.
* @return The builder instance for chaining.
*/
Builder id(String id);
/**
* Sets the seed item ID associated with this crop.
*
* @param seed The seed item ID.
* @return The builder instance for chaining.
*/
Builder seed(String seed);
/**
* Sets the maximum growth points for this crop.
*
* @param maxPoints The maximum points the crop can have.
* @return The builder instance for chaining.
*/
Builder maxPoints(int maxPoints);
/**
* Sets the actions to be performed when the crop is placed in the wrong pot.
*
* @param wrongPotActions An array of {@link Action} objects for wrong pot usage.
* @return The builder instance for chaining.
*/
Builder wrongPotActions(Action<Player>[] wrongPotActions);
/**
* Sets the actions to be performed when interacting with the crop.
*
* @param interactActions An array of {@link Action} objects for crop interaction.
* @return The builder instance for chaining.
*/
Builder interactActions(Action<Player>[] interactActions);
/**
* Sets the actions to be performed when breaking the crop.
*
* @param breakActions An array of {@link Action} objects for breaking the crop.
* @return The builder instance for chaining.
*/
Builder breakActions(Action<Player>[] breakActions);
/**
* Sets the actions to be performed when planting the crop.
*
* @param plantActions An array of {@link Action} objects for planting the crop.
* @return The builder instance for chaining.
*/
Builder plantActions(Action<Player>[] plantActions);
/**
* Sets the actions to be performed when the crop reaches its growth limit.
*
* @param reachLimitActions An array of {@link Action} objects for reaching the growth limit.
* @return The builder instance for chaining.
*/
Builder reachLimitActions(Action<Player>[] reachLimitActions);
/**
* Sets the requirements that must be met to plant this crop.
*
* @param plantRequirements An array of {@link Requirement} objects for planting the crop.
* @return The builder instance for chaining.
*/
Builder plantRequirements(Requirement<Player>[] plantRequirements);
/**
* Sets the requirements that must be met to break this crop.
*
* @param breakRequirements An array of {@link Requirement} objects for breaking the crop.
* @return The builder instance for chaining.
*/
Builder breakRequirements(Requirement<Player>[] breakRequirements);
/**
* Sets the requirements that must be met to interact with this crop.
*
* @param interactRequirements An array of {@link Requirement} objects for interacting with the crop.
* @return The builder instance for chaining.
*/
Builder interactRequirements(Requirement<Player>[] interactRequirements);
/**
* Sets the growth conditions that must be met for this crop to grow.
*
* @param growConditions An array of {@link GrowCondition} objects for crop growth.
* @return The builder instance for chaining.
*/
Builder growConditions(GrowCondition[] growConditions);
/**
* Sets the conditions that determine when the crop dies.
*
* @param deathConditions An array of {@link DeathCondition} objects for crop death.
* @return The builder instance for chaining.
*/
Builder deathConditions(DeathCondition[] deathConditions);
/**
* Sets the bone meal effects that can be applied to this crop.
*
* @param boneMeals An array of {@link BoneMeal} objects representing bone meal effects.
* @return The builder instance for chaining.
*/
Builder boneMeals(BoneMeal[] boneMeals);
/**
* Sets whether the crop should consider rotation during placement.
*
* @param rotation True if rotation is considered, false otherwise.
* @return The builder instance for chaining.
*/
Builder rotation(boolean rotation);
/**
* Sets the pot whitelist for this crop.
* Only pots in this list will be allowed to plant the crop.
*
* @param whitelist A set of pot IDs that are allowed to plant this crop.
* @return The builder instance for chaining.
*/
Builder potWhitelist(Set<String> whitelist);
/**
* Sets the stages of the crop based on growth points.
*
* @param stages A collection of {@link CropStageConfig.Builder} objects representing crop stages.
* @return The builder instance for chaining.
*/
Builder stages(Collection<CropStageConfig.Builder> stages);
}
}

View File

@@ -24,55 +24,183 @@ import net.momirealms.customcrops.api.requirement.Requirement;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.Nullable;
/**
* Interface representing the configuration of a specific stage of crop growth.
*/
public interface CropStageConfig {
/**
* Gets the parent {@link CropConfig} associated with this crop stage.
*
* @return The parent crop configuration.
*/
CropConfig crop();
/**
* Gets the offset for displaying crop information.
* This offset is used to adjust the display of information related to the crop stage.
*
* @return The display information offset.
*/
double displayInfoOffset();
/**
* Gets the unique identifier for this crop stage.
*
* @return The stage ID, or null if not defined.
*/
@Nullable
String stageID();
/**
* Gets the growth point associated with this crop stage.
* This point represents the growth progress of the crop.
*
* @return The growth point.
*/
int point();
/**
* Gets the requirements that must be met to interact with the crop at this stage.
*
* @return An array of interaction requirements.
*/
Requirement<Player>[] interactRequirements();
/**
* Gets the requirements that must be met to break the crop at this stage.
*
* @return An array of break requirements.
*/
Requirement<Player>[] breakRequirements();
/**
* Gets the actions to be performed when interacting with the crop at this stage.
*
* @return An array of interaction actions.
*/
Action<Player>[] interactActions();
/**
* Gets the actions to be performed when breaking the crop at this stage.
*
* @return An array of break actions.
*/
Action<Player>[] breakActions();
/**
* Gets the actions to be performed when the crop grows to this stage.
*
* @return An array of grow actions.
*/
Action<CustomCropsBlockState>[] growActions();
/**
* Gets the form of existence that this crop stage takes.
*
* @return The {@link ExistenceForm} of the crop stage.
*/
ExistenceForm existenceForm();
/**
* Creates a new builder for constructing instances of {@link CropStageConfig}.
*
* @return A new {@link Builder} instance.
*/
static Builder builder() {
return new CropStageConfigImpl.BuilderImpl();
}
/**
* Builder interface for constructing instances of {@link CropStageConfig}.
*/
interface Builder {
/**
* Builds a new {@link CropStageConfig} instance with the specified settings.
*
* @return A new {@link CropStageConfig} instance.
*/
CropStageConfig build();
/**
* Sets the parent crop configuration for this crop stage.
*
* @param crop The parent {@link CropConfig}.
* @return The builder instance for chaining.
*/
Builder crop(CropConfig crop);
/**
* Sets the display information offset for this crop stage.
*
* @param offset The display info offset.
* @return The builder instance for chaining.
*/
Builder displayInfoOffset(double offset);
/**
* Sets the unique identifier for this crop stage.
*
* @param id The stage ID.
* @return The builder instance for chaining.
*/
Builder stageID(String id);
/**
* Sets the growth point associated with this crop stage.
*
* @param i The growth point.
* @return The builder instance for chaining.
*/
Builder point(int i);
/**
* Sets the interaction requirements for this crop stage.
*
* @param requirements An array of interaction requirements.
* @return The builder instance for chaining.
*/
Builder interactRequirements(Requirement<Player>[] requirements);
/**
* Sets the break requirements for this crop stage.
*
* @param requirements An array of break requirements.
* @return The builder instance for chaining.
*/
Builder breakRequirements(Requirement<Player>[] requirements);
/**
* Sets the interaction actions for this crop stage.
*
* @param actions An array of interaction actions.
* @return The builder instance for chaining.
*/
Builder interactActions(Action<Player>[] actions);
/**
* Sets the break actions for this crop stage.
*
* @param actions An array of break actions.
* @return The builder instance for chaining.
*/
Builder breakActions(Action<Player>[] actions);
/**
* Sets the grow actions for this crop stage.
*
* @param actions An array of grow actions.
* @return The builder instance for chaining.
*/
Builder growActions(Action<CustomCropsBlockState>[] actions);
/**
* Sets the existence form of the crop for this crop stage.
*
* @param existenceForm The {@link ExistenceForm} of the crop.
* @return The builder instance for chaining.
*/
Builder existenceForm(ExistenceForm existenceForm);
}
}

View File

@@ -24,6 +24,10 @@ import net.momirealms.customcrops.api.requirement.Requirement;
import net.momirealms.customcrops.api.requirement.RequirementManager;
import org.jetbrains.annotations.Nullable;
/**
* Represents a condition that determines whether a crop will die.
*/
public class DeathCondition {
private final Requirement<CustomCropsBlockState>[] requirements;
@@ -31,6 +35,14 @@ public class DeathCondition {
private final ExistenceForm existenceForm;
private final int deathDelay;
/**
* Constructs a new DeathCondition with the specified requirements, death stage, existence form, and death delay.
*
* @param requirements The array of {@link Requirement} instances that must be met for the crop to die.
* @param deathStage The stage ID to transition to when the crop dies. Can be null if there is no specific death stage.
* @param existenceForm The {@link ExistenceForm} representing the state of the crop after death.
* @param deathDelay The delay in ticks before the crop transitions to the death stage after the condition is met.
*/
public DeathCondition(Requirement<CustomCropsBlockState>[] requirements, String deathStage, ExistenceForm existenceForm, int deathDelay) {
this.requirements = requirements;
this.deathStage = deathStage;
@@ -38,20 +50,43 @@ public class DeathCondition {
this.deathDelay = deathDelay;
}
/**
* Retrieves the stage ID to transition to upon death.
*
* @return The stage ID for the death state, or null if there is no specific death stage.
*/
@Nullable
public String deathStage() {
return deathStage;
}
/**
* Retrieves the delay in ticks before transitioning to the death stage.
*
* @return The delay before the crop dies, in ticks.
*/
public int deathDelay() {
return deathDelay;
}
/**
* Checks if the death condition is met in the given context.
* This method evaluates all the requirements associated with this condition to determine
* whether the crop should die.
*
* @param context The {@link Context} in which the requirements are evaluated.
* @return True if all requirements are satisfied; false otherwise.
*/
public boolean isMet(Context<CustomCropsBlockState> context) {
return RequirementManager.isSatisfied(context, requirements);
}
/**
* Retrieves the existence form that the crop should take after it dies.
*
* @return The {@link ExistenceForm} representing the state of the crop after death.
*/
public ExistenceForm existenceForm() {
return existenceForm;
}
}
}

View File

@@ -22,21 +22,45 @@ import net.momirealms.customcrops.api.core.world.CustomCropsBlockState;
import net.momirealms.customcrops.api.requirement.Requirement;
import net.momirealms.customcrops.api.requirement.RequirementManager;
/**
* Represents a condition for a crop to grow to the next stage.
* The growth condition specifies the requirements that must be met for the crop to progress,
* as well as the number of points to be added to the crop's growth when the condition is met.
*/
public class GrowCondition {
private final Requirement<CustomCropsBlockState>[] requirements;
private final int pointToAdd;
/**
* Constructs a new GrowCondition with the specified requirements and growth points.
*
* @param requirements The array of {@link Requirement} instances that must be met for the crop to grow.
* @param pointToAdd The number of points to be added to the crop's growth when the condition is satisfied.
*/
public GrowCondition(Requirement<CustomCropsBlockState>[] requirements, int pointToAdd) {
this.requirements = requirements;
this.pointToAdd = pointToAdd;
}
/**
* Retrieves the number of growth points to be added when this condition is met.
*
* @return The number of points to add to the crop's growth.
*/
public int pointToAdd() {
return pointToAdd;
}
/**
* Checks if the growth condition is met in the given context.
* This method evaluates all the requirements associated with this condition to determine
* whether the crop can grow.
*
* @param context The {@link Context} in which the requirements are evaluated.
* @return True if all requirements are satisfied; false otherwise.
*/
public boolean isMet(Context<CustomCropsBlockState> context) {
return RequirementManager.isSatisfied(context, requirements);
}
}
}

View File

@@ -19,26 +19,51 @@ package net.momirealms.customcrops.api.core.mechanic.crop;
import net.momirealms.customcrops.api.core.ExistenceForm;
/**
* Represents the data associated with a crop variation.
*/
public class VariationData {
private final String id;
private final ExistenceForm form;
private final double chance;
/**
* Constructs a new VariationData with the specified ID, existence form, and chance.
*
* @param id The unique identifier for the crop variation.
* @param form The {@link ExistenceForm} representing the state or form of the crop variation.
* @param chance The probability (as a decimal between 0 and 1) of this variation occurring.
*/
public VariationData(String id, ExistenceForm form, double chance) {
this.id = id;
this.form = form;
this.chance = chance;
}
/**
* Retrieves the unique identifier for this crop variation.
*
* @return The unique ID of the variation.
*/
public String id() {
return id;
}
/**
* Retrieves the existence form of this crop variation.
*
* @return The {@link ExistenceForm} representing the state or form of the variation.
*/
public ExistenceForm existenceForm() {
return form;
}
/**
* Retrieves the chance of this crop variation occurring.
*
* @return The probability of the variation occurring, as a decimal between 0 and 1.
*/
public double chance() {
return chance;
}

View File

@@ -20,15 +20,40 @@ package net.momirealms.customcrops.api.core.mechanic.fertilizer;
import net.momirealms.customcrops.api.core.Registries;
import org.jetbrains.annotations.Nullable;
/**
* Represents a fertilizer used in the CustomCrops plugin.
*/
public interface Fertilizer {
/**
* Gets the unique identifier of the fertilizer.
*
* @return The fertilizer ID as a {@link String}.
*/
String id();
/**
* Gets the remaining number of times this fertilizer can be used.
*
* @return The number of remaining usages.
*/
int times();
/**
* Reduces the usage times of the fertilizer by one.
* If the number of usages reaches zero or below, it indicates the fertilizer is exhausted.
*
* @return True if the fertilizer is exhausted (no more usages left), false otherwise.
*/
boolean reduceTimes();
// Flexibility matters more than performance
/**
* Retrieves the type of the fertilizer.
* This method provides flexibility in determining the type by querying the fertilizer registry.
* It may incur a slight performance cost due to registry lookup.
*
* @return The {@link FertilizerType} of this fertilizer. Returns {@link FertilizerType#INVALID} if the type is not found.
*/
default FertilizerType type() {
FertilizerConfig config = Registries.FERTILIZER.get(id());
if (config == null) {
@@ -37,21 +62,52 @@ public interface Fertilizer {
return config.type();
}
/**
* Retrieves the configuration of the fertilizer from the registry.
* This method allows access to additional properties and settings of the fertilizer.
*
* @return The {@link FertilizerConfig} associated with this fertilizer, or null if not found.
*/
@Nullable
default FertilizerConfig config() {
return Registries.FERTILIZER.get(id());
}
/**
* Creates a new builder instance for constructing a {@link Fertilizer}.
*
* @return A new {@link Builder} instance.
*/
static Builder builder() {
return new FertilizerImpl.BuilderImpl();
}
/**
* Builder interface for constructing instances of {@link Fertilizer}.
*/
interface Builder {
/**
* Builds a new {@link Fertilizer} instance with the specified settings.
*
* @return A new {@link Fertilizer} instance.
*/
Fertilizer build();
/**
* Sets the unique identifier for the fertilizer.
*
* @param id The unique ID for the fertilizer.
* @return The current instance of the Builder.
*/
Builder id(String id);
/**
* Sets the number of times the fertilizer can be used.
*
* @param times The number of usages for the fertilizer.
* @return The current instance of the Builder.
*/
Builder times(int times);
}
}
}

View File

@@ -24,38 +24,126 @@ import org.jetbrains.annotations.Nullable;
import java.util.Set;
/**
* Represents the configuration settings for a fertilizer in the CustomCrops plugin.
*/
public interface FertilizerConfig {
/**
* Gets the unique identifier for this fertilizer configuration.
*
* @return The unique ID of the fertilizer as a {@link String}.
*/
String id();
/**
* Gets the type of the fertilizer.
*
* @return The {@link FertilizerType} of this fertilizer.
*/
FertilizerType type();
/**
* Determines whether the fertilizer should be used before planting crops.
*
* @return True if the fertilizer is applied before planting, false otherwise.
*/
boolean beforePlant();
/**
* Gets the icon representation for this fertilizer.
*
* @return The icon as a {@link String}, typically an item or block ID.
*/
String icon();
/**
* Retrieves the requirements for using this fertilizer.
*
* @return An array of {@link Requirement} objects that must be met to use the fertilizer.
*/
Requirement<Player>[] requirements();
/**
* Gets the item ID associated with this fertilizer.
*
* @return The item ID as a {@link String}.
*/
String itemID();
/**
* Gets the number of times this fertilizer can be used.
*
* @return The number of usages available.
*/
int times();
/**
* Gets the set of pot IDs that this fertilizer is allowed to be used with.
*
* @return A set of pot IDs as {@link String} objects.
*/
Set<String> whitelistPots();
/**
* Retrieves the actions to be performed before planting when using this fertilizer.
*
* @return An array of {@link Action} objects representing the actions to perform.
*/
Action<Player>[] beforePlantActions();
/**
* Retrieves the actions to be performed when the fertilizer is used.
*
* @return An array of {@link Action} objects representing the actions to perform upon use.
*/
Action<Player>[] useActions();
/**
* Retrieves the actions to be performed when the fertilizer is used on the wrong type of pot.
*
* @return An array of {@link Action} objects representing the actions to perform for wrong pot usage.
*/
Action<Player>[] wrongPotActions();
/**
* Processes and potentially modifies the gain points based on this fertilizer's effects.
*
* @param previousPoints The points before processing.
* @return The modified points after applying the fertilizer's effect.
*/
int processGainPoints(int previousPoints);
/**
* Processes and potentially modifies the amount of water to lose when this fertilizer is used.
*
* @param waterToLose The amount of water to lose before processing.
* @return The modified water loss amount after applying the fertilizer's effect.
*/
int processWaterToLose(int waterToLose);
/**
* Processes and potentially modifies the variation chance for crop growth based on this fertilizer's effects.
*
* @param previousChance The variation chance before processing.
* @return The modified variation chance after applying the fertilizer's effect.
*/
double processVariationChance(double previousChance);
/**
* Processes and potentially modifies the amount of items dropped when the crop is harvested.
*
* @param amount The amount of items to drop before processing.
* @return The modified drop amount after applying the fertilizer's effect.
*/
int processDroppedItemAmount(int amount);
/**
* Provides an optional override for the quality ratio of crops affected by this fertilizer.
* This method may return null if there is no override.
*
* @return An array of doubles representing the quality ratio override, or null if not applicable.
*/
@Nullable
double[] overrideQualityRatio();
}
}

View File

@@ -29,96 +29,340 @@ import org.bukkit.entity.Player;
import java.util.HashMap;
import java.util.Set;
/**
* Represents the configuration settings for a pot in the CustomCrops plugin.
*/
public interface PotConfig {
/**
* Gets the unique identifier for this pot configuration.
*
* @return The ID of the pot configuration.
*/
String id();
/**
* Gets the maximum water storage capacity of the pot.
*
* @return The water storage capacity.
*/
int storage();
/**
* Checks if the pot can accept rain as a source of water.
*
* @return True if rain is accepted, false otherwise.
*/
boolean isRainDropAccepted();
/**
* Checks if the pot can accept water from nearby water sources.
*
* @return True if nearby water is accepted, false otherwise.
*/
boolean isNearbyWaterAccepted();
/**
* Gets the methods available for watering the pot.
*
* @return An array of {@link WateringMethod} instances.
*/
WateringMethod[] wateringMethods();
/**
* Gets the set of block IDs associated with this pot.
*
* @return A set of block IDs.
*/
Set<String> blocks();
/**
* Checks if a specific block ID is considered wet.
*
* @param blockID The block ID to check.
* @return True if the block is wet, false otherwise.
*/
boolean isWet(String blockID);
/**
* Gets the water bar that manages the pot's water level.
*
* @return The {@link WaterBar} instance.
*/
WaterBar waterBar();
/**
* Gets the maximum number of fertilizers that can be added to the pot.
*
* @return The maximum number of fertilizers.
*/
int maxFertilizers();
/**
* Gets the appearance of the pot based on its water state and fertilizer type.
*
* @param watered Whether the pot is watered.
* @param type The fertilizer type.
* @return The appearance ID of the pot.
*/
String getPotAppearance(boolean watered, FertilizerType type);
/**
* Gets the requirements that must be met to place the pot.
*
* @return An array of {@link Requirement} instances for placement.
*/
Requirement<Player>[] placeRequirements();
/**
* Gets the requirements that must be met to break the pot.
*
* @return An array of {@link Requirement} instances for breaking.
*/
Requirement<Player>[] breakRequirements();
/**
* Gets the requirements that must be met to use the pot.
*
* @return An array of {@link Requirement} instances for usage.
*/
Requirement<Player>[] useRequirements();
/**
* Gets the actions performed during each tick of the pot.
*
* @return An array of tick {@link Action} instances.
*/
Action<CustomCropsBlockState>[] tickActions();
/**
* Gets the actions performed when the pot reaches its limit.
*
* @return An array of reach limit {@link Action} instances.
*/
Action<Player>[] reachLimitActions();
/**
* Gets the actions performed when the pot is interacted with.
*
* @return An array of interact {@link Action} instances.
*/
Action<Player>[] interactActions();
/**
* Gets the actions performed when the pot is placed.
*
* @return An array of place {@link Action} instances.
*/
Action<Player>[] placeActions();
/**
* Gets the actions performed when the pot is broken.
*
* @return An array of break {@link Action} instances.
*/
Action<Player>[] breakActions();
/**
* Gets the actions performed when water is added to the pot.
*
* @return An array of add water {@link Action} instances.
*/
Action<Player>[] addWaterActions();
/**
* Gets the actions performed when the pot is full of water.
*
* @return An array of full water {@link Action} instances.
*/
Action<Player>[] fullWaterActions();
/**
* Gets the actions performed when the pot reaches its maximum fertilizer capacity.
*
* @return An array of max fertilizer {@link Action} instances.
*/
Action<Player>[] maxFertilizerActions();
/**
* Creates a new builder instance for constructing a {@link PotConfig}.
*
* @return A new {@link Builder} instance.
*/
static Builder builder() {
return new PotConfigImpl.BuilderImpl();
}
/**
* Builder interface for constructing instances of {@link PotConfig}.
*/
interface Builder {
/**
* Builds a new {@link PotConfig} instance with the specified settings.
*
* @return A new {@link PotConfig} instance.
*/
PotConfig build();
/**
* Sets the unique identifier for the pot configuration.
*
* @param id The unique ID for the pot.
* @return The current instance of the Builder.
*/
Builder id(String id);
/**
* Sets the maximum water storage capacity of the pot.
*
* @param storage The maximum amount of water the pot can store.
* @return The current instance of the Builder.
*/
Builder storage(int storage);
/**
* Sets whether the pot can accept rain as a source of water.
*
* @param isRainDropAccepted True if rain is accepted, false otherwise.
* @return The current instance of the Builder.
*/
Builder isRainDropAccepted(boolean isRainDropAccepted);
/**
* Sets whether the pot can accept water from nearby water sources.
*
* @param isNearbyWaterAccepted True if nearby water is accepted, false otherwise.
* @return The current instance of the Builder.
*/
Builder isNearbyWaterAccepted(boolean isNearbyWaterAccepted);
/**
* Sets the methods available for watering the pot.
*
* @param wateringMethods An array of {@link WateringMethod} instances.
* @return The current instance of the Builder.
*/
Builder wateringMethods(WateringMethod[] wateringMethods);
/**
* Sets the water bar that indicates the pot's current water level.
*
* @param waterBar The {@link WaterBar} instance.
* @return The current instance of the Builder.
*/
Builder waterBar(WaterBar waterBar);
/**
* Sets the maximum number of fertilizers that can be added to the pot.
*
* @param maxFertilizers The maximum number of fertilizers.
* @return The current instance of the Builder.
*/
Builder maxFertilizers(int maxFertilizers);
/**
* Sets the requirements that must be met to place the pot.
*
* @param requirements An array of {@link Requirement} instances.
* @return The current instance of the Builder.
*/
Builder placeRequirements(Requirement<Player>[] requirements);
/**
* Sets the requirements that must be met to break the pot.
*
* @param requirements An array of {@link Requirement} instances.
* @return The current instance of the Builder.
*/
Builder breakRequirements(Requirement<Player>[] requirements);
/**
* Sets the requirements that must be met to use the pot.
*
* @param requirements An array of {@link Requirement} instances.
* @return The current instance of the Builder.
*/
Builder useRequirements(Requirement<Player>[] requirements);
/**
* Sets the actions performed during each tick of the pot.
*
* @param tickActions An array of tick {@link Action} instances.
* @return The current instance of the Builder.
*/
Builder tickActions(Action<CustomCropsBlockState>[] tickActions);
/**
* Sets the actions performed when the pot reaches its limit.
*
* @param reachLimitActions An array of reach limit {@link Action} instances.
* @return The current instance of the Builder.
*/
Builder reachLimitActions(Action<Player>[] reachLimitActions);
/**
* Sets the actions performed when the pot is interacted with.
*
* @param interactActions An array of interact {@link Action} instances.
* @return The current instance of the Builder.
*/
Builder interactActions(Action<Player>[] interactActions);
/**
* Sets the actions performed when the pot is placed.
*
* @param placeActions An array of place {@link Action} instances.
* @return The current instance of the Builder.
*/
Builder placeActions(Action<Player>[] placeActions);
/**
* Sets the actions performed when the pot is broken.
*
* @param breakActions An array of break {@link Action} instances.
* @return The current instance of the Builder.
*/
Builder breakActions(Action<Player>[] breakActions);
/**
* Sets the actions performed when water is added to the pot.
*
* @param addWaterActions An array of add water {@link Action} instances.
* @return The current instance of the Builder.
*/
Builder addWaterActions(Action<Player>[] addWaterActions);
/**
* Sets the actions performed when the pot is full of water.
*
* @param fullWaterActions An array of full water {@link Action} instances.
* @return The current instance of the Builder.
*/
Builder fullWaterActions(Action<Player>[] fullWaterActions);
/**
* Sets the actions performed when the pot reaches its maximum fertilizer capacity.
*
* @param maxFertilizerActions An array of max fertilizer {@link Action} instances.
* @return The current instance of the Builder.
*/
Builder maxFertilizerActions(Action<Player>[] maxFertilizerActions);
/**
* Sets the basic appearance of the pot.
*
* @param basicAppearance A {@link Pair} representing the basic appearance of the pot.
* @return The current instance of the Builder.
*/
Builder basicAppearance(Pair<String, String> basicAppearance);
/**
* Sets the appearance map of the pot for different fertilizer types.
*
* @param potAppearanceMap A map of {@link FertilizerType} to {@link Pair} of appearance strings.
* @return The current instance of the Builder.
*/
Builder potAppearanceMap(HashMap<FertilizerType, Pair<String, String>> potAppearanceMap);
}
}

View File

@@ -14,7 +14,6 @@
* 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.core.mechanic.sprinkler;
import net.momirealms.customcrops.api.action.Action;
@@ -29,137 +28,400 @@ import org.jetbrains.annotations.Nullable;
import java.util.Set;
/**
* Represents the configuration settings for a sprinkler within the CustomCrops plugin.
*/
public interface SprinklerConfig {
/**
* Gets the unique identifier for this sprinkler configuration.
*
* @return The ID of the sprinkler configuration.
*/
String id();
/**
* Gets the maximum water storage capacity of the sprinkler.
*
* @return The water storage capacity.
*/
int storage();
/**
* Gets the range of the sprinkler's watering area.
*
* @return A 2D array representing the offsets of the target blocks.
*/
int[][] range();
/**
* Checks if the sprinkler has infinite water capacity.
*
* @return true if the sprinkler is infinite, false otherwise.
*/
boolean infinite();
/**
* Gets the amount of water the sprinkler adds to pot per operation.
*
* @return The sprinkling amount.
*/
int wateringAmount();
/**
* Gets the amount of water sprinkled per operation.
*
* @return The sprinkling amount.
*/
int sprinklingAmount();
/**
* Gets the 2D item representation of the sprinkler.
*
* @return The 2D item ID, or null if not applicable.
*/
@Nullable
String twoDItem();
/**
* Gets the 3D item representation of the sprinkler without water.
*
* @return The 3D item ID without water.
*/
@NotNull
String threeDItem();
/**
* Gets the 3D item representation of the sprinkler with water.
*
* @return The 3D item ID with water.
*/
@NotNull
String threeDItemWithWater();
/**
* Gets the whitelist of pots that the sprinkler can interact with.
*
* @return A set of pot IDs that are whitelisted.
*/
@NotNull
Set<String> potWhitelist();
/**
* Gets the model IDs associated with this sprinkler.
*
* @return A set of model IDs.
*/
@NotNull
Set<String> modelIDs();
/**
* Gets the water bar that manages the sprinkler's water level.
*
* @return The {@link WaterBar}, or null if not applicable.
*/
@Nullable
WaterBar waterBar();
/**
* Gets the existence form of the sprinkler, which indicates how it exists in the world.
*
* @return The {@link ExistenceForm} of the sprinkler.
*/
@NotNull
ExistenceForm existenceForm();
/**
* Get the requirements for placement
* Gets the placement requirements for the sprinkler.
*
* @return requirements for placement
* @return An array of placement {@link Requirement}s, or null if none.
*/
@Nullable
Requirement<Player>[] placeRequirements();
/**
* Get the requirements for breaking
* Gets the breaking requirements for the sprinkler.
*
* @return requirements for breaking
* @return An array of breaking {@link Requirement}s, or null if none.
*/
@Nullable
Requirement<Player>[] breakRequirements();
/**
* Get the requirements for using
* Gets the usage requirements for the sprinkler.
*
* @return requirements for using
* @return An array of usage {@link Requirement}s, or null if none.
*/
@Nullable
Requirement<Player>[] useRequirements();
/**
* Gets the actions performed when the sprinkler is working.
*
* @return An array of work {@link Action}s, or null if none.
*/
@Nullable
Action<CustomCropsBlockState>[] workActions();
/**
* Gets the actions performed when the sprinkler is interacted with.
*
* @return An array of interact {@link Action}s, or null if none.
*/
@Nullable
Action<Player>[] interactActions();
/**
* Gets the actions performed when the sprinkler is placed.
*
* @return An array of place {@link Action}s, or null if none.
*/
@Nullable
Action<Player>[] placeActions();
/**
* Gets the actions performed when the sprinkler is broken.
*
* @return An array of break {@link Action}s, or null if none.
*/
@Nullable
Action<Player>[] breakActions();
/**
* Gets the actions performed when water is added to the sprinkler.
*
* @return An array of add water {@link Action}s, or null if none.
*/
@Nullable
Action<Player>[] addWaterActions();
/**
* Gets the actions performed when the sprinkler reaches its water limit.
*
* @return An array of reach limit {@link Action}s, or null if none.
*/
@Nullable
Action<Player>[] reachLimitActions();
/**
* Gets the actions performed when the sprinkler's water level is full.
*
* @return An array of full water {@link Action}s, or null if none.
*/
@Nullable
Action<Player>[] fullWaterActions();
/**
* Gets the methods used for watering by the sprinkler.
*
* @return An array of {@link WateringMethod}s.
*/
@NotNull
WateringMethod[] wateringMethods();
/**
* Creates a new builder instance for constructing a {@link SprinklerConfig}.
*
* @return A new {@link Builder} instance.
*/
static Builder builder() {
return new SprinklerConfigImpl.BuilderImpl();
}
/**
* Builder interface for constructing instances of {@link SprinklerConfig}.
*/
interface Builder {
/**
* Builds a new {@link SprinklerConfig} instance with the specified settings.
*
* @return A new {@link SprinklerConfig} instance.
*/
SprinklerConfig build();
/**
* Sets the unique identifier for the sprinkler configuration.
*
* @param id The unique ID for the sprinkler.
* @return The current instance of the Builder.
*/
Builder id(String id);
/**
* Sets the existence form of the sprinkler, indicating its form in the world.
*
* @param existenceForm The existence form of the sprinkler.
* @return The current instance of the Builder.
*/
Builder existenceForm(ExistenceForm existenceForm);
/**
* Sets the water storage capacity of the sprinkler.
*
* @param storage The maximum water storage capacity.
* @return The current instance of the Builder.
*/
Builder storage(int storage);
/**
* Sets the range of the sprinkler's watering area.
*
* @param range A 2D array defining the range.
* @return The current instance of the Builder.
*/
Builder range(int[][] range);
/**
* Specifies whether the sprinkler has an infinite water supply.
*
* @param infinite true if the sprinkler has infinite water; false otherwise.
* @return The current instance of the Builder.
*/
Builder infinite(boolean infinite);
/**
* Sets the amount of water the sprinkler adds to pot per operation.
*
* @param wateringAmount The amount of water used per sprinkling.
* @return The current instance of the Builder.
*/
Builder wateringAmount(int wateringAmount);
/**
* Sets the amount of water the sprinkler uses per operation.
*
* @param sprinklingAmount The amount of water used per sprinkling.
* @return The current instance of the Builder.
*/
Builder sprinklingAmount(int sprinklingAmount);
/**
* Sets the whitelist of pot IDs that the sprinkler can interact with.
*
* @param potWhitelist A set of whitelisted pot IDs.
* @return The current instance of the Builder.
*/
Builder potWhitelist(Set<String> potWhitelist);
/**
* Sets the water bar that manages the sprinkler's water level.
*
* @param waterBar The {@link WaterBar} instance.
* @return The current instance of the Builder.
*/
Builder waterBar(WaterBar waterBar);
/**
* Sets the 2D item representation of the sprinkler.
*
* @param twoDItem The ID of the 2D item representation.
* @return The current instance of the Builder.
*/
Builder twoDItem(@Nullable String twoDItem);
/**
* Sets the 3D item representation of the sprinkler when it does not contain water.
*
* @param threeDItem The ID of the 3D item without water.
* @return The current instance of the Builder.
*/
Builder threeDItem(String threeDItem);
/**
* Sets the 3D item representation of the sprinkler when it contains water.
*
* @param threeDItemWithWater The ID of the 3D item with water.
* @return The current instance of the Builder.
*/
Builder threeDItemWithWater(String threeDItemWithWater);
/**
* Sets the requirements for placing the sprinkler.
*
* @param placeRequirements An array of {@link Requirement} instances for placement.
* @return The current instance of the Builder.
*/
Builder placeRequirements(Requirement<Player>[] placeRequirements);
/**
* Sets the requirements for breaking the sprinkler.
*
* @param breakRequirements An array of {@link Requirement} instances for breaking.
* @return The current instance of the Builder.
*/
Builder breakRequirements(Requirement<Player>[] breakRequirements);
/**
* Sets the requirements for using the sprinkler.
*
* @param useRequirements An array of {@link Requirement} instances for usage.
* @return The current instance of the Builder.
*/
Builder useRequirements(Requirement<Player>[] useRequirements);
/**
* Sets the actions to be performed when the sprinkler is working.
*
* @param workActions An array of {@link Action} instances for working.
* @return The current instance of the Builder.
*/
Builder workActions(Action<CustomCropsBlockState>[] workActions);
/**
* Sets the actions to be performed when the sprinkler is interacted with.
*
* @param interactActions An array of {@link Action} instances for interaction.
* @return The current instance of the Builder.
*/
Builder interactActions(Action<Player>[] interactActions);
/**
* Sets the actions to be performed when water is added to the sprinkler.
*
* @param addWaterActions An array of {@link Action} instances for adding water.
* @return The current instance of the Builder.
*/
Builder addWaterActions(Action<Player>[] addWaterActions);
/**
* Sets the actions to be performed when the sprinkler reaches its water limit.
*
* @param reachLimitActions An array of {@link Action} instances for reaching the limit.
* @return The current instance of the Builder.
*/
Builder reachLimitActions(Action<Player>[] reachLimitActions);
/**
* Sets the actions to be performed when the sprinkler is placed.
*
* @param placeActions An array of {@link Action} instances for placing.
* @return The current instance of the Builder.
*/
Builder placeActions(Action<Player>[] placeActions);
/**
* Sets the actions to be performed when the sprinkler is broken.
*
* @param breakActions An array of {@link Action} instances for breaking.
* @return The current instance of the Builder.
*/
Builder breakActions(Action<Player>[] breakActions);
/**
* Sets the actions to be performed when the sprinkler's water level is full.
*
* @param fullWaterActions An array of {@link Action} instances for full water.
* @return The current instance of the Builder.
*/
Builder fullWaterActions(Action<Player>[] fullWaterActions);
/**
* Sets the watering methods that the sprinkler can use.
*
* @param wateringMethods An array of {@link WateringMethod} instances.
* @return The current instance of the Builder.
*/
Builder wateringMethods(WateringMethod[] wateringMethods);
}
}

View File

@@ -36,6 +36,7 @@ public class SprinklerConfigImpl implements SprinklerConfig {
private final int storage;
private final int[][] range;
private final boolean infinite;
private final int wateringAmount;
private final int sprinklingAmount;
private final Set<String> potWhitelist;
private final WaterBar waterBar;
@@ -61,6 +62,7 @@ public class SprinklerConfigImpl implements SprinklerConfig {
int storage,
int[][] range,
boolean infinite,
int wateringAmount,
int sprinklingAmount,
Set<String> potWhitelist,
WaterBar waterBar,
@@ -84,6 +86,7 @@ public class SprinklerConfigImpl implements SprinklerConfig {
this.storage = storage;
this.range = range;
this.infinite = infinite;
this.wateringAmount = wateringAmount;
this.sprinklingAmount = sprinklingAmount;
this.potWhitelist = potWhitelist;
this.waterBar = waterBar;
@@ -126,6 +129,11 @@ public class SprinklerConfigImpl implements SprinklerConfig {
return infinite;
}
@Override
public int wateringAmount() {
return wateringAmount;
}
@Override
public int sprinklingAmount() {
return sprinklingAmount;
@@ -233,6 +241,7 @@ public class SprinklerConfigImpl implements SprinklerConfig {
private int storage;
private int[][] range;
private boolean infinite;
private int wateringAmount;
private int sprinklingAmount;
private Set<String> potWhitelist;
private WaterBar waterBar;
@@ -253,7 +262,7 @@ public class SprinklerConfigImpl implements SprinklerConfig {
@Override
public SprinklerConfig build() {
return new SprinklerConfigImpl(id, existenceForm, storage, range, infinite, sprinklingAmount, potWhitelist, waterBar, twoDItem, threeDItem, threeDItemWithWater,
return new SprinklerConfigImpl(id, existenceForm, storage, range, infinite, wateringAmount, sprinklingAmount, potWhitelist, waterBar, twoDItem, threeDItem, threeDItemWithWater,
placeRequirements, breakRequirements, useRequirements, workActions, interactActions, reachLimitActions, addWaterActions, placeActions, breakActions, fullWaterActions, wateringMethods);
}
@@ -287,6 +296,12 @@ public class SprinklerConfigImpl implements SprinklerConfig {
return this;
}
@Override
public Builder wateringAmount(int wateringAmount) {
this.wateringAmount = wateringAmount;
return this;
}
@Override
public Builder sprinklingAmount(int sprinklingAmount) {
this.sprinklingAmount = sprinklingAmount;

View File

@@ -28,98 +28,345 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Represents the configuration settings for a watering can in the CustomCrops plugin
*/
public interface WateringCanConfig {
/**
* Gets the unique identifier for this watering can configuration.
*
* @return The ID of the watering can configuration.
*/
String id();
/**
* Gets the item ID representing the watering can.
*
* @return The item ID.
*/
String itemID();
/**
* Gets the width of the watering area.
*
* @return The width of the watering area.
*/
int width();
/**
* Gets the length of the watering area.
*
* @return The length of the watering area.
*/
int length();
/**
* Gets the maximum water storage capacity of the watering can.
*
* @return The water storage capacity.
*/
int storage();
/**
* Gets the amount of water added to pots per watering action.
*
* @return The watering amount.
*/
int wateringAmount();
/**
* Determines if the lore (description text) of the watering can is dynamic.
*
* @return true if the lore is dynamic, false otherwise.
*/
boolean dynamicLore();
/**
* Gets the set of pot IDs that the watering can is whitelisted to interact with.
*
* @return A set of whitelisted pot IDs.
*/
Set<String> whitelistPots();
/**
* Gets the set of sprinkler IDs that the watering can is whitelisted to interact with.
*
* @return A set of whitelisted sprinkler IDs.
*/
Set<String> whitelistSprinklers();
/**
* Gets the lore (description text) of the watering can.
*
* @return A list of {@link TextValue} objects representing the lore.
*/
List<TextValue<Player>> lore();
/**
* Gets the water bar that manages the watering can's water level.
*
* @return The {@link WaterBar} instance.
*/
WaterBar waterBar();
/**
* Gets the requirements for using the watering can.
*
* @return An array of {@link Requirement} instances for usage.
*/
Requirement<Player>[] requirements();
/**
* Checks if the watering can has infinite water capacity.
*
* @return true if the watering can is infinite, false otherwise.
*/
boolean infinite();
/**
* Gets the appearance of the watering can based on its water level.
*
* @param water The current water level.
* @return The appearance value corresponding to the water level.
*/
Integer appearance(int water);
/**
* Gets the actions performed when the watering can is full.
*
* @return An array of full {@link Action}s.
*/
Action<Player>[] fullActions();
/**
* Gets the actions performed when water is added to the watering can.
*
* @return An array of add water {@link Action}s.
*/
Action<Player>[] addWaterActions();
/**
* Gets the actions performed when water is consumed from the watering can.
*
* @return An array of consume water {@link Action}s.
*/
Action<Player>[] consumeWaterActions();
/**
* Gets the actions performed when the watering can runs out of water.
*
* @return An array of run out of water {@link Action}s.
*/
Action<Player>[] runOutOfWaterActions();
/**
* Gets the actions performed when the watering can is used on a wrong pot.
*
* @return An array of wrong pot {@link Action}s.
*/
Action<Player>[] wrongPotActions();
/**
* Gets the actions performed when the watering can is used on a wrong sprinkler.
*
* @return An array of wrong sprinkler {@link Action}s.
*/
Action<Player>[] wrongSprinklerActions();
/**
* Gets the methods available for filling the watering can with water.
*
* @return An array of {@link FillMethod}s.
*/
FillMethod[] fillMethods();
/**
* Creates a new builder instance for constructing a {@link WateringCanConfig}.
*
* @return A new {@link Builder} instance.
*/
static Builder builder() {
return new WateringCanConfigImpl.BuilderImpl();
}
/**
* Builder interface for constructing instances of {@link WateringCanConfig}
*/
interface Builder {
/**
* Builds a new {@link WateringCanConfig} instance with the specified settings.
*
* @return A new {@link WateringCanConfig} instance.
*/
WateringCanConfig build();
/**
* Sets the unique identifier for the watering can configuration.
*
* @param id The unique ID for the watering can.
* @return The current instance of the Builder.
*/
Builder id(String id);
/**
* Sets the item ID representing the watering can.
*
* @param itemID The item ID.
* @return The current instance of the Builder.
*/
Builder itemID(String itemID);
/**
* Sets the width of the watering area for the watering can.
*
* @param width The width of the watering area.
* @return The current instance of the Builder.
*/
Builder width(int width);
/**
* Sets the length of the watering area for the watering can.
*
* @param length The length of the watering area.
* @return The current instance of the Builder.
*/
Builder length(int length);
/**
* Sets the maximum water storage capacity of the watering can.
*
* @param storage The maximum amount of water the watering can can store.
* @return The current instance of the Builder.
*/
Builder storage(int storage);
/**
* Sets the amount of water added to pots per watering action.
*
* @param wateringAmount The amount of water consumed per use.
* @return The current instance of the Builder.
*/
Builder wateringAmount(int wateringAmount);
/**
* Sets whether the lore (description text) of the watering can is dynamic.
*
* @param dynamicLore True if the lore is dynamic, false otherwise.
* @return The current instance of the Builder.
*/
Builder dynamicLore(boolean dynamicLore);
/**
* Sets the whitelist of pot IDs that the watering can can interact with.
*
* @param whitelistPots A set of pot IDs that the watering can is allowed to interact with.
* @return The current instance of the Builder.
*/
Builder potWhitelist(Set<String> whitelistPots);
/**
* Sets the whitelist of sprinkler IDs that the watering can can interact with.
*
* @param whitelistSprinklers A set of sprinkler IDs that the watering can is allowed to interact with.
* @return The current instance of the Builder.
*/
Builder sprinklerWhitelist(Set<String> whitelistSprinklers);
/**
* Sets the lore (description text) for the watering can.
*
* @param lore A list of {@link TextValue} objects representing the lore text.
* @return The current instance of the Builder.
*/
Builder lore(List<TextValue<Player>> lore);
/**
* Sets the water bar that indicates the watering can's current water level.
*
* @param waterBar The {@link WaterBar} instance.
* @return The current instance of the Builder.
*/
Builder waterBar(WaterBar waterBar);
/**
* Sets the requirements that must be met to use the watering can.
*
* @param requirements An array of {@link Requirement} instances.
* @return The current instance of the Builder.
*/
Builder requirements(Requirement<Player>[] requirements);
/**
* Sets whether the watering can has infinite water capacity.
*
* @param infinite True if the watering can has infinite capacity, false otherwise.
* @return The current instance of the Builder.
*/
Builder infinite(boolean infinite);
/**
* Sets the appearances of the watering can at different water levels.
*
* @param appearances A map where keys are water levels and values are appearance custom model IDs.
* @return The current instance of the Builder.
*/
Builder appearances(Map<Integer, Integer> appearances);
/**
* Sets the actions that are triggered when the watering can is full of water.
*
* @param fullActions An array of {@link Action} instances to be performed when the can is full.
* @return The current instance of the Builder.
*/
Builder fullActions(Action<Player>[] fullActions);
/**
* Sets the actions that are triggered when water is added to the watering can.
*
* @param addWaterActions An array of {@link Action} instances to be performed when water is added.
* @return The current instance of the Builder.
*/
Builder addWaterActions(Action<Player>[] addWaterActions);
/**
* Sets the actions that are triggered when water is consumed from the watering can.
*
* @param consumeWaterActions An array of {@link Action} instances to be performed when water is consumed.
* @return The current instance of the Builder.
*/
Builder consumeWaterActions(Action<Player>[] consumeWaterActions);
/**
* Sets the actions that are triggered when the watering can runs out of water.
*
* @param runOutOfWaterActions An array of {@link Action} instances to be performed when the can is empty.
* @return The current instance of the Builder.
*/
Builder runOutOfWaterActions(Action<Player>[] runOutOfWaterActions);
/**
* Sets the actions that are triggered when the watering can is used on the wrong pot.
*
* @param wrongPotActions An array of {@link Action} instances to be performed on wrong pot usage.
* @return The current instance of the Builder.
*/
Builder wrongPotActions(Action<Player>[] wrongPotActions);
/**
* Sets the actions that are triggered when the watering can is used on the wrong sprinkler.
*
* @param wrongSprinklerActions An array of {@link Action} instances to be performed on wrong sprinkler usage.
* @return The current instance of the Builder.
*/
Builder wrongSprinklerActions(Action<Player>[] wrongSprinklerActions);
/**
* Sets the methods available for filling the watering can with water.
*
* @param fillMethods An array of {@link FillMethod} instances.
* @return The current instance of the Builder.
*/
Builder fillMethods(FillMethod[] fillMethods);
}
}

View File

@@ -17,50 +17,110 @@
package net.momirealms.customcrops.api.core.world;
/**
* Represents a position within a chunk in the world. The position is encoded into a single integer for compact storage.
* The position is constructed using the x, y, and z coordinates, with the x and z limited to the range [0, 15]
* (as they represent positions within a 16x16 chunk), and y representing the height.
*/
public class BlockPos {
private final int position;
/**
* Constructs a BlockPos with an already encoded position.
*
* @param position The encoded position.
*/
public BlockPos(int position) {
this.position = position;
}
/**
* Constructs a BlockPos from x, y, and z coordinates within a chunk.
*
* @param x The x-coordinate within the chunk (0-15).
* @param y The y-coordinate (world height).
* @param z The z-coordinate within the chunk (0-15).
*/
public BlockPos(int x, int y, int z) {
this.position = ((x & 0xF) << 28) | ((z & 0xF) << 24) | (y & 0xFFFFFF);
}
/**
* Creates a BlockPos from a Pos3 object, adjusting x and z to be within the chunk.
*
* @param location The Pos3 object representing a 3D coordinate.
* @return A new BlockPos object.
*/
public static BlockPos fromPos3(Pos3 location) {
return new BlockPos(location.x() % 16, location.y(), location.z() % 16);
}
/**
* Converts this BlockPos into a Pos3 object, calculating absolute world coordinates using the provided ChunkPos.
*
* @param coordinate The ChunkPos representing the chunk coordinates.
* @return A Pos3 object representing the world coordinates.
*/
public Pos3 toPos3(ChunkPos coordinate) {
return new Pos3(coordinate.x() * 16 + x(), y(), coordinate.z() * 16 + z());
}
/**
* Retrieves the encoded position value.
*
* @return The encoded position.
*/
public int position() {
return position;
}
/**
* Retrieves the x-coordinate within the chunk.
*
* @return The x-coordinate (0-15).
*/
public int x() {
return (position >> 28) & 0xF;
}
/**
* Retrieves the z-coordinate within the chunk.
*
* @return The z-coordinate (0-15).
*/
public int z() {
return (position >> 24) & 0xF;
}
/**
* Retrieves the y-coordinate (world height).
*
* @return The y-coordinate.
*/
public int y() {
int y = position & 0xFFFFFF;
if ((y & 0x800000) != 0) {
y |= 0xFF000000;
if ((y & 0x800000) != 0) { // Check if y is negative in 24-bit signed integer representation
y |= 0xFF000000; // Extend the sign bit to make it a 32-bit signed integer.
}
return y;
}
/**
* Calculates the section ID based on the y-coordinate.
*
* @return The section ID, representing which 16-block high section of the world the position is in.
*/
public int sectionID() {
return (int) Math.floor((double) y() / 16);
}
/**
* Checks if this BlockPos is equal to another object.
*
* @param o The object to compare.
* @return true if the object is a BlockPos with the same encoded position, false otherwise.
*/
@Override
public boolean equals(Object o) {
if (this == o) return true;
@@ -69,11 +129,21 @@ public class BlockPos {
return position == blockPos.position;
}
/**
* Computes a hash code for this BlockPos.
*
* @return A hash code derived from the encoded position.
*/
@Override
public int hashCode() {
return Math.abs(position);
}
/**
* Returns a string representation of this BlockPos.
*
* @return A string in the format "BlockPos{x=..., y=..., z=...}".
*/
@Override
public String toString() {
return "BlockPos{" +

View File

@@ -20,12 +20,29 @@ package net.momirealms.customcrops.api.core.world;
import org.bukkit.Chunk;
import org.jetbrains.annotations.NotNull;
/**
* Represents the position of a chunk in a Minecraft world using chunk coordinates (x, z).
*/
public record ChunkPos(int x, int z) {
/**
* Creates a new ChunkPos instance with the specified chunk coordinates.
*
* @param x The x-coordinate of the chunk.
* @param z The z-coordinate of the chunk.
* @return A new ChunkPos instance.
*/
public static ChunkPos of(int x, int z) {
return new ChunkPos(x, z);
}
/**
* Parses a ChunkPos from a string representation in the format "x,z".
*
* @param coordinate The string representation of the chunk coordinates.
* @return A new ChunkPos instance parsed from the string.
* @throws RuntimeException If the string cannot be parsed into valid coordinates.
*/
public static ChunkPos fromString(String coordinate) {
String[] split = coordinate.split(",", 2);
try {
@@ -37,18 +54,35 @@ public record ChunkPos(int x, int z) {
}
}
/**
* Creates a ChunkPos from a Pos3 object by calculating which chunk the position falls into.
*
* @param pos3 The Pos3 object representing a 3D position.
* @return A ChunkPos representing the chunk containing the provided position.
*/
public static ChunkPos fromPos3(Pos3 pos3) {
int chunkX = (int) Math.floor((double) pos3.x() / 16.0);
int chunkZ = (int) Math.floor((double) pos3.z() / 16.0);
return ChunkPos.of(chunkX, chunkZ);
}
/**
* Computes a hash code for this ChunkPos.
*
* @return A hash code representing this ChunkPos.
*/
@Override
public int hashCode() {
long combined = (long) x << 32 | z;
return Long.hashCode(combined);
}
/**
* Checks if this ChunkPos is equal to another object.
*
* @param obj The object to compare.
* @return true if the object is a ChunkPos with the same x and z coordinates, false otherwise.
*/
@Override
public boolean equals(Object obj) {
if (obj == null) {
@@ -67,20 +101,41 @@ public record ChunkPos(int x, int z) {
return true;
}
/**
* Converts this ChunkPos to a RegionPos, which represents a larger area containing multiple chunks.
*
* @return A RegionPos representing the region containing this chunk.
*/
@NotNull
public RegionPos toRegionPos() {
return RegionPos.getByChunkPos(this);
}
/**
* Creates a ChunkPos from a Bukkit Chunk object.
*
* @param chunk The Bukkit Chunk object.
* @return A ChunkPos representing the chunk's coordinates.
*/
@NotNull
public static ChunkPos fromBukkitChunk(@NotNull Chunk chunk) {
return new ChunkPos(chunk.getX(), chunk.getZ());
}
/**
* Converts this ChunkPos to a string representation in the format "x,z".
*
* @return A string representing this ChunkPos.
*/
public String asString() {
return x + "," + z;
}
/**
* Returns a string representation of this ChunkPos for debugging and logging purposes.
*
* @return A string in the format "ChunkPos{x=..., z=...}".
*/
@Override
public String toString() {
return "ChunkPos{" +
@@ -88,4 +143,4 @@ public record ChunkPos(int x, int z) {
", z=" + z +
'}';
}
}
}

View File

@@ -21,11 +21,26 @@ import com.flowpowered.nbt.CompoundMap;
import net.momirealms.customcrops.api.core.block.CustomCropsBlock;
import org.jetbrains.annotations.NotNull;
/**
* Interface representing the state of a custom crops block in the CustomCrops plugin.
*/
public interface CustomCropsBlockState extends DataBlock {
/**
* Retrieves the type of the custom crops block associated with this state.
*
* @return The {@link CustomCropsBlock} type of this block state.
*/
@NotNull
CustomCropsBlock type();
/**
* Creates a new instance of {@link CustomCropsBlockState} with the given block type and NBT data.
*
* @param owner The custom crops block type that owns this state.
* @param compoundMap The NBT data associated with this block state.
* @return A new instance of {@link CustomCropsBlockState} representing the specified block type and state.
*/
static CustomCropsBlockState create(CustomCropsBlock owner, CompoundMap compoundMap) {
return new CustomCropsBlockStateImpl(owner, compoundMap);
}

View File

@@ -24,171 +24,215 @@ import java.util.PriorityQueue;
import java.util.Set;
import java.util.stream.Stream;
/**
* Interface representing a chunk in the CustomCrops plugin
*/
public interface CustomCropsChunk {
/**
* Set if the chunk can be force loaded.
* If a chunk is force loaded, no one can unload it unless you set force load to false.
* This can prevent CustomCrops from unloading the chunks on {@link org.bukkit.event.world.ChunkUnloadEvent}
* Sets whether the chunk can be force loaded.
* If a chunk is force loaded, it cannot be unloaded unless force loading is set to false.
* This prevents CustomCrops from unloading the chunk during a {@link org.bukkit.event.world.ChunkUnloadEvent}.
*
* This value will not be persistently stored. Please use {@link org.bukkit.World#setChunkForceLoaded(int, int, boolean)}
* if you want to force a chunk loaded.
* Note: This value is not persistently stored. To force a chunk to stay loaded persistently,
* use {@link org.bukkit.World#setChunkForceLoaded(int, int, boolean)}.
*
* @param forceLoad force loaded
* @param forceLoad Whether the chunk should be force loaded.
*/
void setForceLoaded(boolean forceLoad);
/**
* Indicates whether the chunk is force loaded
* Checks if the chunk is force loaded.
*
* @return force loaded or not
* @return true if the chunk is force loaded, false otherwise.
*/
boolean isForceLoaded();
/**
* Loads the chunk to cache and participate in the mechanism of the plugin.
* Loads the chunk into the cache to participate in the plugin's mechanisms.
*
* @param loadBukkitChunk whether to load Bukkit chunks temporarily if it's not loaded
* @param loadBukkitChunk Whether to temporarily load the Bukkit chunk if it is not already loaded.
*/
void load(boolean loadBukkitChunk);
/**
* Unloads the chunk. Lazy refer to those chunks that will be delayed for unloading.
* Recently unloaded chunks are likely to be loaded again soon.
* Unloads the chunk, with an option for a lazy unload.
* Lazy unloading delays the unload, which is useful if the chunk is likely to be loaded again soon.
*
* @param lazy delay unload or not
* @param lazy Whether to delay the unload (lazy unload).
*/
void unload(boolean lazy);
/**
* Unloads the chunk if it is a lazy chunk
* Unloads the chunk if it is marked as lazy.
*/
void unloadLazy();
/**
* Indicates whether the chunk is in lazy state
* Checks if the chunk is marked as lazy.
*
* @return lazy or not
* @return true if the chunk is lazy, false otherwise.
*/
boolean isLazy();
/**
* Indicates whether the chunk is loaded
* Checks if the chunk is currently loaded.
*
* @return loaded or not
* @return true if the chunk is loaded, false otherwise.
*/
boolean isLoaded();
/**
* Get the world associated with the chunk
* Gets the world associated with this chunk.
*
* @return CustomCrops world
* @return The {@link CustomCropsWorld} instance.
*/
CustomCropsWorld<?> getWorld();
/**
* Get the position of the chunk
* Gets the position of this chunk.
*
* @return chunk position
* @return The {@link ChunkPos} representing the chunk's position.
*/
ChunkPos chunkPos();
/**
* Do second timer
* Executes a timer task associated with this chunk.
*/
void timer();
/**
* Get the unloaded time in seconds
* This value would increase if the chunk is lazy
* Gets the time in seconds since the chunk was unloaded.
* This value increases if the chunk is in a lazy state.
*
* @return the unloaded time
* @return The unloaded time in seconds.
*/
int unloadedSeconds();
/**
* Set the unloaded seconds
* Sets the time in seconds since the chunk was unloaded.
*
* @param unloadedSeconds unloadedSeconds
* @param unloadedSeconds The unloaded time to set.
*/
void unloadedSeconds(int unloadedSeconds);
/**
* Get the last loaded time
* Gets the last time the chunk was loaded.
*
* @return last loaded time
* @return The timestamp of the last loaded time.
*/
long lastLoadedTime();
/**
* Set the last loaded time to current time
* Updates the last loaded time to the current time.
*/
void updateLastLoadedTime();
/**
* Get the loaded time in seconds
* Gets the time in milliseconds since the chunk was loaded.
*
* @return loaded time
* @return The loaded time in milliseconds.
*/
int loadedMilliSeconds();
/**
* Get block data at a certain location
* Retrieves the custom crop block state at a specific location.
*
* @param location location
* @return block data
* @param location The location to check.
* @return An {@link Optional} containing the {@link CustomCropsBlockState} if present, otherwise empty.
*/
@NotNull
Optional<CustomCropsBlockState> getBlockState(Pos3 location);
/**
* Remove any block data from a certain location
* Removes any custom crop block state at a specific location.
*
* @param location location
* @return block data
* @param location The location from which to remove the block state.
* @return An {@link Optional} containing the removed {@link CustomCropsBlockState} if present, otherwise empty.
*/
@NotNull
Optional<CustomCropsBlockState> removeBlockState(Pos3 location);
/**
* Add a custom block data at a certain location
* Adds a custom crop block state at a specific location.
*
* @param block block to add
* @return the previous block data
* @param location The location to add the block state.
* @param block The custom crop block state to add.
* @return An {@link Optional} containing the previous {@link CustomCropsBlockState} if replaced, otherwise empty.
*/
@NotNull
Optional<CustomCropsBlockState> addBlockState(Pos3 location, CustomCropsBlockState block);
/**
* Get CustomCrops sections
* Gets a stream of custom crop sections that need to be saved.
*
* @return sections
* @return A {@link Stream} of {@link CustomCropsSection} to save.
*/
@NotNull
Stream<CustomCropsSection> sectionsToSave();
/**
* Get section by ID
* Retrieves a loaded section by its ID.
*
* @param sectionID id
* @return section
* @param sectionID The ID of the section to retrieve.
* @return An {@link Optional} containing the {@link CustomCropsSection} if loaded, otherwise empty.
*/
@NotNull
Optional<CustomCropsSection> getLoadedSection(int sectionID);
/**
* Retrieves a section by its ID, loading it if necessary.
*
* @param sectionID The ID of the section to retrieve.
* @return The {@link CustomCropsSection} instance.
*/
CustomCropsSection getSection(int sectionID);
/**
* Retrieves all sections within this chunk.
*
* @return An array of {@link CustomCropsSection}.
*/
CustomCropsSection[] sections();
/**
* Removes a section by its ID.
*
* @param sectionID The ID of the section to remove.
* @return An {@link Optional} containing the removed {@link CustomCropsSection} if present, otherwise empty.
*/
Optional<CustomCropsSection> removeSection(int sectionID);
/**
* Resets the unloaded time counter to zero.
*/
void resetUnloadedSeconds();
/**
* Checks if the chunk can be pruned (removed from memory or storage).
*
* @return true if the chunk can be pruned, false otherwise.
*/
boolean canPrune();
/**
* Checks if offline tasks have been notified for this chunk.
*
* @return true if offline tasks are notified, false otherwise.
*/
boolean isOfflineTaskNotified();
/**
* Gets the queue of delayed tick tasks for this chunk.
*
* @return A {@link PriorityQueue} of {@link DelayedTickTask}.
*/
PriorityQueue<DelayedTickTask> tickTaskQueue();
/**
* Gets the set of blocks that have been ticked in one tick cycle within this chunk.
*
* @return A {@link Set} of {@link BlockPos} representing ticked blocks.
*/
Set<BlockPos> tickedBlocks();
}

View File

@@ -21,26 +21,79 @@ import org.jetbrains.annotations.NotNull;
import java.util.Map;
/**
* Interface representing a region in the CustomCrops plugin
*/
public interface CustomCropsRegion {
/**
* Checks if the region is currently loaded.
*
* @return true if the region is loaded, false otherwise.
*/
boolean isLoaded();
/**
* Unloads the region, freeing up resources.
*/
void unload();
/**
* Loads the region into memory, preparing it for operations.
*/
void load();
/**
* Gets the world associated with this region.
*
* @return The {@link CustomCropsWorld} instance representing the world.
*/
@NotNull
CustomCropsWorld<?> getWorld();
/**
* Retrieves the cached data of a chunk within this region by its position.
*
* @param pos The {@link ChunkPos} representing the position of the chunk.
* @return A byte array representing the cached data of the chunk, or null if no data is cached.
*/
byte[] getCachedChunkBytes(ChunkPos pos);
/**
* Gets the position of this region.
*
* @return The {@link RegionPos} representing the region's position.
*/
@NotNull
RegionPos regionPos();
/**
* Removes the cached data of a chunk from this region by its position.
*
* @param pos The {@link ChunkPos} representing the position of the chunk.
* @return true if the cached data was removed successfully, false otherwise.
*/
boolean removeCachedChunk(ChunkPos pos);
/**
* Caches the data of a chunk within this region at the specified position.
*
* @param pos The {@link ChunkPos} representing the position of the chunk.
* @param data A byte array representing the data to cache for the chunk.
*/
void setCachedChunk(ChunkPos pos, byte[] data);
/**
* Retrieves a map of all chunks and their data that need to be saved.
*
* @return A {@link Map} where the key is {@link ChunkPos} and the value is a byte array of the chunk data.
*/
Map<ChunkPos, byte[]> dataToSave();
/**
* Checks if the region can be pruned (removed from memory or storage).
*
* @return true if the region can be pruned, false otherwise.
*/
boolean canPrune();
}

View File

@@ -76,6 +76,7 @@ public class CustomCropsRegionImpl implements CustomCropsRegion {
return this.cachedChunks.get(pos);
}
@NotNull
@Override
public RegionPos regionPos() {
return this.regionPos;

View File

@@ -23,30 +23,85 @@ import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
/**
* Interface representing a section of a chunk in the CustomCrops plugin
*/
public interface CustomCropsSection {
/**
* Creates a new instance of a CustomCropsSection with the specified section ID.
*
* @param sectionID The ID of the section to create.
* @return A new {@link CustomCropsSection} instance.
*/
static CustomCropsSection create(int sectionID) {
return new CustomCropsSectionImpl(sectionID);
}
/**
* Restores an existing CustomCropsSection from the provided section ID and block states.
*
* @param sectionID The ID of the section to restore.
* @param blocks A map of {@link BlockPos} to {@link CustomCropsBlockState} representing the blocks in the section.
* @return A restored {@link CustomCropsSection} instance.
*/
static CustomCropsSection restore(int sectionID, ConcurrentHashMap<BlockPos, CustomCropsBlockState> blocks) {
return new CustomCropsSectionImpl(sectionID, blocks);
}
/**
* Gets the ID of this section.
*
* @return The section ID.
*/
int getSectionID();
/**
* Retrieves the block state at a specific position within this section.
*
* @param pos The {@link BlockPos} representing the position of the block.
* @return An {@link Optional} containing the {@link CustomCropsBlockState} if present, otherwise empty.
*/
@NotNull
Optional<CustomCropsBlockState> getBlockState(BlockPos pos);
/**
* Removes the block state at a specific position within this section.
*
* @param pos The {@link BlockPos} representing the position of the block to remove.
* @return An {@link Optional} containing the removed {@link CustomCropsBlockState} if present, otherwise empty.
*/
@NotNull
Optional<CustomCropsBlockState> removeBlockState(BlockPos pos);
/**
* Adds or replaces a block state at a specific position within this section.
*
* @param pos The {@link BlockPos} representing the position where the block will be added.
* @param block The {@link CustomCropsBlockState} to add.
* @return An {@link Optional} containing the previous {@link CustomCropsBlockState} if replaced, otherwise empty.
*/
@NotNull
Optional<CustomCropsBlockState> addBlockState(BlockPos pos, CustomCropsBlockState block);
/**
* Checks if the section can be pruned (removed from memory or storage).
*
* @return true if the section can be pruned, false otherwise.
*/
boolean canPrune();
/**
* Gets an array of all block states within this section.
*
* @return An array of {@link CustomCropsBlockState}.
*/
CustomCropsBlockState[] blocks();
/**
* Gets a map of all block positions to their respective block states within this section.
*
* @return A {@link Map} of {@link BlockPos} to {@link CustomCropsBlockState}.
*/
Map<BlockPos, CustomCropsBlockState> blockMap();
}

View File

@@ -27,30 +27,46 @@ import java.util.Optional;
import java.util.PriorityQueue;
import java.util.concurrent.ConcurrentHashMap;
/**
* Interface representing a custom world in the CustomCrops plugin
*
* @param <W> The type representing the world (e.g., Bukkit World).
*/
public interface CustomCropsWorld<W> {
/**
* Create a CustomCrops world
* Creates a new CustomCrops world with the specified world instance and adaptor.
*
* @param world world instance
* @param adaptor the world adaptor
* @return CustomCrops world
* @param <W> world type
* @param world The world instance.
* @param adaptor The world adaptor to use for this world.
* @param <W> The type of the world.
* @return A new instance of {@link CustomCropsWorld}.
*/
static <W> CustomCropsWorld<W> create(W world, WorldAdaptor<W> adaptor) {
return new CustomCropsWorldImpl<>(world, adaptor);
}
/**
* Create a new CustomCropsChunk associated with this world
* Creates a new CustomCropsChunk associated with this world at the specified position.
*
* @param pos the position of the chunk
* @return the created chunk
* @param pos The position of the chunk.
* @return The created {@link CustomCropsChunk}.
*/
default CustomCropsChunk createChunk(ChunkPos pos) {
return new CustomCropsChunkImpl(this, pos);
}
/**
* Restores a CustomCropsChunk with the specified parameters.
*
* @param pos The position of the chunk.
* @param loadedSeconds The number of seconds the chunk has been loaded.
* @param lastLoadedTime The last time the chunk was loaded.
* @param loadedSections The sections loaded in this chunk.
* @param queue The queue of delayed tick tasks.
* @param tickedBlocks The set of blocks that have been ticked.
* @return The restored {@link CustomCropsChunk}.
*/
default CustomCropsChunk restoreChunk(
ChunkPos pos,
int loadedSeconds,
@@ -62,156 +78,221 @@ public interface CustomCropsWorld<W> {
return new CustomCropsChunkImpl(this, pos, loadedSeconds, lastLoadedTime, loadedSections, queue, tickedBlocks);
}
/**
* Creates a new CustomCropsRegion associated with this world at the specified position.
*
* @param pos The position of the region.
* @return The created {@link CustomCropsRegion}.
*/
default CustomCropsRegion createRegion(RegionPos pos) {
return new CustomCropsRegionImpl(this, pos);
}
/**
* Restores a CustomCropsRegion with the specified cached chunks.
*
* @param pos The position of the region.
* @param cachedChunks The map of cached chunks within the region.
* @return The restored {@link CustomCropsRegion}.
*/
default CustomCropsRegion restoreRegion(RegionPos pos, ConcurrentHashMap<ChunkPos, byte[]> cachedChunks) {
return new CustomCropsRegionImpl(this, pos, cachedChunks);
}
/**
* Gets the world adaptor associated with this world.
*
* @return The {@link WorldAdaptor} for this world.
*/
WorldAdaptor<W> adaptor();
/**
* Gets the extra data associated with this world.
*
* @return The {@link WorldExtraData} instance.
*/
WorldExtraData extraData();
/**
* Tests if adding a specified amount of blocks of a certain type would exceed
* the chunk limitation for that block type.
*
* @param pos3 The position to test.
* @param clazz The class of the block type.
* @param amount The number of blocks to add.
* @return true if it would exceed the limit, false otherwise.
*/
boolean testChunkLimitation(Pos3 pos3, Class<? extends CustomCropsBlock> clazz, int amount);
/**
* Checks if a chunk contains any blocks of a specific type.
*
* @param pos3 The position to check.
* @param clazz The class of the block type.
* @return true if the chunk contains the block type, false otherwise.
*/
boolean doesChunkHaveBlock(Pos3 pos3, Class<? extends CustomCropsBlock> clazz);
/**
* Gets the number of blocks of a specific type in a chunk.
*
* @param pos3 The position to check.
* @param clazz The class of the block type.
* @return The number of blocks of the specified type in the chunk.
*/
int getChunkBlockAmount(Pos3 pos3, Class<? extends CustomCropsBlock> clazz);
/**
* Gets all the loaded chunks in this world.
*
* @return An array of {@link CustomCropsChunk} representing the loaded chunks.
*/
CustomCropsChunk[] loadedChunks();
/**
* Get the state of the block at a certain location
* Gets the block state at a specific location.
*
* @param location location of the block state
* @return the optional block state
* @param location The location of the block state.
* @return An {@link Optional} containing the block state if present, otherwise empty.
*/
@NotNull
Optional<CustomCropsBlockState> getBlockState(Pos3 location);
/**
* Remove the block state from a certain location
* Removes the block state at a specific location.
*
* @param location the location of the block state
* @return the optional removed state
* @param location The location of the block state to remove.
* @return An {@link Optional} containing the removed block state if present, otherwise empty.
*/
@NotNull
Optional<CustomCropsBlockState> removeBlockState(Pos3 location);
/**
* Add block state at the certain location
* Adds a block state at a specific location.
*
* @param location location of the state
* @param block block state to add
* @return the optional previous state
* @param location The location of the block state.
* @param block The block state to add.
* @return An {@link Optional} containing the previous block state if replaced, otherwise empty.
*/
@NotNull
Optional<CustomCropsBlockState> addBlockState(Pos3 location, CustomCropsBlockState block);
/**
* Save the world to file
* Saves the world data to a file.
*/
void save();
/**
* Set if the ticking task is ongoing
* Sets whether the ticking task is ongoing.
*
* @param tick ongoing or not
* @param tick true if ticking is ongoing, false otherwise.
*/
void setTicking(boolean tick);
/**
* Get the world associated with this world
* Gets the underlying world instance associated with this CustomCrops world.
*
* @return Bukkit world
* @return The world instance of type W.
*/
W world();
/**
* Gets the Bukkit World instance associated with this CustomCrops world.
*
* @return The Bukkit {@link World} instance.
*/
World bukkitWorld();
/**
* Gets the name of the world.
*
* @return The world name.
*/
String worldName();
/**
* Get the settings of the world
* Gets the settings associated with this world.
*
* @return the setting
* @return The {@link WorldSetting} instance.
*/
@NotNull
WorldSetting setting();
/**
* Set the settings of the world
* Sets the settings for this world.
*
* @param setting setting
* @param setting The {@link WorldSetting} to apply.
*/
void setting(WorldSetting setting);
/*
* Chunks
/**
* Checks if a chunk is loaded in this world.
*
* @param pos The position of the chunk.
* @return true if the chunk is loaded, false otherwise.
*/
boolean isChunkLoaded(ChunkPos pos);
/**
* Get loaded chunk from cache
* Gets a loaded chunk from the cache, if available.
*
* @param chunkPos the position of the chunk
* @return the optional loaded chunk
* @param chunkPos The position of the chunk.
* @return An {@link Optional} containing the loaded chunk if present, otherwise empty.
*/
@NotNull
Optional<CustomCropsChunk> getLoadedChunk(ChunkPos chunkPos);
/**
* Get chunk from cache or file
* Gets a chunk from the cache or loads it from file if not cached.
*
* @param chunkPos the position of the chunk
* @return the optional chunk
* @param chunkPos The position of the chunk.
* @return An {@link Optional} containing the chunk if present, otherwise empty.
*/
@NotNull
Optional<CustomCropsChunk> getChunk(ChunkPos chunkPos);
/**
* Get chunk from cache or file, create if not found
* Gets a chunk from the cache or loads it from file, creating a new one if it does not exist.
*
* @param chunkPos the position of the chunk
* @return the chunk
* @param chunkPos The position of the chunk.
* @return The {@link CustomCropsChunk}.
*/
@NotNull
CustomCropsChunk getOrCreateChunk(ChunkPos chunkPos);
/**
* Check if a region is loaded
* Checks if a region is loaded in this world.
*
* @param regionPos the position of the region
* @return loaded or not
* @param regionPos The position of the region.
* @return true if the region is loaded, false otherwise.
*/
boolean isRegionLoaded(RegionPos regionPos);
/**
* Get the loaded region, empty if not loaded
* Gets a loaded region from the cache, if available.
*
* @param regionPos position of the region
* @return the optional loaded region
* @param regionPos The position of the region.
* @return An {@link Optional} containing the loaded region if present, otherwise empty.
*/
@NotNull
Optional<CustomCropsRegion> getLoadedRegion(RegionPos regionPos);
/**
* Get the region from cache or file
* Gets a region from the cache or loads it from file if not cached.
*
* @param regionPos position of the region
* @return the optional region
* @param regionPos The position of the region.
* @return An {@link Optional} containing the region if present, otherwise empty.
*/
@NotNull
Optional<CustomCropsRegion> getRegion(RegionPos regionPos);
/**
* Get the region from cache or file, create if not found
* Gets a region from the cache or loads it from file, creating a new one if it does not exist.
*
* @param regionPos position of the region
* @return the region
* @param regionPos The position of the region.
* @return The {@link CustomCropsRegion}.
*/
@NotNull
CustomCropsRegion getOrCreateRegion(RegionPos regionPos);
}

View File

@@ -60,9 +60,10 @@ public class CustomCropsWorldImpl<W> implements CustomCropsWorld<W> {
this.regionTimer = 0;
this.adaptor = adaptor;
this.extraData = adaptor.loadExtraData(world);
this.currentMinecraftDay = (int) (adaptor.getWorldFullTime(world) / 24_000);
this.currentMinecraftDay = (int) (bukkitWorld().getFullTime() / 24_000);
}
@NotNull
@Override
public WorldAdaptor<W> adaptor() {
return adaptor;

View File

@@ -20,18 +20,40 @@ package net.momirealms.customcrops.api.core.world;
import com.flowpowered.nbt.Tag;
import net.momirealms.customcrops.api.core.SynchronizedCompoundMap;
/**
* Interface representing a data block that can store, retrieve, and manipulate NBT data.
*/
public interface DataBlock {
/**
* Sets an NBT tag in the data block with the specified key.
*
* @param key The key for the tag to set.
* @param tag The NBT tag to set.
* @return The previous tag associated with the key, or null if there was no previous tag.
*/
Tag<?> set(String key, Tag<?> tag);
/**
* Retrieves an NBT tag from the data block with the specified key.
*
* @param key The key of the tag to retrieve.
* @return The NBT tag associated with the key, or null if no tag is found.
*/
Tag<?> get(String key);
/**
* Removes an NBT tag from the data block with the specified key.
*
* @param key The key of the tag to remove.
* @return The removed NBT tag, or null if no tag was found with the specified key.
*/
Tag<?> remove(String key);
/**
* Get the data map
* Gets the synchronized compound map containing all the NBT data of the block.
*
* @return data map
* @return The {@link SynchronizedCompoundMap} containing the block's NBT data.
*/
SynchronizedCompoundMap compoundMap();
}

View File

@@ -20,8 +20,17 @@ package net.momirealms.customcrops.api.core.world;
import org.bukkit.Location;
import org.bukkit.World;
/**
* Represents a 3-dimensional position (x, y, z) in a Minecraft world.
*/
public record Pos3(int x, int y, int z) {
/**
* Checks if this position is equal to another object.
*
* @param obj The object to compare with.
* @return true if the object is a Pos3 with the same coordinates, false otherwise.
*/
@Override
public boolean equals(Object obj) {
if (obj == null) {
@@ -43,6 +52,11 @@ public record Pos3(int x, int y, int z) {
return true;
}
/**
* Computes a hash code for this position.
*
* @return A hash code representing this Pos3.
*/
@Override
public int hashCode() {
int hash = 3;
@@ -52,30 +66,70 @@ public record Pos3(int x, int y, int z) {
return hash;
}
/**
* Converts a Bukkit {@link Location} to a Pos3 instance.
*
* @param location The Bukkit location to convert.
* @return A new Pos3 instance representing the block coordinates of the location.
*/
public static Pos3 from(Location location) {
return new Pos3(location.getBlockX(), location.getBlockY(), location.getBlockZ());
}
/**
* Converts this Pos3 instance to a Bukkit {@link Location}.
*
* @param world The Bukkit world to associate with the location.
* @return A new Location instance with this Pos3's coordinates in the specified world.
*/
public Location toLocation(World world) {
return new Location(world, x, y, z);
}
/**
* Adds the specified values to this position's coordinates and returns a new Pos3 instance.
*
* @param x The amount to add to the x-coordinate.
* @param y The amount to add to the y-coordinate.
* @param z The amount to add to the z-coordinate.
* @return A new Pos3 instance with updated coordinates.
*/
public Pos3 add(int x, int y, int z) {
return new Pos3(this.x + x, this.y + y, this.z + z);
}
/**
* Converts this Pos3 instance to a {@link ChunkPos}, representing the chunk coordinates of this position.
*
* @return The {@link ChunkPos} containing this Pos3.
*/
public ChunkPos toChunkPos() {
return ChunkPos.fromPos3(this);
}
/**
* Calculates the chunk x-coordinate of this position.
*
* @return The chunk x-coordinate.
*/
public int chunkX() {
return (int) Math.floor((double) this.x() / 16.0);
}
/**
* Calculates the chunk z-coordinate of this position.
*
* @return The chunk z-coordinate.
*/
public int chunkZ() {
return (int) Math.floor((double) this.z() / 16.0);
}
/**
* Returns a string representation of this Pos3 instance for debugging and logging.
*
* @return A string in the format "Pos3{x=..., y=..., z=...}".
*/
@Override
public String toString() {
return "Pos3{" +
@@ -84,4 +138,4 @@ public record Pos3(int x, int y, int z) {
", z=" + z +
'}';
}
}
}

View File

@@ -20,12 +20,30 @@ package net.momirealms.customcrops.api.core.world;
import org.bukkit.Chunk;
import org.jetbrains.annotations.NotNull;
/**
* Represents a region position in a Minecraft world, defined by its x and z coordinates.
*/
public record RegionPos(int x, int z) {
/**
* Creates a new RegionPos instance with the specified x and z coordinates.
*
* @param x The x-coordinate of the region.
* @param z The z-coordinate of the region.
* @return A new {@link RegionPos} instance.
*/
public static RegionPos of(int x, int z) {
return new RegionPos(x, z);
}
/**
* Parses a string representation of a region position and returns a RegionPos instance.
* The string should be in the format "x,z".
*
* @param coordinate The string representation of the region position.
* @return A new {@link RegionPos} instance.
* @throws RuntimeException if the coordinate string is invalid.
*/
public static RegionPos getByString(String coordinate) {
String[] split = coordinate.split(",", 2);
try {
@@ -38,12 +56,23 @@ public record RegionPos(int x, int z) {
}
}
/**
* Computes a hash code for this region position.
*
* @return A hash code representing this {@link RegionPos}.
*/
@Override
public int hashCode() {
long combined = (long) x << 32 | z;
return Long.hashCode(combined);
}
/**
* Checks if this region position is equal to another object.
*
* @param obj The object to compare with.
* @return true if the object is a {@link RegionPos} with the same coordinates, false otherwise.
*/
@Override
public boolean equals(Object obj) {
if (obj == null) {
@@ -62,6 +91,13 @@ public record RegionPos(int x, int z) {
return true;
}
/**
* Converts a Bukkit {@link Chunk} to a {@link RegionPos} by calculating the region coordinates.
* A region covers a 32x32 area of chunks.
*
* @param chunk The Bukkit chunk to convert.
* @return A new {@link RegionPos} representing the region containing the chunk.
*/
@NotNull
public static RegionPos getByBukkitChunk(@NotNull Chunk chunk) {
int regionX = (int) Math.floor((double) chunk.getX() / 32.0);
@@ -69,6 +105,13 @@ public record RegionPos(int x, int z) {
return new RegionPos(regionX, regionZ);
}
/**
* Converts a {@link ChunkPos} to a {@link RegionPos} by calculating the region coordinates.
* A region covers a 32x32 area of chunks.
*
* @param chunk The {@link ChunkPos} to convert.
* @return A new {@link RegionPos} representing the region containing the chunk position.
*/
@NotNull
public static RegionPos getByChunkPos(@NotNull ChunkPos chunk) {
int regionX = (int) Math.floor((double) chunk.x() / 32.0);
@@ -76,6 +119,11 @@ public record RegionPos(int x, int z) {
return new RegionPos(regionX, regionZ);
}
/**
* Returns a string representation of this RegionPos instance for debugging and logging.
*
* @return A string in the format "RegionPos{x=..., z=...}".
*/
@Override
public String toString() {
return "RegionPos{" +
@@ -84,3 +132,4 @@ public record RegionPos(int x, int z) {
'}';
}
}

View File

@@ -22,6 +22,12 @@ import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
/**
* A class representing additional data associated with a world, such as the current season,
* date, and any extra arbitrary data stored as key-value pairs. This class provides methods
* for managing the season and date of the world, as well as adding, removing, and retrieving
* extra data.
*/
public class WorldExtraData {
@SerializedName("season")
@@ -31,33 +37,62 @@ public class WorldExtraData {
@SerializedName("extra")
private HashMap<String, Object> extra;
/**
* Constructs a new WorldExtraData instance with the specified season and date.
* Initializes an empty HashMap for extra data.
*
* @param season The initial season of the world.
* @param date The initial date of the world.
*/
public WorldExtraData(Season season, int date) {
this.season = season;
this.date = date;
this.extra = new HashMap<>();
}
/**
* Creates an empty WorldExtraData instance with default values.
*
* @return A new WorldExtraData instance with the season set to SPRING and date set to 1.
*/
public static WorldExtraData empty() {
return new WorldExtraData(Season.SPRING, 1);
}
/**
* Adds extra data to the world data storage.
*
* @param key The key under which the data will be stored.
* @param value The value to store.
*/
public void addExtraData(String key, Object value) {
this.extra.put(key, value);
}
/**
* Removes extra data from the world data storage.
*
* @param key The key of the data to remove.
*/
public void removeExtraData(String key) {
this.extra.remove(key);
}
/**
* Retrieves extra data from the world data storage.
*
* @param key The key of the data to retrieve.
* @return The data associated with the key, or null if the key does not exist.
*/
@Nullable
public Object getExtraData(String key) {
return this.extra.get(key);
}
/**
* Get season
* Gets the current season of the world.
*
* @return season
* @return The current season.
*/
public Season getSeason() {
if (season == null) season = Season.SPRING;
@@ -65,37 +100,43 @@ public class WorldExtraData {
}
/**
* Set season
* Sets the season of the world.
*
* @param season the new season
* @param season The new season to set.
*/
public void setSeason(Season season) {
this.season = season;
}
/**
* Get date
* Gets the current date of the world.
*
* @return date
* @return The current date.
*/
public int getDate() {
return date;
}
/**
* Set date
* Sets the date of the world.
*
* @param date the new date
* @param date The new date to set.
*/
public void setDate(int date) {
this.date = date;
}
/**
* Returns a string representation of the WorldExtraData.
*
* @return A string containing the season and date information.
*/
@Override
public String toString() {
return "WorldExtraData{" +
"season=" + season +
", date=" + date +
", extra=" + extra +
'}';
}
}

View File

@@ -24,28 +24,98 @@ import org.bukkit.World;
import java.util.Optional;
import java.util.Set;
import java.util.TreeSet;
/**
* WorldManager is responsible for managing the lifecycle and state of worlds in the CustomCrops plugin.
* It provides methods to load, unload, and adapt worlds, manage seasonal changes, and interact with
* different world adaptors.
*/
public interface WorldManager extends Reloadable {
/**
* Gets the current SeasonProvider used for determining the season of each world.
*
* @return The current SeasonProvider.
*/
SeasonProvider seasonProvider();
/**
* Retrieves the current season for a given Bukkit world.
*
* @param world The Bukkit world to get the season for.
* @return The current season of the specified world.
*/
Season getSeason(World world);
/**
* Retrieves the current date for a given Bukkit world.
*
* @param world The Bukkit world to get the date for.
* @return The current date of the specified world.
*/
int getDate(World world);
/**
* Loads a CustomCrops world based on the specified Bukkit world.
*
* @param world The Bukkit world to load as a CustomCrops world.
* @return The loaded CustomCropsWorld instance.
*/
CustomCropsWorld<?> loadWorld(World world);
/**
* Unloads the CustomCrops world associated with the specified Bukkit world.
*
* @param world The Bukkit world to unload.
* @return True if the world was successfully unloaded, false otherwise.
*/
boolean unloadWorld(World world);
/**
* Retrieves a CustomCrops world based on the specified Bukkit world, if loaded.
*
* @param world The Bukkit world to retrieve the CustomCrops world for.
* @return An Optional containing the CustomCropsWorld instance if loaded, otherwise empty.
*/
Optional<CustomCropsWorld<?>> getWorld(World world);
/**
* Retrieves a CustomCrops world based on the world name, if loaded.
*
* @param world The name of the world to retrieve.
* @return An Optional containing the CustomCropsWorld instance if loaded, otherwise empty.
*/
Optional<CustomCropsWorld<?>> getWorld(String world);
/**
* Checks if a given Bukkit world is currently loaded as a CustomCrops world.
*
* @param world The Bukkit world to check.
* @return True if the world is loaded, false otherwise.
*/
boolean isWorldLoaded(World world);
Set<WorldAdaptor<?>> adaptors();
/**
* Retrieves all available world adaptors.
*
* @return A set of WorldAdaptor instances.
*/
TreeSet<WorldAdaptor<?>> adaptors();
/**
* Adapts a Bukkit world into a CustomCrops world.
*
* @param world The Bukkit world to adapt.
* @return The adapted CustomCropsWorld instance.
*/
CustomCropsWorld<?> adapt(World world);
/**
* Adapts a world by its name into a CustomCrops world.
*
* @param world The name of the world to adapt.
* @return The adapted CustomCropsWorld instance.
*/
CustomCropsWorld<?> adapt(String world);
}
}

View File

@@ -17,6 +17,10 @@
package net.momirealms.customcrops.api.core.world;
/**
* Represents the configuration settings for a CustomCrops world, including various
* parameters for ticking behavior, season management, and random events.
*/
public class WorldSetting implements Cloneable {
private final boolean enableScheduler;
@@ -37,6 +41,27 @@ public class WorldSetting implements Cloneable {
private final boolean tickPotRandomly;
private final boolean tickSprinklerRandomly;
/**
* Private constructor to initialize a WorldSetting instance with the provided parameters.
*
* @param enableScheduler Whether the scheduler is enabled.
* @param minTickUnit The minimum unit of tick.
* @param tickCropRandomly Whether crops are ticked randomly.
* @param tickCropInterval The interval for ticking crops.
* @param tickPotRandomly Whether pots are ticked randomly.
* @param tickPotInterval The interval for ticking pots.
* @param tickSprinklerRandomly Whether sprinklers are ticked randomly.
* @param tickSprinklerInterval The interval for ticking sprinklers.
* @param offlineTick Whether offline ticking is enabled.
* @param maxOfflineTime The maximum offline time allowed.
* @param enableSeason Whether seasons are enabled.
* @param autoSeasonChange Whether season change is automatic.
* @param seasonDuration The duration of each season.
* @param cropPerChunk The maximum number of crops per chunk.
* @param potPerChunk The maximum number of pots per chunk.
* @param sprinklerPerChunk The maximum number of sprinklers per chunk.
* @param randomTickSpeed The random tick speed.
*/
private WorldSetting(
boolean enableScheduler,
int minTickUnit,
@@ -75,6 +100,28 @@ public class WorldSetting implements Cloneable {
this.tickSprinklerRandomly = tickSprinklerRandomly;
}
/**
* Factory method to create a new instance of WorldSetting.
*
* @param enableScheduler Whether the scheduler is enabled.
* @param minTickUnit The minimum unit of tick.
* @param tickCropRandomly Whether crops are ticked randomly.
* @param tickCropInterval The interval for ticking crops.
* @param tickPotRandomly Whether pots are ticked randomly.
* @param tickPotInterval The interval for ticking pots.
* @param tickSprinklerRandomly Whether sprinklers are ticked randomly.
* @param tickSprinklerInterval The interval for ticking sprinklers.
* @param offlineGrow Whether offline ticking is enabled.
* @param maxOfflineTime The maximum offline time allowed.
* @param enableSeason Whether seasons are enabled.
* @param autoSeasonChange Whether season change is automatic.
* @param seasonDuration The duration of each season.
* @param cropPerChunk The maximum number of crops per chunk.
* @param potPerChunk The maximum number of pots per chunk.
* @param sprinklerPerChunk The maximum number of sprinklers per chunk.
* @param randomTickSpeed The random tick speed.
* @return A new WorldSetting instance.
*/
public static WorldSetting of(
boolean enableScheduler,
int minTickUnit,
@@ -115,74 +162,164 @@ public class WorldSetting implements Cloneable {
);
}
/**
* Checks if the scheduler is enabled.
*
* @return true if the scheduler is enabled, false otherwise.
*/
public boolean enableScheduler() {
return enableScheduler;
}
/**
* Gets the minimum tick unit.
*
* @return The minimum tick unit.
*/
public int minTickUnit() {
return minTickUnit;
}
/**
* Gets the interval for ticking crops.
*
* @return The tick interval for crops.
*/
public int tickCropInterval() {
return tickCropInterval;
}
/**
* Gets the interval for ticking pots.
*
* @return The tick interval for pots.
*/
public int tickPotInterval() {
return tickPotInterval;
}
/**
* Gets the interval for ticking sprinklers.
*
* @return The tick interval for sprinklers.
*/
public int tickSprinklerInterval() {
return tickSprinklerInterval;
}
/**
* Checks if offline ticking is enabled.
*
* @return true if offline ticking is enabled, false otherwise.
*/
public boolean offlineTick() {
return offlineTick;
}
/**
* Checks if seasons are enabled.
*
* @return true if seasons are enabled, false otherwise.
*/
public boolean enableSeason() {
return enableSeason;
}
/**
* Checks if automatic season change is enabled.
*
* @return true if automatic season change is enabled, false otherwise.
*/
public boolean autoSeasonChange() {
return autoSeasonChange;
}
/**
* Gets the duration of each season.
*
* @return The duration of each season.
*/
public int seasonDuration() {
return seasonDuration;
}
/**
* Gets the maximum number of pots per chunk.
*
* @return The maximum number of pots per chunk.
*/
public int potPerChunk() {
return potPerChunk;
}
/**
* Gets the maximum number of crops per chunk.
*
* @return The maximum number of crops per chunk.
*/
public int cropPerChunk() {
return cropPerChunk;
}
/**
* Gets the maximum number of sprinklers per chunk.
*
* @return The maximum number of sprinklers per chunk.
*/
public int sprinklerPerChunk() {
return sprinklerPerChunk;
}
/**
* Gets the random tick speed.
*
* @return The random tick speed.
*/
public int randomTickSpeed() {
return randomTickSpeed;
}
/**
* Checks if crops are ticked randomly.
*
* @return true if crops are ticked randomly, false otherwise.
*/
public boolean randomTickCrop() {
return tickCropRandomly;
}
/**
* Checks if sprinklers are ticked randomly.
*
* @return true if sprinklers are ticked randomly, false otherwise.
*/
public boolean randomTickSprinkler() {
return tickSprinklerRandomly;
}
/**
* Checks if pots are ticked randomly.
*
* @return true if pots are ticked randomly, false otherwise.
*/
public boolean randomTickPot() {
return tickPotRandomly;
}
/**
* Gets the maximum offline time allowed.
*
* @return The maximum offline time.
*/
public int maxOfflineTime() {
return maxOfflineTime;
}
/**
* Creates a clone of this WorldSetting instance.
*
* @return A cloned instance of WorldSetting.
*/
@Override
public WorldSetting clone() {
try {

View File

@@ -20,43 +20,99 @@ package net.momirealms.customcrops.api.core.world.adaptor;
import net.momirealms.customcrops.api.core.world.*;
import org.jetbrains.annotations.Nullable;
/**
* Interface defining methods for adapting different types of worlds (e.g., Bukkit, Slime) for use with CustomCrops.
* This adaptor provides methods to load and save regions and chunks, handle world-specific data, and interact with
* various world implementations.
*
* @param <W> The type of the world that this adaptor supports.
*/
public interface WorldAdaptor<W> extends Comparable<WorldAdaptor<W>> {
int BUKKIT_WORLD_PRIORITY = 100;
int SLIME_WORLD_PRIORITY = 200;
/**
* Loads extra data associated with the given world.
*
* @param world The world to load data for.
* @return The loaded {@link WorldExtraData} containing extra world-specific information.
*/
WorldExtraData loadExtraData(W world);
/**
* Saves extra data for the given CustomCrops world instance.
*
* @param world The CustomCrops world instance whose extra data is to be saved.
*/
void saveExtraData(CustomCropsWorld<W> world);
/**
* Load the region from file or cache
* Loads a region from the file or cache. Creates a new region if it doesn't exist and createIfNotExist is true.
*
* @param world The CustomCrops world instance to which the region belongs.
* @param pos The position of the region to be loaded.
* @param createIfNotExist If true, creates the region if it does not exist.
* @return The loaded {@link CustomCropsRegion}, or null if the region could not be loaded and createIfNotExist is false.
*/
@Nullable
CustomCropsRegion loadRegion(CustomCropsWorld<W> world, RegionPos pos, boolean createIfNotExist);
/**
* Load the chunk from file or cache
* Loads a chunk from the file or cache. Creates a new chunk if it doesn't exist and createIfNotExist is true.
*
* @param world The CustomCrops world instance to which the chunk belongs.
* @param pos The position of the chunk to be loaded.
* @param createIfNotExist If true, creates the chunk if it does not exist.
* @return The loaded {@link CustomCropsChunk}, or null if the chunk could not be loaded and createIfNotExist is false.
*/
@Nullable
CustomCropsChunk loadChunk(CustomCropsWorld<W> world, ChunkPos pos, boolean createIfNotExist);
/**
* Unload the region to file or cache
* Saves the specified region to a file or cache.
*
* @param world The CustomCrops world instance to which the region belongs.
* @param region The region to be saved.
*/
void saveRegion(CustomCropsWorld<W> world, CustomCropsRegion region);
/**
* Saves the specified chunk to a file or cache.
*
* @param world The CustomCrops world instance to which the chunk belongs.
* @param chunk The chunk to be saved.
*/
void saveChunk(CustomCropsWorld<W> world, CustomCropsChunk chunk);
/**
* Retrieves the name of the given world.
*
* @param world The world instance.
* @return The name of the world.
*/
String getName(W world);
/**
* Gets the world instance by its name.
*
* @param worldName The name of the world to retrieve.
* @return The world instance, or null if no world with the given name is found.
*/
@Nullable
W getWorld(String worldName);
/**
* Adapts the given object to a CustomCropsWorld instance if possible.
*
* @param world The object to adapt.
* @return The adapted {@link CustomCropsWorld} instance.
*/
CustomCropsWorld<W> adapt(Object world);
long getWorldFullTime(W world);
/**
* Gets the priority of this world adaptor. Adaptors with lower priority values are considered before those with higher values.
*
* @return The priority value of this adaptor.
*/
int priority();
}

View File

@@ -1,76 +0,0 @@
/*
* 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.value;
import net.momirealms.customcrops.api.misc.placeholder.BukkitPlaceholderManager;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class DynamicText {
private final Player owner;
private String originalValue;
private String latestValue;
private String[] placeholders;
public DynamicText(Player owner, String rawValue) {
this.owner = owner;
analyze(rawValue);
}
private void analyze(String value) {
// Analyze the provided text to find and replace placeholders with '%s'.
// Store the original value, placeholders, and the initial latest value.
List<String> placeholdersOwner = new ArrayList<>(BukkitPlaceholderManager.getInstance().resolvePlaceholders(value));
String origin = value;
for (String placeholder : placeholdersOwner) {
origin = origin.replace(placeholder, "%s");
}
originalValue = origin;
placeholders = placeholdersOwner.toArray(new String[0]);
latestValue = originalValue;
}
public String getLatestValue() {
return latestValue;
}
public boolean update(Map<String, String> placeholders) {
String string = originalValue;
if (this.placeholders.length != 0) {
BukkitPlaceholderManager bukkitPlaceholderManager = BukkitPlaceholderManager.getInstance();
if ("%s".equals(originalValue)) {
string = bukkitPlaceholderManager.parseSingle(owner, this.placeholders[0], placeholders);
} else {
Object[] values = new String[this.placeholders.length];
for (int i = 0; i < this.placeholders.length; i++) {
values[i] = bukkitPlaceholderManager.parseSingle(owner, this.placeholders[i], placeholders);
}
string = String.format(originalValue, values);
}
}
if (!latestValue.equals(string)) {
latestValue = string;
return true;
}
return false;
}
}

View File

@@ -22,7 +22,7 @@ import net.momirealms.customcrops.api.context.Context;
/**
* The MathValue interface represents a mathematical value that can be evaluated
* within a specific context. This interface allows for the evaluation of mathematical
* expressions or plain numerical values in the context of custom fishing mechanics.
* expressions or plain numerical values in the context of custom crops mechanics.
*
* @param <T> the type of the holder object for the context
*/

View File

@@ -26,7 +26,7 @@ import java.util.regex.Pattern;
/**
* The TextValue interface represents a text value that can be rendered
* within a specific context. This interface allows for the rendering of
* placeholder-based or plain text values in the context of custom fishing mechanics.
* placeholder-based or plain text values in the context of custom crops mechanics.
*
* @param <T> the type of the holder object for the context
*/

View File

@@ -158,11 +158,6 @@ public class SlimeWorldAdaptorR1 extends AbstractWorldAdaptor<SlimeWorld> {
return world.getName();
}
@Override
public long getWorldFullTime(SlimeWorld world) {
return Objects.requireNonNull(Bukkit.getWorld(world.getName())).getFullTime();
}
@Override
public int priority() {
return SLIME_WORLD_PRIORITY;

View File

@@ -61,6 +61,7 @@ import java.io.InputStream;
import java.nio.file.Path;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class BukkitCustomCropsPluginImpl extends BukkitCustomCropsPlugin {
@@ -91,6 +92,12 @@ public class BukkitCustomCropsPluginImpl extends BukkitCustomCropsPlugin {
this.debugger.accept(message);
}
@Override
public void debug(Supplier<Object> message) {
if (this.debugger != null)
this.debugger.accept(message.get());
}
@Override
public InputStream getResourceStream(String filePath) {
return getBoostrap().getResource(filePath);

View File

@@ -266,7 +266,8 @@ public class ConfigType {
.storage(section.getInt("storage", 4))
.infinite(section.getBoolean("infinite", false))
.twoDItem(section.getString("2D-item"))
.sprinklingAmount(section.getInt("water", 1))
.wateringAmount(section.getInt("water", 1))
.sprinklingAmount(section.getInt("sprinkling", 1))
.threeDItem(section.getString("3D-item"))
.threeDItemWithWater(section.getString("3D-item-with-water"))
.wateringMethods(manager.getWateringMethods(section.getSection("fill-method")))

View File

@@ -212,11 +212,6 @@ public class BukkitWorldAdaptor extends AbstractWorldAdaptor<World> {
return world.getName();
}
@Override
public long getWorldFullTime(World world) {
return world.getFullTime();
}
@Override
public int priority() {
return BUKKIT_WORLD_PRIORITY;

View File

@@ -169,6 +169,7 @@ public class BukkitItemManager extends AbstractItemManager {
}
}
@NotNull
@Override
public FurnitureRotation remove(@NotNull Location location, @NotNull ExistenceForm form) {
switch (form) {
@@ -216,6 +217,7 @@ public class BukkitItemManager extends AbstractItemManager {
}
}
@NotNull
@Override
public FurnitureRotation removeFurniture(@NotNull Location location) {
Collection<Entity> entities = location.getWorld().getNearbyEntities(LocationUtils.toSurfaceCenterLocation(location), 0.5,0.25,0.5);
@@ -229,7 +231,7 @@ public class BukkitItemManager extends AbstractItemManager {
}
}
}
return rotation;
return rotation == null ? FurnitureRotation.NONE : rotation;
}
@NotNull
@@ -329,7 +331,7 @@ public class BukkitItemManager extends AbstractItemManager {
}
@Override
public Item<ItemStack> wrap(ItemStack itemStack) {
public Item<ItemStack> wrap(@NotNull ItemStack itemStack) {
return factory.wrap(itemStack);
}

View File

@@ -43,7 +43,7 @@ import java.util.concurrent.ConcurrentHashMap;
public class BukkitWorldManager implements WorldManager, Listener {
private final BukkitCustomCropsPlugin plugin;
private final Set<WorldAdaptor<?>> adaptors = new TreeSet<>();
private final TreeSet<WorldAdaptor<?>> adaptors = new TreeSet<>();
private final ConcurrentHashMap<String, CustomCropsWorld<?>> worlds = new ConcurrentHashMap<>();
private final HashMap<String, WorldSetting> worldSettings = new HashMap<>();
private WorldSetting defaultWorldSetting;
@@ -290,7 +290,7 @@ public class BukkitWorldManager implements WorldManager, Listener {
}
@Override
public Set<WorldAdaptor<?>> adaptors() {
public TreeSet<WorldAdaptor<?>> adaptors() {
return adaptors;
}