Improved the feedback messages when a player tries to create a shop via

command.

* If the player targets a container (regardless of whether it is
supported), we assume that he might be trying to create a player shop.
However, unlike before this only affects the default shop type that is
chosen if the player does not specify a shop type himself.
* It is now possible to create admin shops via command even when
targeting a container. However, the admin shop type has to be explicitly
specified as command argument.
* When a player shop type is selected, we send appropriate feedback
messages depending on whether player shop creation via command is
enabled, whether a container is targeted, and whether it is a supported
type of container.
* When not specifying a shop object type, we pick the first shop object
type that can be used by the player. This is consistent between the
creation of player and admin shops now.

Messages:
* Added 'must-target-container'.
* Added 'no-player-shops-via-command'.
* Removed 'no-admin-shop-type-selected'.
* Removed 'no-player-shop-type-selected'.
master
blablubbabc 2020-11-23 14:19:17 +01:00
parent ccc76cf363
commit 0dfc51a6b1
9 changed files with 54 additions and 74 deletions

View File

@ -10,6 +10,11 @@ Date format: (YYYY-MM-DD)
* Fixed: Text#parse can now also parse alternative color codes starting with '&'. This has an effect when some messages of the specified language file cannot be loaded and the plugin then uses the default messages instead.
* Added warning output when the language file misses messages, or contains unexpected messages.
* Changed: Players in creative mode are no longer ignored when using the shop creation item.
* Improved the feedback messages when a player tries to create a shop via command.
* If the player targets a container (regardless of whether it is supported), we assume that he might be trying to create a player shop. However, unlike before this only affects the default shop type that is chosen if the player does not specify a shop type himself.
* It is now possible to create admin shops via command even when targeting a container. However, the admin shop type has to be explicitly specified as command argument.
* When a player shop type is selected, we send appropriate feedback messages depending on whether player shop creation via command is enabled, whether a container is targeted, and whether it is a supported type of container.
* When not specifying a shop object type, we pick the first shop object type that can be used by the player. This is consistent between the creation of player and admin shops now.
Migration notes:
* The folder structure has changed:
@ -24,6 +29,10 @@ Messages:
* 'cant-trade-with-own-shop' -> 'cannot-trade-with-own-shop'
* 'cant-trade-while-owner-online' -> 'cannot-trade-while-owner-online'
* 'cant-trade-with-shop-missing-container' -> 'cannot-trade-with-shop-missing-container'
* Added 'must-target-container'.
* Added 'no-player-shops-via-command'.
* Removed 'no-admin-shop-type-selected'.
* Removed 'no-player-shop-type-selected'.
You will have to manually update your custom language files to adapt for these changes.

View File

