Version 1.3.0:

* Added per-world disabled trading
* Added per-item disabled trading
This commit is contained in:
PretzelJohn 2021-09-16 01:35:21 -04:00
parent 960fd1c535
commit 589efcbfdb
9 changed files with 75 additions and 29 deletions

View File

@ -63,7 +63,13 @@
</tr> </tr>
<tr> <tr>
<td><code>DisableTrading:</code></td> <td><code>DisableTrading:</code></td>
<td>Set this to true if you want to completely disable ALL villager trading.</td> <td>Whether to disable all villager trading for all worlds, some worlds, or no worlds. Options:
<ul>
<li>Add world names for worlds that you want to completely disable ALL villager trading.</li>
<li>Set to true to disable trading in all worlds.</li>
<li>Set to false or [] to disable this feature.</li>
</ul>
</td>
</tr> </tr>
<tr> <tr>
<td><code>MaxHeroLevel:</code></td> <td><code>MaxHeroLevel:</code></td>
@ -106,13 +112,17 @@
<td><code>&lt;item_name&gt;:</code></td> <td><code>&lt;item_name&gt;:</code></td>
<td>Override the global settings by adding as many of these as you need. Enchanted books must follow the format of <code>name_level</code> (mending_1). All other items must follow the format of <code>item_name</code> (stone_bricks).</td> <td>Override the global settings by adding as many of these as you need. Enchanted books must follow the format of <code>name_level</code> (mending_1). All other items must follow the format of <code>item_name</code> (stone_bricks).</td>
</tr> </tr>
<tr>
<td><code>.Disabled:</code></td>
<td>Disables any trade that contains the item (true/false)</td>
</tr>
<tr> <tr>
<td><code>.MaxDiscount:</code></td> <td><code>.MaxDiscount:</code></td>
<td>Sets the maximum discount for this item</td> <td>Sets the maximum discount for this item (-1.0, or between 0.0 to 1.0)</td>
</tr> </tr>
<tr> <tr>
<td><code>.MaxDemand:</code></td> <td><code>.MaxDemand:</code></td>
<td>Sets the maximum demand for this item</td> <td>Sets the maximum demand for this item (-1, or 0+)</td>
</tr> </tr>
</table> </table>
</li> </li>

View File

@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>com.pretzel.dev</groupId> <groupId>com.pretzel.dev</groupId>
<artifactId>VillagerTradeLimiter</artifactId> <artifactId>VillagerTradeLimiter</artifactId>
<version>1.2.1</version> <version>1.3.0</version>
<properties> <properties>
<java.version>1.8</java.version> <java.version>1.8</java.version>

View File

