Add serialization support to kits (#3248)

Co-authored-by: MD <1917406+mdcfe@users.noreply.github.com>

This PR makes use of Paper's item serialization to serialize items into base64 allowing for all items to be properly stored without needing to manual write in special cases for every complex item. There is a config option to disable using this new serialization and use the legacy ItemDB serializer since the new serializer removes the ability to manually edit/read kits.

Defaults to not enabled

Note: The new serializer places an @ sign in front of items serialized by the new format in order to quickly determine what is serialized by the new serializer and also to retain backward compatibility with the old serializer.

Att #3114
Att #2867
Att #1694
Att #31
Att #1283
This commit is contained in:
Josh Roy 2021-06-26 16:03:27 -04:00 committed by GitHub
parent 736ecae5ff
commit 64eb39a417
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 88 additions and 3 deletions

View File

@ -58,6 +58,7 @@ import net.ess3.provider.KnownCommandsProvider;
import net.ess3.provider.MaterialTagProvider;
import net.ess3.provider.PersistentDataProvider;
import net.ess3.provider.PotionMetaProvider;
import net.ess3.provider.SerializationProvider;
import net.ess3.provider.ProviderListener;
import net.ess3.provider.ServerStateProvider;
import net.ess3.provider.SpawnEggProvider;
@ -76,6 +77,7 @@ import net.ess3.provider.providers.PaperContainerProvider;
import net.ess3.provider.providers.PaperKnownCommandsProvider;
import net.ess3.provider.providers.PaperMaterialTagProvider;
import net.ess3.provider.providers.PaperRecipeBookListener;
import net.ess3.provider.providers.PaperSerializationProvider;
import net.ess3.provider.providers.PaperServerStateProvider;
import net.essentialsx.api.v2.services.BalanceTop;
import org.bukkit.Bukkit;
@ -151,6 +153,7 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
private transient PotionMetaProvider potionMetaProvider;
private transient ServerStateProvider serverStateProvider;
private transient ContainerProvider containerProvider;
private transient SerializationProvider serializationProvider;
private transient KnownCommandsProvider knownCommandsProvider;
private transient FormattedCommandAliasProvider formattedCommandAliasProvider;
private transient ProviderListener recipeBookEventProvider;
@ -350,6 +353,7 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
if (PaperLib.isPaper() && VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_15_2_R01)) {
serverStateProvider = new PaperServerStateProvider();
containerProvider = new PaperContainerProvider();
serializationProvider = new PaperSerializationProvider();
} else {
serverStateProvider = new ReflServerStateProvider();
}
@ -1132,6 +1136,11 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
return knownCommandsProvider;
}
@Override
public SerializationProvider getSerializationProvider() {
return serializationProvider;
}
@Override
public FormattedCommandAliasProvider getFormattedCommandAliasProvider() {
return formattedCommandAliasProvider;

View File

@ -12,6 +12,7 @@ import net.ess3.provider.KnownCommandsProvider;
import net.ess3.provider.MaterialTagProvider;
import net.ess3.provider.PersistentDataProvider;
import net.ess3.provider.ServerStateProvider;
import net.ess3.provider.SerializationProvider;
import net.ess3.provider.SpawnerBlockProvider;
import net.ess3.provider.SpawnerItemProvider;
import net.ess3.provider.SyncCommandsProvider;
@ -136,6 +137,8 @@ public interface IEssentials extends Plugin {
KnownCommandsProvider getKnownCommandsProvider();
SerializationProvider getSerializationProvider();
FormattedCommandAliasProvider getFormattedCommandAliasProvider();
SyncCommandsProvider getSyncCommandsProvider();

View File

@ -327,6 +327,8 @@ public interface ISettings extends IConf {
boolean isPastebinCreateKit();
boolean isUseBetterKits();
boolean isAllowBulkBuySell();
boolean isAllowSellNamedItems();

View File

@ -16,6 +16,7 @@ import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder;
import java.math.BigDecimal;
import java.util.ArrayList;
@ -188,6 +189,15 @@ public class Kit {
continue;
}
if (kitItem.startsWith("@")) {
if (ess.getSerializationProvider() == null) {
ess.getLogger().log(Level.WARNING, tl("kitError3", kitName, user.getName()));
continue;
}
itemList.add(ess.getSerializationProvider().deserializeItem(Base64Coder.decodeLines(kitItem.substring(1))));
continue;
}
final String[] parts = kitItem.split(" +");
final ItemStack parseStack = ess.getItemDb().get(parts[0], parts.length > 1 ? Integer.parseInt(parts[1]) : 1);

View File

@ -1640,6 +1640,11 @@ public class Settings implements net.ess3.api.ISettings {
return config.getBoolean("pastebin-createkit", false);
}
@Override
public boolean isUseBetterKits() {
return config.getBoolean("use-nbt-serialization-in-createkit", false);
}
@Override
public boolean isAllowBulkBuySell() {
return config.getBoolean("allow-bulk-buy-sell", false);

View File

@ -14,6 +14,7 @@ import org.bukkit.inventory.ItemStack;
import org.spongepowered.configurate.ConfigurationNode;
import org.spongepowered.configurate.yaml.NodeStyle;
import org.spongepowered.configurate.yaml.YamlConfigurationLoader;
import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
@ -51,9 +52,22 @@ public class Commandcreatekit extends EssentialsCommand {
final String kitname = args[0];
final ItemStack[] items = user.getBase().getInventory().getContents();
final List<String> list = new ArrayList<>();
for (final ItemStack is : items) {
boolean useSerializationProvider = ess.getSettings().isUseBetterKits();
if (useSerializationProvider && ess.getSerializationProvider() == null) {
ess.showError(user.getSource(), new Exception(tl("createKitUnsupported")), commandLabel);
useSerializationProvider = false;
}
for (ItemStack is : items) {
if (is != null && is.getType() != null && is.getType() != Material.AIR) {
final String serialized = ess.getItemDb().serialize(is);
final String serialized;
if (useSerializationProvider) {
serialized = "@" + Base64Coder.encodeLines(ess.getSerializationProvider().serializeItem(is));
} else {
serialized = ess.getItemDb().serialize(is);
}
list.add(serialized);
}
}

View File

@ -331,9 +331,18 @@ kit-auto-equip: false
# Determines the functionality of the /createkit command.
# If this is true, /createkit will give the user a link with the kit code.
# If this is false, /createkit will add the kit to the kits.yml config file directly.
#
# Default is false.
pastebin-createkit: false
# Determines if /createkit will generate kits using NBT item serialization.
# If this is true, /createkit will store items as NBT; otherwise, it will use Essentials' human-readable item format.
# By using NBT serialization, /createkit can store items with complex metadata such as shulker boxes and weapons with custom attributes.
# WARNING: This option only works on 1.15.2+ Paper servers, and it will bypass any custom serializers from other plugins such as Magic.
# WARNING: When creating kits via /createkit with this option enabled, you will not be able to downgrade your server with these kit items.
# This option only affects /createkit - you can still create kits by hand in `kits.yml` using Essentials' human-readable item format.
# Default is false.
use-nbt-serialization-in-createkit: false
# Essentials Sign Control
# See http://wiki.ess3.net/wiki/Sign_Tutorial for instructions on how to use these.
# To enable signs, remove # symbol. To disable all signs, comment/remove each sign.

View File

@ -181,6 +181,7 @@ createkitCommandUsage1Description=Creates a kit with the given name and delay
createKitFailed=\u00a74Error occurred whilst creating kit {0}.
createKitSeparator=\u00a7m-----------------------
createKitSuccess=\u00a76Created Kit: \u00a7f{0}\n\u00a76Delay: \u00a7f{1}\n\u00a76Link: \u00a7f{2}\n\u00a76Copy contents in the link above into your kits.yml.
createKitUnsupported=\u00a74NBT item serialization has been enabled, but this server is not running Paper 1.15.2+. Falling back to standard item serialization.
creatingConfigFromTemplate=Creating config from template\: {0}
creatingEmptyConfig=Creating empty config\: {0}
creative=creative
@ -582,6 +583,7 @@ kitCost=\ \u00a77\u00a7o({0})\u00a7r
kitDelay=\u00a7m{0}\u00a7r
kitError=\u00a74There are no valid kits.
kitError2=\u00a74That kit is improperly defined. Contact an administrator.
kitError3=Cannot give kit item in kit "{0}" to user {1} as kit item requires Paper 1.15.2+ to deserialize.
kitGiveTo=\u00a76Giving kit\u00a7c {0}\u00a76 to \u00a7c{1}\u00a76.
kitInvFull=\u00a74Your inventory was full, placing kit on the floor.
kitInvFullNoDrop=\u00a74There is not enough room in your inventory for that kit.

View File

@ -0,0 +1,9 @@
package net.ess3.provider;
import org.bukkit.inventory.ItemStack;
public interface SerializationProvider extends Provider {
byte[] serializeItem(ItemStack stack);
ItemStack deserializeItem(byte[] bytes);
}

View File

@ -0,0 +1,22 @@
package net.ess3.provider.providers;
import net.ess3.provider.SerializationProvider;
import org.bukkit.inventory.ItemStack;
public class PaperSerializationProvider implements SerializationProvider {
@Override
public byte[] serializeItem(ItemStack stack) {
return stack.serializeAsBytes();
}
@Override
public ItemStack deserializeItem(byte[] bytes) {
return ItemStack.deserializeBytes(bytes);
}
@Override
public String getDescription() {
return "Paper Serialization Provider";
}
}