PotatoLand
Create a complete production-ready Minecraft Paper plugin named PotatoLand. Target: - Paper 1.21.11 - Java 21 - Maven - Package: me.potatocraft.potatoland Generate a complete Maven project with all Java files, plugin.yml and config.yml. Must compile with: mvn clean package Plugin purpose: Land rental/selling system. COMMAND: /zamin /zamin tool /zamin add <name> /zamin delete <name> confirm /zamin list /zamin reload Permission: potatoland.admin LAND TOOL: Create a special WOODEN_AXE selector using PersistentDataContainer. Name: &6&lPotato Land Selector Only admins can use it.
Read the full description
Right click block = position 1 Left click block = position 2 LAND: Admins create lands with /zamin add. Store using SQLite: - name - world UUID - min/max XYZ - owner UUID/name - purchase time - expiration time - price - material - sign location Prevent duplicate names and overlapping regions. Database: Create automatically: plugins/PotatoLand/database.db MARKET SIGN: Format: [House1] 5 DIAMOND Support any Bukkit Material and any positive amount. Examples: 5 DIAMOND 32 EMERALD 10 GOLD_INGOT Case insensitive. BUY SYSTEM: Players right click signs. Check: - land exists - available - enough items Remove exact material amount. Set owner and rental time. Rental duration: 30 days using timestamps. After expiration: - remove owner - release land - update sign - allow repurchase PROTECTION: Protect owned lands from: - break/place blocks - containers - doors - trapdoors - gates - buttons - levers - furnaces - crafting tables - anvils - villagers - animals Owner allowed. Admins bypass. PLACEHOLDERAPI soft support: %potatoland_land% %potatoland_owner% %potatoland_days_left% %potatoland_expiration% %potatoland_has_land% Compatible with TAB and scoreboards. Do not create scoreboard or tablist. Use clean architecture: command database land listener sign placeholder util Include: PotatoLand.java ZaminCommand.java LandManager.java DatabaseManager.java SelectionManager.java ProtectionListener.java SignListener.java PurchaseManager.java ExpirationManager.java PlaceholderAPI expansion. Do not simplify. Do not remove features. Generate complete source code.
package me.potatocraft.potatoland.command;
import me.potatocraft.potatoland.database.DatabaseManager;
import me.potatocraft.potatoland.land.LandManager;
import me.potatocraft.potatoland.land.PurchaseManager;
import me.potatocraft.potatoland.land.SelectionManager;
import me.potatocraft.potatoland.util.ConfigManager;
import me.potatocraft.potatoland.util.MessageUtil;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public final class ZaminCommand implements CommandExecutor, TabCompleter {
private final LandManager landManager;
private final SelectionManager selectionManager;
private final PurchaseManager purchaseManager;
private final MessageUtil messageUtil;
private final ConfigManager configManager;
private final DatabaseManager databaseManager;
private final String permission = "potatoland.admin";
public ZaminCommand(Object plugin,
LandManager landManager,
SelectionManager selectionManager,
PurchaseManager purchaseManager,
MessageUtil messageUtil,
ConfigManager configManager,
DatabaseManager databaseManager) {
this.landManager = landManager;
this.selectionManager = selectionManager;
this.purchaseManager = purchaseManager;
this.messageUtil = messageUtil;
this.configManager = configManager;
this.databaseManager = databaseManager;
}
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
if (args.length == 0) {
messageUtil.send(sender, "&6/zamin tool&7, &6/zamin add <name>&7, &6/zamin delete <name> confirm&7, &6/zamin list&7, &6/zamin reload");
return true;
}
String sub = args[0].toLowerCase();
if (!sender.hasPermission(permission)) {
messageUtil.send(sender, "no-permission");
return true;
}
switch (sub) {