@ -54,10 +54,10 @@ public class VillagerTradeLimiter extends JavaPlugin {
//Registers plugin commands //Registers plugin commands
private void registerCommands() { private void registerCommands() {
final String reloaded = Util.replaceColors("&eVillagerTradeLimiter &ahas been reloaded!"); final String reloaded = Util.replaceColors("&eVillagerTradeLimiter &ahas been reloaded!");
final CommandBase vtl = new CommandBase("villagertradelimiter", "villagertradelimiter.use", p -> this.help(p)); final CommandBase vtl = new CommandBase("villagertradelimiter", "villagertradelimiter.use", (p,args) -> this.help(p));
vtl.addSub(new CommandBase("reload", "villagertradelimiter.reload", p -> { vtl.addSub(new CommandBase("reload", "villagertradelimiter.reload", (p,args) -> {
loadSettings(); loadSettings();
if(p != null) p.sendMessage(reloaded); Util.sendMsg(reloaded, p);
})); }));
this.getCommand("villagertradelimiter").setExecutor(vtl); this.getCommand("villagertradelimiter").setExecutor(vtl);
this.getCommand("villagertradelimiter").setTabCompleter(vtl); this.getCommand("villagertradelimiter").setTabCompleter(vtl);

View File

@ -1,5 +1,5 @@
package com.pretzel.dev.villagertradelimiter.lib; package com.pretzel.dev.villagertradelimiter.lib;
public interface Callback<T> { public interface Callback<T> {
void call(T result); void call(T result, String[] args);
} }

View File

@ -1,5 +1,6 @@
package com.pretzel.dev.villagertradelimiter.lib; package com.pretzel.dev.villagertradelimiter.lib;
import org.bukkit.Bukkit;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
@ -32,8 +33,8 @@ public class CommandBase implements CommandExecutor, TabCompleter {
final Player player = (sender instanceof Player ? (Player)sender : null); final Player player = (sender instanceof Player ? (Player)sender : null);
if(player != null && !player.hasPermission(this.permission) && !this.permission.isEmpty()) return false; if(player != null && !player.hasPermission(this.permission) && !this.permission.isEmpty()) return false;
if(args.length == 0) { if(args.length == 0 || (args.length == 1 && subs.size() == 0)) {
this.callback.call(player); this.callback.call(player, args);
return true; return true;
} }
@ -54,6 +55,7 @@ public class CommandBase implements CommandExecutor, TabCompleter {
final List<String> list = new ArrayList<>(); final List<String> list = new ArrayList<>();
if(args.length == 0) return null; if(args.length == 0) return null;
if(args.length == 1) { if(args.length == 1) {
if(subs.size() == 0) return getPlayerList();
for(CommandBase cmd : subs) for(CommandBase cmd : subs)
if(player.hasPermission(cmd.getPermission())) if(player.hasPermission(cmd.getPermission()))
list.add(cmd.getName()); list.add(cmd.getName());
@ -73,6 +75,13 @@ public class CommandBase implements CommandExecutor, TabCompleter {
return res; return res;
} }
private static List<String> getPlayerList() {
final List<String> players = new ArrayList<>();
for(Player p : Bukkit.getOnlinePlayers())
players.add(p.getName());
return players;
}
public String getName() { return this.name; } public String getName() { return this.name; }
public String getPermission() { return this.permission; } public String getPermission() { return this.permission; }
} }

View File

@ -29,7 +29,7 @@ public class ConfigUpdater {
} }
public FileConfiguration updateConfig(File file, String prefix) { public FileConfiguration updateConfig(File file, String prefix) {
final FileConfiguration cfg = (FileConfiguration)YamlConfiguration.loadConfiguration(file); final FileConfiguration cfg = YamlConfiguration.loadConfiguration(file);
if(this.isUpdated()) return cfg; if(this.isUpdated()) return cfg;
Util.consoleMsg(prefix+"Updating config.yml..."); Util.consoleMsg(prefix+"Updating config.yml...");
@ -49,14 +49,13 @@ public class ConfigUpdater {
} }
out += line+"\n"; out += line+"\n";
boolean found = false; boolean found = false;
for(int j = 0; j < cfgActive.length; j++) { for(String line2 : cfgActive) {
String line2 = cfgActive[j];
if (line2.startsWith(" ") && !line2.replace(" ", "").isEmpty()) { if (line2.startsWith(" ") && !line2.replace(" ", "").isEmpty()) {
out += line2 + "\n"; out += line2 + "\n";
found = true; found = true;
} }
} }
if(found == false) { if(!found) {
while(i < cfgDefault.length-1) { while(i < cfgDefault.length-1) {
i++; i++;
String line2 = cfgDefault[i]; String line2 = cfgDefault[i];
@ -68,7 +67,7 @@ public class ConfigUpdater {
} }
} }
Util.writeFile(file, out+"\n"); Util.writeFile(file, out+"\n");
return (FileConfiguration)YamlConfiguration.loadConfiguration(file); return YamlConfiguration.loadConfiguration(file);
} }
public boolean isUpdated() { public boolean isUpdated() {

View File

@ -19,10 +19,11 @@ import org.bukkit.inventory.meta.EnchantmentStorageMeta;
import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType; import org.bukkit.potion.PotionEffectType;
import java.util.ArrayList;
import java.util.List; import java.util.List;
public class PlayerListener implements Listener { public class PlayerListener implements Listener {
private static final Material[] MATERIALS = new Material[] { Material.IRON_HELMET, Material.IRON_CHESTPLATE, Material.IRON_LEGGINGS, Material.IRON_BOOTS, Material.BELL, Material.CHAINMAIL_HELMET, Material.CHAINMAIL_CHESTPLATE, Material.CHAINMAIL_LEGGINGS, Material.CHAINMAIL_BOOTS, Material.SHIELD, Material.DIAMOND_HELMET, Material.DIAMOND_CHESTPLATE, Material.DIAMOND_LEGGINGS, Material.DIAMOND_BOOTS, Material.FILLED_MAP, Material.FISHING_ROD, Material.LEATHER_HELMET, Material.LEATHER_CHESTPLATE, Material.LEATHER_LEGGINGS, Material.LEATHER_BOOTS, Material.LEATHER_HORSE_ARMOR, Material.SADDLE, Material.ENCHANTED_BOOK, Material.STONE_AXE, Material.STONE_SHOVEL, Material.STONE_PICKAXE, Material.STONE_HOE, Material.IRON_AXE, Material.IRON_SHOVEL, Material.IRON_PICKAXE, Material.DIAMOND_AXE, Material.DIAMOND_SHOVEL, Material.DIAMOND_PICKAXE, Material.DIAMOND_HOE, Material.IRON_SWORD, Material.DIAMOND_SWORD }; private static final Material[] MATERIALS = new Material[] { Material.IRON_HELMET, Material.IRON_CHESTPLATE, Material.IRON_LEGGINGS, Material.IRON_BOOTS, Material.BELL, Material.CHAINMAIL_HELMET, Material.CHAINMAIL_CHESTPLATE, Material.CHAINMAIL_LEGGINGS, Material.CHAINMAIL_BOOTS, Material.SHIELD, Material.DIAMOND_HELMET, Material.DIAMOND_CHESTPLATE, Material.DIAMOND_LEGGINGS, Material.DIAMOND_BOOTS, Material.FILLED_MAP, Material.FISHING_ROD, Material.LEATHER_HELMET, Material.LEATHER_CHESTPLATE, Material.LEATHER_LEGGINGS, Material.LEATHER_BOOTS, Material.LEATHER_HORSE_ARMOR, Material.SADDLE, Material.ENCHANTED_BOOK, Material.STONE_AXE, Material.STONE_SHOVEL, Material.STONE_PICKAXE, Material.STONE_HOE, Material.IRON_AXE, Material.IRON_SHOVEL, Material.IRON_PICKAXE, Material.DIAMOND_AXE, Material.DIAMOND_SHOVEL, Material.DIAMOND_PICKAXE, Material.DIAMOND_HOE, Material.IRON_SWORD, Material.DIAMOND_SWORD, Material.NETHERITE_AXE, Material.NETHERITE_HOE, Material.NETHERITE_PICKAXE, Material.NETHERITE_SHOVEL, Material.NETHERITE_SWORD, Material.NETHERITE_HELMET, Material.NETHERITE_CHESTPLATE, Material.NETHERITE_LEGGINGS, Material.NETHERITE_BOOTS };
private final VillagerTradeLimiter instance; private final VillagerTradeLimiter instance;
private final NMS nms; private final NMS nms;
@ -39,10 +40,22 @@ public class PlayerListener implements Listener {
if(Util.isNPC(villager)) return; //Skips NPCs if(Util.isNPC(villager)) return; //Skips NPCs
if(villager.getProfession() == Villager.Profession.NONE || villager.getProfession() == Villager.Profession.NITWIT) return; //Skips non-trading villagers if(villager.getProfession() == Villager.Profession.NONE || villager.getProfession() == Villager.Profession.NITWIT) return; //Skips non-trading villagers
if(villager.getRecipeCount() == 0) return; //Skips non-trading villagers if(villager.getRecipeCount() == 0) return; //Skips non-trading villagers
//DisableTrading feature
if(instance.getCfg().isBoolean("DisableTrading")) {
if(instance.getCfg().getBoolean("DisableTrading", false)) { if(instance.getCfg().getBoolean("DisableTrading", false)) {
event.setCancelled(true); event.setCancelled(true);
return; return;
} }
} else {
List<String> disabledWorlds = instance.getCfg().getStringList("DisableTrading");
for(String world : disabledWorlds) {
if(event.getPlayer().getWorld().getName().equals(world)) {
event.setCancelled(true);
return;
}
}
}
final Player player = event.getPlayer(); final Player player = event.getPlayer();
if(Util.isNPC(player)) return; //Skips NPCs if(Util.isNPC(player)) return; //Skips NPCs
@ -51,6 +64,7 @@ public class PlayerListener implements Listener {
this.maxDemand(villager); this.maxDemand(villager);
} }
//Hero of the Village effect limiter feature
private void hotv(final Player player) { private void hotv(final Player player) {
final PotionEffectType effect = PotionEffectType.HERO_OF_THE_VILLAGE; final PotionEffectType effect = PotionEffectType.HERO_OF_THE_VILLAGE;
if(!player.hasPotionEffect(effect)) return; //Skips when player doesn't have HotV if(!player.hasPotionEffect(effect)) return; //Skips when player doesn't have HotV
@ -66,6 +80,7 @@ public class PlayerListener implements Listener {
} }
} }
//MaxDiscount feature - limits the lowest discounted price to a % of the base price
private void maxDiscount(final Villager villager, final Player player) { private void maxDiscount(final Villager villager, final Player player) {
final List<MerchantRecipe> recipes = villager.getRecipes(); final List<MerchantRecipe> recipes = villager.getRecipes();
int a = 0, b = 0, c = 0, d = 0, e = 0; int a = 0, b = 0, c = 0, d = 0, e = 0;
@ -92,16 +107,20 @@ public class PlayerListener implements Listener {
} }
} }
final ConfigurationSection overrides = instance.getCfg().getConfigurationSection("Overrides"); final ConfigurationSection overrides = instance.getCfg().getConfigurationSection("Overrides");
final ArrayList<MerchantRecipe> finalRecipes = new ArrayList<>();
for (final MerchantRecipe recipe : recipes) { for (final MerchantRecipe recipe : recipes) {
final int x = recipe.getIngredients().get(0).getAmount(); final int x = recipe.getIngredients().get(0).getAmount();
final float p0 = this.getPriceMultiplier(recipe); final float p0 = this.getPriceMultiplier(recipe);
final int w = 5 * a + b + c - d - 5 * e; final int w = 5 * a + b + c - d - 5 * e;
final float y = x - p0 * w; final float y = x - p0 * w;
boolean disabled = false;
double maxDiscount = instance.getCfg().getDouble("MaxDiscount", 0.3); double maxDiscount = instance.getCfg().getDouble("MaxDiscount", 0.3);
if(overrides != null) { if(overrides != null) {
for(final String k : overrides.getKeys(false)) { for(final String k : overrides.getKeys(false)) {
final ConfigurationSection item = this.getItem(recipe, k); final ConfigurationSection item = this.getItem(recipe, k);
if(item != null) { if(item != null) {
disabled = item.getBoolean("Disabled", false);
maxDiscount = item.getDouble("MaxDiscount", maxDiscount); maxDiscount = item.getDouble("MaxDiscount", maxDiscount);
break; break;
} }
@ -116,9 +135,13 @@ public class PlayerListener implements Listener {
} else { } else {
recipe.setPriceMultiplier(p0); recipe.setPriceMultiplier(p0);
} }
if(!disabled) finalRecipes.add(recipe);
} }
villager.setRecipes(finalRecipes);
Bukkit.getScheduler().runTaskLater(instance, () -> villager.setRecipes(recipes), 0);
} }
//MaxDemand feature - limits demand-based price increases
private void maxDemand(final Villager villager) { private void maxDemand(final Villager villager) {
List<MerchantRecipe> recipes = villager.getRecipes(); List<MerchantRecipe> recipes = villager.getRecipes();
final NBTContainer vnbt = new NBTContainer(this.nms, villager); final NBTContainer vnbt = new NBTContainer(this.nms, villager);
@ -147,6 +170,7 @@ public class PlayerListener implements Listener {
vnbt.saveTag(villager, vtag); vnbt.saveTag(villager, vtag);
} }
//Returns the price multiplier for a given trade
private float getPriceMultiplier(final MerchantRecipe recipe) { private float getPriceMultiplier(final MerchantRecipe recipe) {
float p = 0.05f; float p = 0.05f;
final Material type = recipe.getResult().getType(); final Material type = recipe.getResult().getType();
@ -159,6 +183,7 @@ public class PlayerListener implements Listener {
return p; return p;
} }
//Returns the configured settings for a trade
private ConfigurationSection getItem(final MerchantRecipe recipe, final String k) { private ConfigurationSection getItem(final MerchantRecipe recipe, final String k) {
final ConfigurationSection item = instance.getCfg().getConfigurationSection("Overrides."+k); final ConfigurationSection item = instance.getCfg().getConfigurationSection("Overrides."+k);
if(item == null) return null; if(item == null) return null;
@ -176,6 +201,7 @@ public class PlayerListener implements Listener {
if(recipe.getResult().getType() != Material.ENCHANTED_BOOK) return null; if(recipe.getResult().getType() != Material.ENCHANTED_BOOK) return null;
final EnchantmentStorageMeta meta = (EnchantmentStorageMeta)recipe.getResult().getItemMeta(); final EnchantmentStorageMeta meta = (EnchantmentStorageMeta)recipe.getResult().getItemMeta();
final Enchantment enchantment = EnchantmentWrapper.getByKey(NamespacedKey.minecraft(k.substring(0, k.lastIndexOf("_")))); final Enchantment enchantment = EnchantmentWrapper.getByKey(NamespacedKey.minecraft(k.substring(0, k.lastIndexOf("_"))));
if(meta == null || enchantment == null) return null;
if(meta.hasStoredEnchant(enchantment) && meta.getStoredEnchantLevel(enchantment) == level) return item; if(meta.hasStoredEnchant(enchantment) && meta.getStoredEnchantLevel(enchantment) == level) return item;
return null; return null;
} catch(NumberFormatException e) { } catch(NumberFormatException e) {

View File

@ -1,6 +1,6 @@
#---------------------------------------------------------------------------------# #---------------------------------------------------------------------------------#
# VTL ~ VillagerTradeLimiter # # VTL ~ VillagerTradeLimiter #
# Version: 1.2.1 # # Version: 1.3.0 #
# By: PretzelJohn # # By: PretzelJohn #
#---------------------------------------------------------------------------------# #---------------------------------------------------------------------------------#
@ -9,8 +9,10 @@
# This helps me keep track of what server versions are being used. Please leave this set to true. # This helps me keep track of what server versions are being used. Please leave this set to true.
bStats: true bStats: true
# Set this to true if you want to completely disable ALL villager trading. # Add world names for worlds that you want to completely disable ALL villager trading. Set to [] to disable this feature.
DisableTrading: false DisableTrading:
- world_nether
- world_the_end
# The maximum level of the "Hero of the Village" (HotV) effect that a player can have. This limits HotV price decreases. # The maximum level of the "Hero of the Village" (HotV) effect that a player can have. This limits HotV price decreases.
# * Set to -1 to disable this feature and keep vanilla behavior. # * Set to -1 to disable this feature and keep vanilla behavior.
@ -34,7 +36,7 @@ MaxDemand: -1
# To enable, add items below! # To enable, add items below!
# * Enchanted books must follow the format: enchantment_name_level (ex: mending_1) # * Enchanted books must follow the format: enchantment_name_level (ex: mending_1)
# * All other items must follow the format: item_name (ex: stone_bricks) # * All other items must follow the format: item_name (ex: stone_bricks)
# For each item you add, you can override MaxDiscount and/or MaxDemand. # For each item you add, you can disable the trade (set Disabled: true), or override MaxDiscount and/or MaxDemand.
Overrides: Overrides:
mending_1: mending_1:
MaxDiscount: 0.1 MaxDiscount: 0.1
@ -47,4 +49,4 @@ Overrides:
clock: clock:
MaxDemand: 12 MaxDemand: 12
paper: paper:
MaxDiscount: 0.1 Disabled: true

View File

@ -1,7 +1,7 @@
name: VillagerTradeLimiter name: VillagerTradeLimiter
author: PretzelJohn author: PretzelJohn
main: com.pretzel.dev.villagertradelimiter.VillagerTradeLimiter main: com.pretzel.dev.villagertradelimiter.VillagerTradeLimiter
version: 1.2.1 version: 1.3.0
api-version: 1.14 api-version: 1.14
commands: commands: