Added support for the new crimson and warped sign variants.

We no longer use Bukkit's (now outdated) TreeSpecies enum to represent the available sign/wood types. Instead we use our own 'SignType' enum.
Sign shops of type 'GENERIC' and 'REDWOOD' are migrated to 'OAK' and 'SPRUCE' respectively.
When loading the sign type from the storage we verify that the loaded type is both valid and also supported on the currently used server version.

Also:
* Added the debug option 'capabilities', which logs additional details when the plugin checks for server version dependent capabilities.
* Added a note to the changelog regarding Minecrafts new chat features not being supported yet.
master
blablubbabc 2020-06-26 16:30:09 +02:00
parent 186711941b
commit 496b3761f8
7 changed files with 147 additions and 45 deletions

View File

@ -16,6 +16,9 @@ Date format: (YYYY-MM-DD)
* The pig zombie mob type has been removed from the by default enabled mob types. If you are updating to MC 1.16, it will get automatically removed from your config. To prevent your config from losing its comments and formatting during this small migration, consider manually removing this mob type before your update.
* If you are updating to MC 1.16, your pig zombie shopkeepers get automatically converted to zombified pigman shopkeepers.
* Internal: Any internal references to the pig zombie mob type have been removed to prevent any kind of binary problems to arise.
* Sign shops support the new crimson and warped sign variants.
* Internal data format changes: Sign shops of type 'GENERIC' and 'REDWOOD' are migrated to 'OAK' and 'SPRUCE' respectively.
* Note on Minecraft's new RGB color codes and other new text related features: I have not yet looked into supporting those in the texts and messages of the Shopkeepers plugin.
**Other migration notes:**
* Removed: We no longer migrate items inside the config from legacy (pre MC 1.13) item types, data values and spawn eggs to corresponding item types in MC 1.13. Instead any unknown item types get migrated to their default now.
@ -39,6 +42,7 @@ Date format: (YYYY-MM-DD)
* Fixed/API: The PlayerDeleteShopkeeperEvent is now also called when a player deletes shops via command.
* Changed: The result message after deleting shops via command will now print the number of actually removed shops (which does not necessarily match the number of shops that were confirmed for removal).
* Changed: The item representing the black horse inside the editor is now slightly less black.
* Debug: Added the debug option 'capabilities', which logs additional details when the plugin checks for server version dependent capabilities.
* Debug: Added some more information to the debug message that gets logged when the PlayerDeleteShopkeeperEvent has been cancelled.
* Debug: Minor changes to some debug messages related to Citizens shopkeepers.
* API/Internal: Added Shopkeeper#delete(Player) which optionally passes the player responsible for the shopkeeper deletion. Note that the player is not passed if a player shop is deleted due to a player breaking the shop's chest.

View File

