forked from Upstream/VillagerTradeLimiter
Version 1.5.0-pre4:
* Add per-villager restock cooldowns To-do: * Add enchantments, data, etc. to ingredients and result * Add config editor GUI in-game
This commit is contained in:
parent
3aba0ff1c7
commit
8720e840e2
@ -5,6 +5,7 @@ import com.pretzel.dev.villagertradelimiter.commands.CommandBase;
|
||||
import com.pretzel.dev.villagertradelimiter.data.PlayerData;
|
||||
import com.pretzel.dev.villagertradelimiter.database.DatabaseManager;
|
||||
import com.pretzel.dev.villagertradelimiter.listeners.InventoryListener;
|
||||
import com.pretzel.dev.villagertradelimiter.listeners.VillagerListener;
|
||||
import com.pretzel.dev.villagertradelimiter.settings.ConfigUpdater;
|
||||
import com.pretzel.dev.villagertradelimiter.lib.Metrics;
|
||||
import com.pretzel.dev.villagertradelimiter.lib.Util;
|
||||
@ -76,6 +77,7 @@ public class VillagerTradeLimiter extends JavaPlugin {
|
||||
|
||||
//Load/reload database manager
|
||||
if(this.databaseManager == null) this.databaseManager = new DatabaseManager(this);
|
||||
else onDisable();
|
||||
this.databaseManager.load();
|
||||
}
|
||||
|
||||
@ -99,6 +101,7 @@ public class VillagerTradeLimiter extends JavaPlugin {
|
||||
this.playerListener = new PlayerListener(this, settings);
|
||||
this.getServer().getPluginManager().registerEvents(this.playerListener, this);
|
||||
this.getServer().getPluginManager().registerEvents(new InventoryListener(this, settings), this);
|
||||
this.getServer().getPluginManager().registerEvents(new VillagerListener(this, settings), this);
|
||||
}
|
||||
|
||||
|
||||
|
@ -39,10 +39,18 @@ public class Cooldown {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param date The date to format
|
||||
* @return The date as a 'yyyy-MM-dd HH:mm:ss' formatted string
|
||||
*/
|
||||
public static String formatTime(Date date) {
|
||||
return FORMAT.format(date);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param timeStr The string to format, in 'yyyy-MM-dd HH:mm:ss' format
|
||||
* @return The date that the string represents
|
||||
*/
|
||||
public static Date parseTime(final String timeStr) {
|
||||
try {
|
||||
return FORMAT.parse(timeStr);
|
||||
|
@ -4,7 +4,9 @@ import com.pretzel.dev.villagertradelimiter.VillagerTradeLimiter;
|
||||
import com.pretzel.dev.villagertradelimiter.data.Cooldown;
|
||||
import com.pretzel.dev.villagertradelimiter.data.PlayerData;
|
||||
import com.pretzel.dev.villagertradelimiter.lib.Util;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.entity.Villager;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Date;
|
||||
@ -52,18 +54,20 @@ public class DatabaseManager {
|
||||
if(date == null) continue;
|
||||
long time = date.getTime();
|
||||
|
||||
PlayerData playerData = instance.getPlayerData().get(uuid);
|
||||
if(playerData == null) {
|
||||
playerData = new PlayerData();
|
||||
instance.getPlayerData().put(uuid, playerData);
|
||||
PlayerData data = instance.getPlayerData().get(uuid);
|
||||
if(data == null) {
|
||||
data = new PlayerData();
|
||||
instance.getPlayerData().put(uuid, data);
|
||||
}
|
||||
|
||||
String key = (Bukkit.getEntity(uuid) instanceof Villager ? "Restock" : "Cooldown");
|
||||
String cooldownStr = instance.getCfg().getString(key, "0");
|
||||
cooldownStr = instance.getCfg().getString("Overrides."+item+"."+key, cooldownStr);
|
||||
long cooldown = Cooldown.parseCooldown(cooldownStr);
|
||||
|
||||
final Date now = Date.from(Instant.now());
|
||||
final String global = instance.getCfg().getString("Cooldown", "0");
|
||||
final String local = instance.getCfg().getString("Overrides."+item+".Cooldown", global);
|
||||
long cooldown = Cooldown.parseCooldown(local);
|
||||
if(cooldown != 0 && now.getTime()/1000L < time/1000L + cooldown) {
|
||||
playerData.getTradingCooldowns().put(item, Cooldown.formatTime(date));
|
||||
data.getTradingCooldowns().put(item, Cooldown.formatTime(date));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -88,7 +92,7 @@ public class DatabaseManager {
|
||||
|
||||
String values = "";
|
||||
for(String item : playerData.getTradingCooldowns().keySet()) {
|
||||
String time = playerData.getTradingCooldowns().get(item);
|
||||
final String time = playerData.getTradingCooldowns().get(item);
|
||||
|
||||
if(!values.isEmpty()) values += ",";
|
||||
values += "('"+uuid+"','"+item+"','"+time+"')";
|
||||
|
@ -79,13 +79,12 @@ public class InventoryListener implements Listener {
|
||||
if(overrides == null) return;
|
||||
|
||||
final String type = settings.getType(result, ingredient1, ingredient2);
|
||||
if(instance.getCfg().getString("Cooldown", "0").equals("0")) {
|
||||
Util.consoleMsg("global cooldown is 0");
|
||||
if(overrides.getString(type+".Cooldown", "0").equals("0")) {
|
||||
Util.consoleMsg("local cooldown is 0");
|
||||
return;
|
||||
}
|
||||
}
|
||||
String cooldownStr = instance.getCfg().getString("Cooldown", "0");
|
||||
cooldownStr = overrides.getString(type+".Cooldown", cooldownStr);
|
||||
String restockStr = instance.getCfg().getString("Restock", "0");
|
||||
restockStr = overrides.getString(type+".Restock", restockStr);
|
||||
|
||||
if(cooldownStr.equals("0") && restockStr.equals("0")) return;
|
||||
|
||||
//Get the selected recipe by the items in the slots
|
||||
final MerchantRecipe selectedRecipe = getSelectedRecipe((Villager)event.getInventory().getHolder(), ingredient1, ingredient2, result);
|
||||
@ -96,11 +95,18 @@ public class InventoryListener implements Listener {
|
||||
|
||||
//Add a cooldown to the trade if the player has reached the max uses
|
||||
final PlayerData playerData = instance.getPlayerData().get(player.getUniqueId());
|
||||
final PlayerData villagerData = instance.getPlayerData().get(((Villager)event.getInventory().getHolder()).getUniqueId());
|
||||
if(playerData == null || playerData.getTradingVillager() == null) return;
|
||||
Bukkit.getScheduler().runTaskLater(instance, () -> {
|
||||
int uses = selectedRecipe.getUses();
|
||||
if(!playerData.getTradingCooldowns().containsKey(type) && uses >= selectedRecipe.getMaxUses()) {
|
||||
playerData.getTradingCooldowns().put(type, Cooldown.formatTime(Date.from(Instant.now())));
|
||||
final String time = Cooldown.formatTime(Date.from(Instant.now()));
|
||||
if(uses >= selectedRecipe.getMaxUses()) {
|
||||
if(!playerData.getTradingCooldowns().containsKey(type)) {
|
||||
playerData.getTradingCooldowns().put(type, time);
|
||||
}
|
||||
if(villagerData != null && !villagerData.getTradingCooldowns().containsKey(type)) {
|
||||
villagerData.getTradingCooldowns().put(type, time);
|
||||
}
|
||||
}
|
||||
}, 1);
|
||||
}
|
||||
|
@ -67,6 +67,9 @@ public class PlayerListener implements Listener {
|
||||
if(!instance.getPlayerData().containsKey(player.getUniqueId())) {
|
||||
instance.getPlayerData().put(player.getUniqueId(), new PlayerData());
|
||||
}
|
||||
if(!instance.getPlayerData().containsKey(villager.getUniqueId())) {
|
||||
instance.getPlayerData().put(villager.getUniqueId(), new PlayerData());
|
||||
}
|
||||
this.see(villager, player, player);
|
||||
}
|
||||
|
||||
@ -143,6 +146,7 @@ public class PlayerListener implements Listener {
|
||||
* @return The total discount for the recipe, which is added to the base price to get the final price
|
||||
*/
|
||||
private int getDiscount(final RecipeWrapper recipe, int totalReputation, double hotvDiscount) {
|
||||
//Calculates the total discount
|
||||
int basePrice = getBasePrice(recipe);
|
||||
int demand = getDemand(recipe);
|
||||
float priceMultiplier = recipe.getPriceMultiplier();
|
||||
@ -150,10 +154,12 @@ public class PlayerListener implements Listener {
|
||||
|
||||
double maxDiscount = settings.fetchDouble(recipe, "MaxDiscount", 0.3);
|
||||
if(maxDiscount >= 0.0 && maxDiscount <= 1.0) {
|
||||
//Change the discount to the smaller MaxDiscount
|
||||
if(basePrice + discount < basePrice * (1.0 - maxDiscount)) {
|
||||
discount = -(int)(basePrice * maxDiscount);
|
||||
}
|
||||
} else if(maxDiscount > 1.0) {
|
||||
//Change the discount to the larger MaxDiscount
|
||||
//TODO: Allow for better fine-tuning
|
||||
discount = (int)(discount * maxDiscount);
|
||||
}
|
||||
@ -169,6 +175,7 @@ public class PlayerListener implements Listener {
|
||||
int maxUses = settings.fetchInt(recipe, "MaxUses", -1);
|
||||
boolean disabled = settings.fetchBoolean(recipe, "Disabled", false);
|
||||
|
||||
//Disables the trade if the player has an active cooldown for the trade
|
||||
final PlayerData playerData = instance.getPlayerData().get(player.getUniqueId());
|
||||
if(playerData != null && playerData.getTradingVillager() != null) {
|
||||
final ConfigurationSection overrides = instance.getCfg().getConfigurationSection("Overrides");
|
||||
@ -210,6 +217,7 @@ public class PlayerListener implements Listener {
|
||||
final PotionEffect effect = player.getPotionEffect(effectType);
|
||||
if(effect == null) return 0.0;
|
||||
|
||||
//Calculates the discount factor from the player's current effect level or the defined maximum
|
||||
int heroLevel = effect.getAmplifier()+1;
|
||||
final int maxHeroLevel = instance.getCfg().getInt("MaxHeroLevel", -1);
|
||||
if(maxHeroLevel == 0 || heroLevel == 0) return 0.0;
|
||||
|
@ -0,0 +1,69 @@
|
||||
package com.pretzel.dev.villagertradelimiter.listeners;
|
||||
|
||||
import com.pretzel.dev.villagertradelimiter.VillagerTradeLimiter;
|
||||
import com.pretzel.dev.villagertradelimiter.data.Cooldown;
|
||||
import com.pretzel.dev.villagertradelimiter.data.PlayerData;
|
||||
import com.pretzel.dev.villagertradelimiter.lib.Util;
|
||||
import com.pretzel.dev.villagertradelimiter.settings.Settings;
|
||||
import org.bukkit.entity.Villager;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.VillagerReplenishTradeEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.MerchantRecipe;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
|
||||
public class VillagerListener implements Listener {
|
||||
private final VillagerTradeLimiter instance;
|
||||
private final Settings settings;
|
||||
|
||||
/**
|
||||
* @param instance The instance of VillagerTradeLimiter.java
|
||||
* @param settings The settings instance
|
||||
*/
|
||||
public VillagerListener(final VillagerTradeLimiter instance, final Settings settings) {
|
||||
this.instance = instance;
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
/** Handles villager restocks */
|
||||
@EventHandler
|
||||
public void onVillagerRestock(final VillagerReplenishTradeEvent event) {
|
||||
if(!(event.getEntity() instanceof Villager)) return;
|
||||
if(Util.isNPC((Villager) event.getEntity())) return;
|
||||
|
||||
//Get the items involved in the restock
|
||||
final MerchantRecipe recipe = event.getRecipe();
|
||||
final ItemStack result = recipe.getResult();
|
||||
ItemStack ingredient1 = recipe.getIngredients().get(0);
|
||||
ItemStack ingredient2 = recipe.getIngredients().get(1);
|
||||
final String type = settings.getType(result, ingredient1, ingredient2);
|
||||
|
||||
//Get the villager's data container
|
||||
final UUID uuid = event.getEntity().getUniqueId();
|
||||
final PlayerData villagerData = instance.getPlayerData().get(uuid);
|
||||
if(villagerData == null) return;
|
||||
|
||||
//Get the time of the last trade, restock cooldown setting, and now
|
||||
final String lastTradeStr = villagerData.getTradingCooldowns().get(type);
|
||||
if(lastTradeStr == null) return;
|
||||
|
||||
String cooldownStr = instance.getCfg().getString("Restock", "0");
|
||||
cooldownStr = instance.getCfg().getString("Overrides."+type+".Restock", cooldownStr);
|
||||
|
||||
final Date now = Date.from(Instant.now());
|
||||
final Date lastTrade = Cooldown.parseTime(lastTradeStr);
|
||||
if(lastTrade == null) return;
|
||||
final long cooldown = Cooldown.parseCooldown(cooldownStr);
|
||||
|
||||
//Cancel the event if there is an active restock cooldown, otherwise remove the restock cooldown
|
||||
if(now.getTime()/1000L >= lastTrade.getTime()/1000L + cooldown) {
|
||||
villagerData.getTradingCooldowns().remove(type);
|
||||
} else {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
@ -61,6 +61,12 @@ MaxUses: -1
|
||||
# * w = weeks (e.g. 2w)
|
||||
Cooldown: 0
|
||||
|
||||
# The per-villager, per-trade cooldown in real-world time.
|
||||
# This is the same as Cooldown, but applies to a villager's restocking function
|
||||
# * Set to 0 to disable this feature and keep vanilla behavior
|
||||
# * Set to a number and interval to add a per-villager, per-trade cooldown for all trades (see below)
|
||||
Restock: 0
|
||||
|
||||
|
||||
#-------------------------------- PER-ITEM SETTINGS --------------------------------#
|
||||
# Override the global settings for individual items. To disable, set like this --> Overrides: none
|
||||
@ -91,4 +97,5 @@ Overrides:
|
||||
clock:
|
||||
MaxDemand: 12
|
||||
paper:
|
||||
Disabled: true
|
||||
MaxUses: 1
|
||||
Restock: 1h
|
Loading…
Reference in New Issue
Block a user