Add Coal Cents economy
This commit is contained in:
@@ -0,0 +1,218 @@
|
||||
package com.librewiki.coalgov.service;
|
||||
|
||||
import com.librewiki.coalgov.CoalGovPlugin;
|
||||
import com.librewiki.coalgov.model.ClaimPoint;
|
||||
import com.librewiki.coalgov.model.CoalNpc;
|
||||
import com.librewiki.coalgov.model.NpcZone;
|
||||
import com.librewiki.coalgov.storage.NpcRepository;
|
||||
import com.librewiki.coalgov.util.CoalMoney;
|
||||
import net.citizensnpcs.api.CitizensAPI;
|
||||
import net.citizensnpcs.api.npc.NPC;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
|
||||
public final class NpcService {
|
||||
private final CoalGovPlugin plugin;
|
||||
private final NpcRepository repository;
|
||||
private final Random random = new Random();
|
||||
|
||||
public NpcService(CoalGovPlugin plugin, NpcRepository repository) {
|
||||
this.plugin = plugin;
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
public long createZone(String name, String world, List<ClaimPoint> points) throws SQLException {
|
||||
return repository.createZone(name, world, points);
|
||||
}
|
||||
|
||||
public long createNpc(String type, String name, NpcZone zone, Location location) throws SQLException {
|
||||
NPC npc = CitizensAPI.getNPCRegistry().createNPC(EntityType.VILLAGER, name);
|
||||
npc.spawn(location);
|
||||
npc.setProtected(true);
|
||||
UUID accountUuid = UUID.nameUUIDFromBytes(("coalgov:npc:" + npc.getId()).getBytes(StandardCharsets.UTF_8));
|
||||
plugin.economyService().ensureAccount(accountUuid, "NPC-" + name);
|
||||
return repository.createNpc(npc.getId(), accountUuid, type, name, zone.id(),
|
||||
location.getWorld().getName(), location.getX(), location.getY(), location.getZ());
|
||||
}
|
||||
|
||||
public boolean removeNpc(long id) throws SQLException {
|
||||
Optional<CoalNpc> coalNpc = repository.findNpc(id);
|
||||
if (coalNpc.isPresent()) {
|
||||
NPC npc = CitizensAPI.getNPCRegistry().getById(coalNpc.get().citizensId());
|
||||
if (npc != null) {
|
||||
npc.destroy();
|
||||
}
|
||||
}
|
||||
return repository.deleteNpc(id);
|
||||
}
|
||||
|
||||
public Optional<CoalNpc> findNpc(long id) throws SQLException {
|
||||
return repository.findNpc(id);
|
||||
}
|
||||
|
||||
public Optional<CoalNpc> findByCitizensId(int citizensId) throws SQLException {
|
||||
return repository.findByCitizensId(citizensId);
|
||||
}
|
||||
|
||||
public Optional<NpcZone> findZone(String name) throws SQLException {
|
||||
return repository.findZone(name);
|
||||
}
|
||||
|
||||
public List<CoalNpc> listNpcs() throws SQLException {
|
||||
return repository.listNpcs();
|
||||
}
|
||||
|
||||
public List<NpcZone> listZones() throws SQLException {
|
||||
return repository.listZones();
|
||||
}
|
||||
|
||||
public Map<Material, Long> inventory(long npcId) throws SQLException {
|
||||
return repository.inventory(npcId);
|
||||
}
|
||||
|
||||
public void addInventory(long npcId, Material material, long amount) throws SQLException {
|
||||
repository.addInventory(npcId, material, amount);
|
||||
}
|
||||
|
||||
public long balance(CoalNpc npc) throws SQLException {
|
||||
return plugin.economyService().balance(npc.accountUuid());
|
||||
}
|
||||
|
||||
public HaggleQuote quote(CoalNpc npc, String mode, Material material, int amount, long offer) throws SQLException {
|
||||
double base = plugin.marketService().basePrices().getOrDefault(material, 1.0D);
|
||||
long fair = Math.max(1L, CoalMoney.fromCoal(base * amount));
|
||||
int maxDiscount = plugin.getConfig().getInt("npc.trader.max_discount_percent", 15);
|
||||
int maxSurcharge = plugin.getConfig().getInt("npc.trader.max_surcharge_percent", 20);
|
||||
if (mode.equalsIgnoreCase("buy")) {
|
||||
long stock = repository.inventoryAmount(npc.id(), material);
|
||||
long listPrice = Math.max(1L, Math.round(fair * 1.10D));
|
||||
long minimum = Math.max(1L, Math.round(listPrice * (100.0D - maxDiscount) / 100.0D));
|
||||
long counter = Math.max(minimum, Math.min(listPrice, offer <= 0L ? listPrice : Math.round((offer + listPrice) / 2.0D)));
|
||||
boolean possible = stock >= amount;
|
||||
boolean accepted = possible && offer >= minimum;
|
||||
return new HaggleQuote(mode.toLowerCase(), material, amount, offer, minimum, listPrice, counter, accepted, possible ? "" : "I do not have enough stock.");
|
||||
}
|
||||
long maximum = Math.max(1L, Math.round(fair * (100.0D + maxSurcharge) / 100.0D));
|
||||
long target = Math.max(1L, Math.round(fair * 0.90D));
|
||||
long counter = Math.min(maximum, Math.max(target, offer <= 0L ? target : Math.round((offer + target) / 2.0D)));
|
||||
boolean possible = balance(npc) >= offer;
|
||||
boolean accepted = possible && offer <= maximum;
|
||||
return new HaggleQuote(mode.toLowerCase(), material, amount, offer, target, maximum, counter, accepted, possible ? "" : "I do not have enough coal.");
|
||||
}
|
||||
|
||||
public boolean completeTrade(Player player, CoalNpc npc, HaggleQuote quote, long finalPrice) throws SQLException {
|
||||
if (quote.mode().equals("buy")) {
|
||||
if (repository.inventoryAmount(npc.id(), quote.material()) < quote.amount()) {
|
||||
return false;
|
||||
}
|
||||
if (!plugin.economyService().charge(player.getUniqueId(), finalPrice, "npc_purchase")) {
|
||||
return false;
|
||||
}
|
||||
repository.removeInventory(npc.id(), quote.material(), quote.amount());
|
||||
plugin.economyService().credit(npc.accountUuid(), finalPrice, "npc_sale");
|
||||
player.getInventory().addItem(new ItemStack(quote.material(), quote.amount()));
|
||||
return true;
|
||||
}
|
||||
if (!playerHas(player, quote.material(), quote.amount()) || balance(npc) < finalPrice) {
|
||||
return false;
|
||||
}
|
||||
if (!plugin.economyService().charge(npc.accountUuid(), finalPrice, "npc_purchase")) {
|
||||
return false;
|
||||
}
|
||||
removePlayerItems(player, quote.material(), quote.amount());
|
||||
plugin.economyService().credit(player.getUniqueId(), finalPrice, "npc_sale");
|
||||
repository.addInventory(npc.id(), quote.material(), quote.amount());
|
||||
return true;
|
||||
}
|
||||
|
||||
public void tickWorkers() {
|
||||
try {
|
||||
for (CoalNpc coalNpc : repository.listNpcs()) {
|
||||
if (!coalNpc.worker()) {
|
||||
continue;
|
||||
}
|
||||
NPC npc = CitizensAPI.getNPCRegistry().getById(coalNpc.citizensId());
|
||||
Optional<NpcZone> zone = repository.findZone(coalNpc.zoneId());
|
||||
if (npc == null || zone.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
if (!npc.isSpawned()) {
|
||||
World world = Bukkit.getWorld(coalNpc.world());
|
||||
if (world != null) {
|
||||
npc.spawn(new Location(world, coalNpc.x(), coalNpc.y(), coalNpc.z()));
|
||||
}
|
||||
}
|
||||
if (npc.isSpawned() && !npc.getNavigator().isNavigating()) {
|
||||
Location target = randomPoint(zone.get());
|
||||
if (target != null) {
|
||||
npc.getNavigator().setTarget(target);
|
||||
}
|
||||
}
|
||||
Material material = Material.matchMaterial(plugin.getConfig().getString("npc.worker.produce_material", "BREAD"));
|
||||
int amount = plugin.getConfig().getInt("npc.worker.produce_amount", 2);
|
||||
if (material != null && amount > 0) {
|
||||
repository.addInventory(coalNpc.id(), material, amount);
|
||||
}
|
||||
}
|
||||
} catch (SQLException exception) {
|
||||
plugin.getLogger().warning("NPC worker tick failed: " + exception.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private Location randomPoint(NpcZone zone) {
|
||||
World world = Bukkit.getWorld(zone.world());
|
||||
if (world == null) {
|
||||
return null;
|
||||
}
|
||||
for (int tries = 0; tries < 32; tries++) {
|
||||
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)) {
|
||||
return new Location(world, x + 0.5D, world.getHighestBlockYAt(x, z), z + 0.5D);
|
||||
}
|
||||
}
|
||||
return new Location(world, zone.x1() + 0.5D, world.getHighestBlockYAt(zone.x1(), zone.z1()), zone.z1() + 0.5D);
|
||||
}
|
||||
|
||||
private boolean playerHas(Player player, Material material, int amount) {
|
||||
int found = 0;
|
||||
for (ItemStack item : player.getInventory().getStorageContents()) {
|
||||
if (item != null && item.getType() == material) {
|
||||
found += item.getAmount();
|
||||
}
|
||||
}
|
||||
return found >= amount;
|
||||
}
|
||||
|
||||
private void removePlayerItems(Player player, Material material, int amount) {
|
||||
int remaining = amount;
|
||||
for (ItemStack item : player.getInventory().getStorageContents()) {
|
||||
if (item == null || item.getType() != material) {
|
||||
continue;
|
||||
}
|
||||
int take = Math.min(remaining, item.getAmount());
|
||||
item.setAmount(item.getAmount() - take);
|
||||
remaining -= take;
|
||||
if (remaining <= 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public record HaggleQuote(String mode, Material material, int amount, long offer, long floor, long ceiling,
|
||||
long counter, boolean accepted, String reason) {
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user