Players without the permission to edit regular villagers will silently

access the regular trading interface now when they sneak and right-click
a regular villager.
master
blablubbabc 2020-10-28 01:17:24 +01:00
parent 47264cab00
commit 7b7f1e3bfb
2 changed files with 91 additions and 63 deletions

View File

@ -9,6 +9,7 @@ Date format: (YYYY-MM-DD)
* Minor changes to handling failures when trying to create a shopkeeper via Citizens trait. We always inform the player (if there is one), log a warning and delete the trait again now.
* Config: Added some more examples for the 'name-regex' setting to the default config.
* Fixed: Some messages would print an empty line when set to an empty text, instead of being disabled.
* Changed: Players without the permission to edit regular villagers will silently access the regular trading interface now when they sneak and right-click a regular villager.
API:
* PlayerOpenUIEvent indicates whether the UI request has been silent now.

View File

@ -3,6 +3,7 @@ package com.nisovin.shopkeepers.villagers;
import java.util.Map;
import org.bukkit.entity.AbstractVillager;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.entity.Villager;
import org.bukkit.entity.WanderingTrader;
@ -66,39 +67,55 @@ public class VillagerInteractionListener implements Listener {
if (event.getHand() != EquipmentSlot.HAND) return;
Player player = event.getPlayer();
if (player.isSneaking()
&& ((isVillager && Settings.editRegularVillagers) || (isWanderingTrader && Settings.editRegularWanderingTraders))) {
// Open the villager editor:
// Note: This will check if the player has the permission to edit villagers.
boolean overrideTrading = false;
if (this.handleEditRegularVillager(player, villager)) {
// Villager editor for regular villagers.
overrideTrading = true;
} else if (this.handleHireOtherVillager(player, villager)) {
// Hiring of regular villagers.
overrideTrading = true;
}
if (overrideTrading) {
// The villager interaction resulted in some action that overrides the default trading behavior:
event.setCancelled(true);
Log.debug(" requesting villager editor.");
}
}
private boolean handleEditRegularVillager(Player player, AbstractVillager villager) {
if (!player.isSneaking()) return false;
if ((Settings.editRegularVillagers && villager instanceof Villager)
|| (Settings.editRegularWanderingTraders && villager instanceof WanderingTrader)) {
Log.debug(" possible villager editor request ..");
// Open the villager editor:
// Silent request (fails if the player is missing the permission):
VillagerEditorHandler villagerEditor = new VillagerEditorHandler(villager);
SKShopkeepersPlugin.getInstance().getUIRegistry().requestUI(villagerEditor, player);
} else if ((isVillager && Settings.hireOtherVillagers) || (isWanderingTrader && Settings.hireWanderingTraders)) {
// Allow hiring of other villagers
Log.debug(" possible hire ..");
if (this.handleHireOtherVillager(player, villager)) {
// Hiring was successful. -> Prevent normal trading.
Log.debug(" ..success (normal trading prevented)");
event.setCancelled(true);
if (SKShopkeepersPlugin.getInstance().getUIRegistry().requestUI(villagerEditor, player, true)) {
Log.debug(" ..success (normal trading prevented).");
return true;
} else {
// Hiring was not successful. -> No preventing of normal villager trading.
Log.debug(" ..failed");
Log.debug(" ..no access (probably missing permission).");
}
}
return false;
}
// Returns false, if the player wasn't able to hire this villager.
private boolean handleHireOtherVillager(Player player, AbstractVillager villager) {
// Check if the player is allowed to remove (attack) the entity (in case the entity is protected by another
// plugin).
Log.debug(" checking villager access ..");
TestEntityDamageByEntityEvent fakeDamageEvent = new TestEntityDamageByEntityEvent(player, villager);
plugin.getServer().getPluginManager().callEvent(fakeDamageEvent);
if (fakeDamageEvent.isCancelled()) {
Log.debug(" no permission to remove villager");
if (!(Settings.hireOtherVillagers && villager instanceof Villager)
&& !(Settings.hireWanderingTraders && villager instanceof WanderingTrader)) {
return false;
}
Log.debug(" possible hire ..");
// Check if the player is allowed to remove (attack) the entity (in case the entity is protected by another
// plugin).
Log.debug(" checking villager access.");
if (!this.checkEntityAccess(player, villager)) {
Log.debug(" ..no permission to remove villager.");
return false;
}
// Hire him if holding his hiring item.
PlayerInventory playerInventory = player.getInventory();
ItemStack itemInMainHand = playerInventory.getItemInMainHand();
@ -108,50 +125,60 @@ public class VillagerInteractionListener implements Listener {
"costs", Settings.hireOtherVillagersCosts,
"hire-item", Settings.hireItem.getType().name()
); // TODO Also print required hire item name and lore?
Log.debug(" ..not holding hire item.");
return false;
} else {
// Check if the player has enough of those hiring items:
int costs = Settings.hireOtherVillagersCosts;
if (costs > 0) {
ItemStack[] storageContents = playerInventory.getStorageContents();
if (ItemUtils.containsAtLeast(storageContents, Settings.hireItem, costs)) {
Log.debug(" Villager hiring: the player has the needed amount of hiring items");
int inHandAmount = itemInMainHand.getAmount();
int remaining = inHandAmount - costs;
Log.debug(() -> " Villager hiring: in hand=" + inHandAmount + " costs=" + costs + " remaining=" + remaining);
if (remaining > 0) {
itemInMainHand.setAmount(remaining);
} else { // remaining <= 0
playerInventory.setItemInMainHand(null); // Remove item in hand
if (remaining < 0) {
// Remove remaining costs from inventory:
ItemUtils.removeItems(storageContents, Settings.hireItem, -remaining);
// Apply the change to the player's inventory:
ItemUtils.setStorageContents(playerInventory, storageContents);
}
}
} else {
TextUtils.sendMessage(player, Settings.msgCantHire);
return false;
}
// Check if the player has enough of those hiring items:
final int costs = Settings.hireOtherVillagersCosts;
if (costs > 0) {
ItemStack[] storageContents = playerInventory.getStorageContents();
if (!ItemUtils.containsAtLeast(storageContents, Settings.hireItem, costs)) {
TextUtils.sendMessage(player, Settings.msgCantHire);
Log.debug(" ..not holding enough hire items.");
return false;
}
Log.debug(" Villager hiring: The player has the needed amount of hiring items.");
int inHandAmount = itemInMainHand.getAmount();
int remaining = inHandAmount - costs;
Log.debug(() -> " Villager hiring: in hand=" + inHandAmount + " costs=" + costs + " remaining=" + remaining);
if (remaining > 0) {
itemInMainHand.setAmount(remaining);
} else { // remaining <= 0
playerInventory.setItemInMainHand(null); // Remove item in hand
if (remaining < 0) {
// Remove remaining costs from inventory:
ItemUtils.removeItems(storageContents, Settings.hireItem, -remaining);
// Apply the change to the player's inventory:
ItemUtils.setStorageContents(playerInventory, storageContents);
}
}
// Give player the shop creation item
ItemStack shopCreationItem = Settings.createShopCreationItem();
Map<Integer, ItemStack> remaining = playerInventory.addItem(shopCreationItem);
if (!remaining.isEmpty()) {
villager.getWorld().dropItem(villager.getLocation(), shopCreationItem);
}
// Remove the entity:
// Note: The leashed trader llamas for the wandering trader will break and the llamas will remain.
villager.remove();
// Update client's inventory:
player.updateInventory();
TextUtils.sendMessage(player, Settings.msgHired);
return true;
}
// Give player the shop creation item
ItemStack shopCreationItem = Settings.createShopCreationItem();
Map<Integer, ItemStack> remaining = playerInventory.addItem(shopCreationItem);
if (!remaining.isEmpty()) {
villager.getWorld().dropItem(villager.getLocation(), shopCreationItem);
}
// Remove the entity:
// Note: The leashed trader llamas for the wandering trader will break and the llamas will remain.
villager.remove();
// Update client's inventory:
player.updateInventory();
TextUtils.sendMessage(player, Settings.msgHired);
Log.debug(" ..success (normal trading prevented).");
return true;
}
// Returns true if the player can access (remove / attack) this entity.
private boolean checkEntityAccess(Player player, Entity entity) {
TestEntityDamageByEntityEvent fakeDamageEvent = new TestEntityDamageByEntityEvent(player, entity);
plugin.getServer().getPluginManager().callEvent(fakeDamageEvent);
return !fakeDamageEvent.isCancelled();
}
}