@ -129,14 +129,14 @@ public class Messages {
public static Text containerSelected = Text.parse("&aContainer selected! Right-click a block to place your shopkeeper.");
public static Text unsupportedContainer = Text.parse("&7This type of container cannot be used for shops.");
public static Text mustSelectContainer = Text.parse("&7You must right-click a container before placing your shopkeeper.");
public static Text mustTargetContainer = Text.parse("&7You must target a container to place this type of shop.");
public static Text invalidContainer = Text.parse("&7The selected block is not a valid container!");
public static Text containerTooFarAway = Text.parse("&7The shopkeeper's container is too far away!");
public static Text containerNotPlaced = Text.parse("&7You must select a container you have recently placed!");
public static Text containerAlreadyInUse = Text.parse("&7Another shopkeeper is already using the selected container!");
public static Text noContainerAccess = Text.parse("&7You cannot access the selected container!");
public static Text tooManyShops = Text.parse("&7You have too many shops!");
public static Text noAdminShopTypeSelected = Text.parse("&7You have to select an admin shop type!");
public static Text noPlayerShopTypeSelected = Text.parse("&7You have to select a player shop type!");
public static Text noPlayerShopsViaCommand = Text.parse("&7Player shops can only be created via the shop creation item!");
public static Text shopCreateFail = Text.parse("&7You cannot create a shopkeeper there.");
public static Text typeNewName = Text.parse("&aPlease type the shop's name into the chat.\n"

View File

@ -11,7 +11,6 @@ import org.bstats.bukkit.Metrics;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.configuration.Configuration;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.event.HandlerList;
import org.bukkit.inventory.ItemStack;
@ -60,7 +59,6 @@ import com.nisovin.shopkeepers.shopkeeper.SKTradingRecipe;
import com.nisovin.shopkeepers.shopkeeper.offers.SKBookOffer;
import com.nisovin.shopkeepers.shopkeeper.offers.SKPriceOffer;
import com.nisovin.shopkeepers.shopkeeper.offers.SKTradingOffer;
import com.nisovin.shopkeepers.shopobjects.AbstractShopObjectType;
import com.nisovin.shopkeepers.shopobjects.SKDefaultShopObjectTypes;
import com.nisovin.shopkeepers.shopobjects.SKShopObjectTypesRegistry;
import com.nisovin.shopkeepers.shopobjects.citizens.CitizensShops;
@ -630,20 +628,6 @@ public class SKShopkeepersPlugin extends JavaPlugin implements ShopkeepersPlugin
return defaultShopObjectTypes;
}
/**
* Gets the default shop object type.
*
* <p>
* Usually this will be the villager entity shop object type. However, there are no guarantees that this might not
* get changed or be configurable in the future.
*
* @return the default shop object type
*/
public AbstractShopObjectType<?> getDefaultShopObjectType() {
// Default: Villager entity shop object type.
return this.getDefaultShopObjectTypes().getLivingShopObjectTypes().get(EntityType.VILLAGER);
}
// SHOPKEEPER NAMING
public ShopkeeperNaming getShopkeeperNaming() {

View File

@ -20,7 +20,6 @@ import com.nisovin.shopkeepers.api.shopkeeper.ShopCreationData;
import com.nisovin.shopkeepers.api.shopkeeper.ShopType;
import com.nisovin.shopkeepers.api.shopkeeper.ShopkeeperRegistry;
import com.nisovin.shopkeepers.api.shopkeeper.admin.AdminShopCreationData;
import com.nisovin.shopkeepers.api.shopkeeper.admin.AdminShopType;
import com.nisovin.shopkeepers.api.shopkeeper.player.PlayerShopCreationData;
import com.nisovin.shopkeepers.api.shopkeeper.player.PlayerShopType;
import com.nisovin.shopkeepers.api.shopobjects.ShopObjectType;
@ -34,7 +33,7 @@ import com.nisovin.shopkeepers.commands.lib.CommandInput;
import com.nisovin.shopkeepers.commands.lib.CommandRegistry;
import com.nisovin.shopkeepers.commands.lib.PlayerCommand;
import com.nisovin.shopkeepers.commands.lib.arguments.OptionalArgument;
import com.nisovin.shopkeepers.container.ShopContainers;
import com.nisovin.shopkeepers.util.ItemUtils;
import com.nisovin.shopkeepers.util.PermissionUtils;
import com.nisovin.shopkeepers.util.TextUtils;
@ -125,63 +124,50 @@ public class ShopkeepersCommand extends BaseCommand {
ShopType<?> shopType = context.get(ARGUMENT_SHOP_TYPE);
ShopObjectType<?> shopObjType = context.get(ARGUMENT_OBJECT_TYPE);
boolean createPlayerShop = (Settings.createPlayerShopWithCommand && ShopContainers.isSupportedContainer(targetBlock.getType()));
if (createPlayerShop) {
// Create player shopkeeper:
// Default shop type and shop object type: First useable player shop type and shop object type.
// We use different defaults depending on whether the player might be trying to create a player or admin shop:
boolean containerTargeted = ItemUtils.isContainer(targetBlock.getType());
boolean maybeCreatePlayerShop = containerTargeted;
if (maybeCreatePlayerShop) {
// Default shop type and shop object type: First usable player shop type and shop object type.
if (shopType == null) {
shopType = plugin.getShopTypeRegistry().getDefaultSelection(player);
}
if (shopObjType == null) {
shopObjType = plugin.getShopObjectTypeRegistry().getDefaultSelection(player);
}
if (shopType == null || shopObjType == null) {
// The player cannot create shops at all:
TextUtils.sendMessage(player, Messages.noPermission);
return;
}
// Validate the selected shop type:
if (!(shopType instanceof PlayerShopType)) {
// Only player shop types are allowed here:
TextUtils.sendMessage(player, Messages.noPlayerShopTypeSelected);
return;
}
} else {
// Create admin shopkeeper:
// Check permission:
if (!PermissionUtils.hasPermission(player, ShopkeepersPlugin.ADMIN_PERMISSION)) {
TextUtils.sendMessage(sender, Messages.noPermission);
return;
}
// Default shop type and shop object type:
if (shopType == null) {
shopType = DefaultShopTypes.ADMIN();
}
if (shopObjType == null) {
shopObjType = plugin.getDefaultShopObjectType();
}
assert shopType != null && shopObjType != null;
// Validate the selected shop type:
if (!(shopType instanceof AdminShopType)) {
// Only admin shop types are allowed here:
TextUtils.sendMessage(player, Messages.noAdminShopTypeSelected);
return;
// Note: Shop type permissions are checked afterwards during shop creation.
}
}
if (shopObjType == null) {
shopObjType = plugin.getShopObjectTypeRegistry().getDefaultSelection(player);
}
if (shopType == null || shopObjType == null) {
// The player cannot create shops at all:
TextUtils.sendMessage(player, Messages.noPermission);
return;
}
assert shopType != null && shopObjType != null;
boolean isPlayerShopType = (shopType instanceof PlayerShopType);
if (isPlayerShopType) {
if (!Settings.createPlayerShopWithCommand) {
TextUtils.sendMessage(player, Messages.noPlayerShopsViaCommand);
return;
} else if (!containerTargeted) {
TextUtils.sendMessage(player, Messages.mustTargetContainer);
return;
}
// Note: We check if the targeted container is valid / supported during shop creation.
}
// Determine spawn location:
Location spawnLocation = plugin.getShopkeeperCreation().determineSpawnLocation(player, targetBlock, targetBlockFace);
// Shop creation data:
ShopCreationData shopCreationData;
if (createPlayerShop) {
if (isPlayerShopType) {
// Create player shopkeeper:
shopCreationData = PlayerShopCreationData.create(player, shopType, shopObjType, spawnLocation, targetBlockFace, targetBlock);
} else {

View File

@ -179,12 +179,8 @@ class CreateListener implements Listener {
}
assert ShopContainers.isSupportedContainer(selectedContainer.getType()); // Checked above already
// Validate the selected shop type:
if (!(shopType instanceof PlayerShopType)) {
// Only player shop types are allowed here:
TextUtils.sendMessage(player, Messages.noPlayerShopTypeSelected);
return;
}
// Only player shops can be selected currently. TODO Change that?
assert shopType instanceof PlayerShopType;
// Determine spawn location:
BlockFace clickedBlockFace = event.getBlockFace();

View File

@ -18,7 +18,7 @@ public class SKShopTypesRegistry extends AbstractSelectableTypeRegistry<Abstract
// TODO This currently skips all shop types that are not PlayerShopType.
// Maybe include the admin shop types here for players which are admins, because there /could/ be different
// types of admin shops in the future.
// Maybe include other types of shop types here, is custom ones get registered?
// Maybe include other types of shop types here, if custom ones get registered?
return super.canBeSelected(player, type) && (type instanceof PlayerShopType);
}
}

View File

@ -18,6 +18,7 @@ import com.nisovin.shopkeepers.container.ShopContainers;
import com.nisovin.shopkeepers.pluginhandlers.TownyHandler;
import com.nisovin.shopkeepers.pluginhandlers.WorldGuardHandler;
import com.nisovin.shopkeepers.shopkeeper.AbstractShopType;
import com.nisovin.shopkeepers.util.ItemUtils;
import com.nisovin.shopkeepers.util.Log;
import com.nisovin.shopkeepers.util.TextUtils;
import com.nisovin.shopkeepers.util.Validate;
@ -45,8 +46,12 @@ public abstract class AbstractPlayerShopType<T extends AbstractPlayerShopkeeper>
// Validate container block:
Block containerBlock = playerShopCreationData.getShopContainer();
if (!ShopContainers.isSupportedContainer(containerBlock.getType())) {
// The block is not / no longer a supported container:
TextUtils.sendMessage(creator, Messages.invalidContainer);
// The block is not / no longer a supported type of container:
if (ItemUtils.isContainer(containerBlock.getType())) {
TextUtils.sendMessage(creator, Messages.unsupportedContainer);
} else {
TextUtils.sendMessage(creator, Messages.invalidContainer);
}
return false;
}

View File

@ -170,14 +170,14 @@ msg-trading-title-default: "Händler"
msg-container-selected: "&aBehälter ausgewählt! Klicke mit rechts auf einen Block, um den Shop zu platzieren."
msg-unsupported-container: "&7Diese Art von Behälter kann nicht für Shops benutzt werden."
msg-must-select-container: "&7Du musst zuerst einen Behälter mit rechts anklicken, bevor du den Shop platzieren kannst."
must-target-container: "&7Du musst einen Behälter anvisieren, um diesen Shop zu platzieren."
msg-invalid-container: "&7Der ausgewählte Block ist kein gültiger Behälter!"
msg-container-too-far-away: "&7Der Behälter des Shops ist zu weit entfernt!"
msg-container-not-placed: "&7Du musst einen Behälter auswählen, den du kürzlich platziert hast!"
msg-container-already-in-use: "&7Ein anderer Shop benutzt bereits den ausgewählten Behälter!"
msg-no-container-access: "&7Du hast keinen Zugriff auf den ausgewählten Behälter!"
msg-too-many-shops: "&7Du hast bereits zu viele Shops!"
msg-no-admin-shop-type-selected: "&7Du musst einen Admin-Shop Typ auswählen!"
msg-no-player-shop-type-selected: "&7Du musst einen Spieler-Shop Typ auswählen!"
no-player-shops-via-command: "&7Spieler-Shops können nur mit dem Shop-Erstellungs Item erzeugt werden!"
msg-shop-create-fail: "&7Du kannst dort keinen Shop erstellen."
msg-type-new-name: "&aBitte gebe den neuen Shop-Namen im Chat ein.\n &aTippe Minus (-) ein, um den Namen zu entfernen."

View File

@ -171,14 +171,14 @@ trading-title-default: "Shopkeeper"
container-selected: "&aContainer selected! Right-click a block to place your shopkeeper."
unsupported-container: "&7This type of container cannot be used for shops."
must-select-container: "&7You must right-click a container before placing your shopkeeper."
must-target-container: "&7You must target a container to place this type of shop."
invalid-container: "&7The selected block is not a valid container!"
container-too-far-away: "&7The shopkeeper's container is too far away!"
container-not-placed: "&7You must select a container you have recently placed!"
container-already-in-use: "&7Another shopkeeper is already using the selected container!"
no-container-access: "&7You cannot access the selected container!"
too-many-shops: "&7You have too many shops!"
no-admin-shop-type-selected: "&7You have to select an admin shop type!"
no-player-shop-type-selected: "&7You have to select a player shop type!"
no-player-shops-via-command: "&7Player shops can only be created via the shop creation item!"
shop-create-fail: "&7You cannot create a shopkeeper there."
type-new-name: "&aPlease type the shop's name into the chat.\n &aType a dash (-) to remove the name."