Add real farm worker harvesting
This commit is contained in:
@@ -12,6 +12,9 @@ import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.data.Ageable;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
@@ -20,6 +23,7 @@ import org.bukkit.inventory.ItemStack;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -166,7 +170,15 @@ public final class NpcService {
|
||||
}
|
||||
}
|
||||
WorkerRecipe recipe = recipeFor(coalNpc);
|
||||
if (recipe != null && produce(coalNpc, recipe, npcs)) {
|
||||
if (recipe == null) {
|
||||
continue;
|
||||
}
|
||||
if (recipe.farmBehavior()) {
|
||||
harvestCrop(coalNpc, recipe, zone.get(), npc);
|
||||
supplyTraders(coalNpc, recipe, npcs);
|
||||
continue;
|
||||
}
|
||||
if (produce(coalNpc, recipe, npcs)) {
|
||||
supplyTraders(coalNpc, recipe, npcs);
|
||||
}
|
||||
}
|
||||
@@ -190,7 +202,7 @@ public final class NpcService {
|
||||
}
|
||||
Material material = Material.matchMaterial(plugin.getConfig().getString("npc.worker.produce_material", "BREAD"));
|
||||
int amount = plugin.getConfig().getInt("npc.worker.produce_amount", 2);
|
||||
return material == null || amount <= 0 ? null : new WorkerRecipe("default", material, amount, Map.of());
|
||||
return material == null || amount <= 0 ? null : new WorkerRecipe("default", "PRODUCE", material, amount, Map.of(), List.of(), true);
|
||||
}
|
||||
|
||||
private WorkerRecipe recipe(String name, ConfigurationSection section) {
|
||||
@@ -213,7 +225,104 @@ public final class NpcService {
|
||||
}
|
||||
}
|
||||
}
|
||||
return new WorkerRecipe(name, output, outputAmount, inputs);
|
||||
List<Material> crops = new ArrayList<>();
|
||||
for (String raw : section.getStringList("crops")) {
|
||||
Material crop = Material.matchMaterial(raw);
|
||||
if (crop != null) {
|
||||
crops.add(crop);
|
||||
}
|
||||
}
|
||||
String behavior = section.getString("behavior", inputs.isEmpty() ? "PRODUCE" : "CRAFT");
|
||||
boolean replant = section.getBoolean("replant", true);
|
||||
return new WorkerRecipe(name, behavior.toUpperCase(), output, outputAmount, inputs, crops, replant);
|
||||
}
|
||||
|
||||
private boolean harvestCrop(CoalNpc worker, WorkerRecipe recipe, NpcZone zone, NPC npc) throws SQLException {
|
||||
if (!npc.isSpawned()) {
|
||||
return false;
|
||||
}
|
||||
Block crop = findMatureCrop(zone, recipe);
|
||||
if (crop == null) {
|
||||
return false;
|
||||
}
|
||||
Location cropLocation = crop.getLocation().add(0.5D, 0.0D, 0.5D);
|
||||
double actionDistance = Math.max(1.0D, plugin.getConfig().getDouble("npc.worker.farm.action_distance", 3.0D));
|
||||
if (npc.getEntity().getLocation().distanceSquared(cropLocation) > actionDistance * actionDistance) {
|
||||
npc.getNavigator().setTarget(cropLocation);
|
||||
return false;
|
||||
}
|
||||
collectDrops(worker, crop.getDrops());
|
||||
Material cropType = crop.getType();
|
||||
crop.setType(Material.AIR);
|
||||
if (recipe.replant()) {
|
||||
replant(worker, crop, cropType);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private Block findMatureCrop(NpcZone zone, WorkerRecipe recipe) {
|
||||
World world = Bukkit.getWorld(zone.world());
|
||||
if (world == null) {
|
||||
return null;
|
||||
}
|
||||
List<Material> crops = recipe.crops().isEmpty() ? List.of(Material.WHEAT, Material.CARROTS, Material.POTATOES, Material.BEETROOTS) : recipe.crops();
|
||||
int maxScans = Math.max(16, plugin.getConfig().getInt("npc.worker.farm.max_scan_blocks", 512));
|
||||
for (int scan = 0; scan < maxScans; scan++) {
|
||||
int x = zone.x1() + random.nextInt(Math.max(1, zone.x2() - zone.x1() + 1));
|
||||
int z = zone.z1() + random.nextInt(Math.max(1, zone.z2() - zone.z1() + 1));
|
||||
if (!zone.contains(world.getName(), x, z)) {
|
||||
continue;
|
||||
}
|
||||
int topY = world.getHighestBlockYAt(x, z) + 1;
|
||||
for (int y = topY; y >= Math.max(world.getMinHeight(), topY - 4); y--) {
|
||||
Block block = world.getBlockAt(x, y, z);
|
||||
if (crops.contains(block.getType()) && mature(block)) {
|
||||
return block;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean mature(Block block) {
|
||||
BlockData data = block.getBlockData();
|
||||
return data instanceof Ageable ageable && ageable.getAge() >= ageable.getMaximumAge();
|
||||
}
|
||||
|
||||
private void collectDrops(CoalNpc worker, Collection<ItemStack> drops) throws SQLException {
|
||||
for (ItemStack drop : drops) {
|
||||
if (drop == null || drop.getType().isAir() || drop.getAmount() <= 0) {
|
||||
continue;
|
||||
}
|
||||
repository.addInventory(worker.id(), drop.getType(), drop.getAmount());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean replant(CoalNpc worker, Block block, Material cropType) throws SQLException {
|
||||
Material seed = plantingMaterial(cropType);
|
||||
if (seed == null || repository.inventoryAmount(worker.id(), seed) <= 0L) {
|
||||
return false;
|
||||
}
|
||||
if (!repository.removeInventory(worker.id(), seed, 1L)) {
|
||||
return false;
|
||||
}
|
||||
block.setType(cropType);
|
||||
BlockData data = block.getBlockData();
|
||||
if (data instanceof Ageable ageable) {
|
||||
ageable.setAge(0);
|
||||
block.setBlockData(ageable);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private Material plantingMaterial(Material cropType) {
|
||||
return switch (cropType) {
|
||||
case WHEAT -> Material.WHEAT_SEEDS;
|
||||
case CARROTS -> Material.CARROT;
|
||||
case POTATOES -> Material.POTATO;
|
||||
case BEETROOTS -> Material.BEETROOT_SEEDS;
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
private boolean produce(CoalNpc worker, WorkerRecipe recipe, List<CoalNpc> npcs) throws SQLException {
|
||||
@@ -336,6 +445,10 @@ public final class NpcService {
|
||||
long counter, boolean accepted, String reason) {
|
||||
}
|
||||
|
||||
private record WorkerRecipe(String name, Material output, int outputAmount, Map<Material, Long> inputs) {
|
||||
private record WorkerRecipe(String name, String behavior, Material output, int outputAmount,
|
||||
Map<Material, Long> inputs, List<Material> crops, boolean replant) {
|
||||
private boolean farmBehavior() {
|
||||
return behavior.equalsIgnoreCase("FARM");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,13 +23,24 @@ npc:
|
||||
produce_amount: 2
|
||||
roles:
|
||||
farmer:
|
||||
behavior: FARM
|
||||
output_material: WHEAT
|
||||
output_amount: 4
|
||||
crops:
|
||||
- WHEAT
|
||||
- CARROTS
|
||||
- POTATOES
|
||||
- BEETROOTS
|
||||
replant: true
|
||||
baker:
|
||||
behavior: CRAFT
|
||||
output_material: BREAD
|
||||
output_amount: 2
|
||||
inputs:
|
||||
WHEAT: 3
|
||||
farm:
|
||||
action_distance: 3.0
|
||||
max_scan_blocks: 512
|
||||
supply_chain:
|
||||
max_transfer_per_tick: 64
|
||||
source_reserve: 16
|
||||
|
||||
Reference in New Issue
Block a user