@ -36,6 +36,7 @@ import com.nisovin.shopkeepers.api.shopkeeper.player.PlayerShopkeeper;
import com.nisovin.shopkeepers.chestprotection.ProtectedChests;
import com.nisovin.shopkeepers.chestprotection.RemoveShopOnChestBreak;
import com.nisovin.shopkeepers.commands.Commands;
import com.nisovin.shopkeepers.compat.MC_1_16_Utils;
import com.nisovin.shopkeepers.compat.NMSManager;
import com.nisovin.shopkeepers.config.ConfigLoadException;
import com.nisovin.shopkeepers.metrics.CitizensChart;
@ -318,6 +319,9 @@ public class SKShopkeepersPlugin extends JavaPlugin implements ShopkeepersPlugin
}
}
// Check for and initialize version dependent utilities:
MC_1_16_Utils.init();
// inform about Spigot exclusive features:
if (SpigotFeatures.isSpigotAvailable()) {
Log.debug("Spigot-based server found: Enabling Spigot exclusive features.");

View File

@ -37,6 +37,8 @@ public class Settings {
private DebugOptions() {
}
// Logs details of the server version dependent capabilities.
public static final String capabilities = "capabilities";
// Logs all events (spams!). Starts slightly delayed. Subsequent calls of the same event get combined into a
// single logging entry to slightly reduce spam.
public static final String logAllEvents = "log-all-events";

View File

@ -1,29 +1,70 @@
package com.nisovin.shopkeepers.compat;
import java.util.Optional;
import org.bukkit.Material;
import org.bukkit.entity.EntityType;
import com.nisovin.shopkeepers.Settings;
import com.nisovin.shopkeepers.util.Log;
// TODO This can be removed once we only support Bukkit 1.16.1 upwards.
public class MC_1_16_Utils {
private static Optional<EntityType> zombifiedPiglin = null;
private static final EntityType zombifiedPiglin = getEntityType("ZOMBIFIED_PIGLIN");
private static final Material crimsonSign = getMaterial("CRIMSON_SIGN");
private static final Material crimsonWallSign = getMaterial("CRIMSON_WALL_SIGN");
private static final Material warpedSign = getMaterial("WARPED_SIGN");
private static final Material warpedWallSign = getMaterial("WARPED_WALL_SIGN");
private MC_1_16_Utils() {
}
public static EntityType getZombifiedPiglin() {
if (zombifiedPiglin == null) {
try {
zombifiedPiglin = Optional.of(EntityType.valueOf("ZOMBIFIED_PIGLIN"));
Log.debug("Server knows EntityType 'ZOMBIFIED_PIGLIN'.");
} catch (IllegalArgumentException e) {
zombifiedPiglin = Optional.empty();
Log.debug("Server does not know EntityType 'ZOMBIFIED_PIGLIN'.");
}
public static void init() {
if (zombifiedPiglin != null) {
Log.debug("MC 1.16 exclusive features are enabled.");
} else {
Log.debug("MC 1.16 exclusive features are disabled.");
}
}
public static EntityType getZombifiedPiglin() {
return zombifiedPiglin;
}
public static Material getCrimsonSign() {
return crimsonSign;
}
public static Material getCrimsonWallSign() {
return crimsonWallSign;
}
public static Material getWarpedSign() {
return warpedSign;
}
public static Material getWarpedWallSign() {
return warpedWallSign;
}
private static EntityType getEntityType(String name) {
try {
EntityType entityType = EntityType.valueOf(name); // not null
Log.debug(Settings.DebugOptions.capabilities, "Server knows EntityType '" + name + "'.");
return entityType;
} catch (IllegalArgumentException e) {
Log.debug(Settings.DebugOptions.capabilities, "Server does not know EntityType '" + name + "'.");
return null;
}
}
private static Material getMaterial(String name) {
try {
Material material = Material.valueOf(name); // not null
Log.debug(Settings.DebugOptions.capabilities, "Server knows Material '" + name + "'.");
return material;
} catch (IllegalArgumentException e) {
Log.debug(Settings.DebugOptions.capabilities, "Server does not know Material '" + name + "'.");
return null;
}
return zombifiedPiglin.orElse(null);
}
}

View File

@ -6,7 +6,6 @@ import java.util.List;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.TreeSpecies;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.Sign;
@ -33,10 +32,10 @@ import com.nisovin.shopkeepers.util.Validate;
public class SKSignShopObject extends AbstractBlockShopObject implements SignShopObject {
protected final SignShops signShops;
private TreeSpecies signType = TreeSpecies.GENERIC; // default oak
private SignType signType = SignType.OAK; // not null, not unsupported, default is oak
private boolean wallSign = true;
private BlockFace signFacing = BlockFace.SOUTH; // not null
// update the sign content at least once after plugin start, in case some settings have changed which affect the
// Update the sign content at least once after plugin start, in case some settings have changed which affect the
// sign content:
private boolean updateSign = true;
private long lastFailedRespawnAttempt = 0;
@ -63,15 +62,34 @@ public class SKSignShopObject extends AbstractBlockShopObject implements SignSho
@Override
public void load(ConfigurationSection configSection) {
super.load(configSection);
// sign wood type:
// Sign (wood) type:
String signTypeName = configSection.getString("signType");
// Migration from TreeSpecies to SignType:
// TODO remove this again at some point
if ("GENERIC".equals(signTypeName)) {
Log.warning("Migrating sign type of shopkeeper '" + shopkeeper.getId() + "' from '" + signTypeName
+ "' to '" + SignType.OAK + "'.");
signTypeName = SignType.OAK.name();
shopkeeper.markDirty();
} else if ("REDWOOD".equals(signTypeName)) {
Log.warning("Migrating sign type of shopkeeper '" + shopkeeper.getId() + "' from '" + signTypeName
+ "' to '" + SignType.SPRUCE + "'.");
signTypeName = SignType.SPRUCE.name();
shopkeeper.markDirty();
}
try {
signType = TreeSpecies.valueOf(signTypeName);
signType = SignType.valueOf(signTypeName);
assert signType != null;
// Ensure that the loaded sign type is supported:
if (!signType.isSupported()) {
throw new RuntimeException("unsupported sign type");
}
} catch (Exception e) {
// fallback to default:
Log.warning("Missing or invalid sign type '" + signTypeName + "' for shopkeeper " + shopkeeper.getId()
+ "'. Using '" + TreeSpecies.GENERIC + "' now.");
this.signType = TreeSpecies.GENERIC;
Log.warning("Missing, invalid, or unsupported sign type '" + signTypeName + "' for shopkeeper "
+ shopkeeper.getId() + "'. Using '" + SignType.OAK + "' now.");
signType = SignType.OAK;
shopkeeper.markDirty();
}
@ -198,7 +216,7 @@ public class SKSignShopObject extends AbstractBlockShopObject implements SignSho
}
private BlockData createBlockData() {
Material signMaterial = getMaterial(signType, wallSign);
Material signMaterial = getSignMaterial(signType, wallSign);
assert ItemUtils.isSign(signMaterial);
BlockData signData = null;
if (wallSign) {
@ -215,25 +233,10 @@ public class SKSignShopObject extends AbstractBlockShopObject implements SignSho
return signData;
}
private static Material getMaterial(TreeSpecies treeSpecies, boolean wallSign) {
if (treeSpecies == null) {
treeSpecies = TreeSpecies.GENERIC; // default
}
switch (treeSpecies) {
case ACACIA:
return wallSign ? Material.ACACIA_WALL_SIGN : Material.ACACIA_SIGN;
case BIRCH:
return wallSign ? Material.BIRCH_WALL_SIGN : Material.BIRCH_SIGN;
case DARK_OAK:
return wallSign ? Material.DARK_OAK_WALL_SIGN : Material.DARK_OAK_SIGN;
case JUNGLE:
return wallSign ? Material.JUNGLE_WALL_SIGN : Material.JUNGLE_SIGN;
case REDWOOD: // spruce
return wallSign ? Material.SPRUCE_WALL_SIGN : Material.SPRUCE_SIGN;
case GENERIC: // oak
default:
return wallSign ? Material.OAK_WALL_SIGN : Material.OAK_SIGN;
}
private static Material getSignMaterial(SignType signType, boolean wallSign) {
assert signType != null && signType.isSupported();
if (wallSign) return signType.getWallSignMaterial();
else return signType.getSignMaterial();
}
@Override
@ -347,8 +350,9 @@ public class SKSignShopObject extends AbstractBlockShopObject implements SignSho
// SIGN TYPE
public void setSignType(TreeSpecies signType) {
Validate.notNull(signType, "Sign type is null!");
public void setSignType(SignType signType) {
Validate.notNull(signType, "signType is null");
Validate.isTrue(signType.isSupported(), "signType is not supported");
this.signType = signType;
shopkeeper.markDirty();
this.applySignType();
@ -364,11 +368,11 @@ public class SKSignShopObject extends AbstractBlockShopObject implements SignSho
}
public void cycleSignType(boolean backwards) {
this.setSignType(EnumUtils.cycleEnumConstant(TreeSpecies.class, signType, backwards));
this.setSignType(EnumUtils.cycleEnumConstant(SignType.class, signType, backwards, SignType.IS_SUPPORTED));
}
protected ItemStack getSignTypeEditorItem() {
ItemStack iconItem = new ItemStack(getMaterial(signType, false));
ItemStack iconItem = new ItemStack(signType.getSignMaterial());
return ItemUtils.setItemStackNameAndLore(iconItem, Settings.msgButtonSignVariant, Settings.msgButtonSignVariantLore);
}
}

View File

@ -0,0 +1,46 @@
package com.nisovin.shopkeepers.shopobjects.sign;
import java.util.function.Predicate;
import org.bukkit.Material;
import com.nisovin.shopkeepers.compat.MC_1_16_Utils;
public enum SignType {
// Previously persisted as 'GENERIC'.
OAK(Material.OAK_SIGN, Material.OAK_WALL_SIGN),
// Previously persisted as 'REDWOOD'.
SPRUCE(Material.SPRUCE_SIGN, Material.SPRUCE_WALL_SIGN),
BIRCH(Material.BIRCH_SIGN, Material.BIRCH_WALL_SIGN),
JUNGLE(Material.JUNGLE_SIGN, Material.JUNGLE_WALL_SIGN),
ACACIA(Material.ACACIA_SIGN, Material.ACACIA_WALL_SIGN),
DARK_OAK(Material.DARK_OAK_SIGN, Material.DARK_OAK_WALL_SIGN),
CRIMSON(MC_1_16_Utils.getCrimsonSign(), MC_1_16_Utils.getCrimsonWallSign()),
WARPED(MC_1_16_Utils.getWarpedSign(), MC_1_16_Utils.getWarpedWallSign());
public static final Predicate<SignType> IS_SUPPORTED = SignType::isSupported;
// These can be null if the current server version does not support the specific sign type.
private final Material signMaterial;
private final Material wallSignMaterial;
private SignType(Material signMaterial, Material wallSignMaterial) {
this.signMaterial = signMaterial;
this.wallSignMaterial = wallSignMaterial;
// Assert: Either both a null or both a non-null:
assert signMaterial != null ^ wallSignMaterial == null;
}
public boolean isSupported() {
return (signMaterial != null);
}
public Material getSignMaterial() {
return signMaterial;
}
public Material getWallSignMaterial() {
return wallSignMaterial;
}
}

View File

@ -10,6 +10,7 @@ config-version: 2
# The initial debugging state of the plugin.
debug: false
# Additional debugging options.
# - 'capabilities': Logs details of the server version dependent capabilities.
# - 'log-all-events': Logs all events.
# - 'print-listeners': Prints the registered listeners for the first call of
# each event.