Skip to content

Commit 83659fa

Browse files
authored
Merge pull request #578 from Multiverse/ben/mv5/byte-serialization
Add support for paper's better ItemStack byte serialization
2 parents 74f21d1 + 3e69bd0 commit 83659fa

File tree

11 files changed

+121
-6
lines changed

11 files changed

+121
-6
lines changed

build.gradle

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ configure(apiDependencies) {
2626
}
2727

2828
dependencies {
29+
// Server API
30+
// TODO make our custom plugin target paper instead of spigot
31+
externalPlugin 'io.papermc.paper:paper-api:1.18.2-R0.1-SNAPSHOT'
32+
2933
// Core
3034
// TODO update to correct version once we have it published
3135
externalPlugin 'org.mvplugins.multiverse.core:multiverse-core:5.0.0-SNAPSHOT'

src/main/java/org/mvplugins/multiverse/inventories/MultiverseInventories.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.mvplugins.multiverse.inventories.profile.container.ProfileContainerStoreProvider;
2626
import org.mvplugins.multiverse.inventories.profile.group.WorldGroupManager;
2727
import org.mvplugins.multiverse.inventories.share.Sharables;
28+
import org.mvplugins.multiverse.inventories.util.ItemStackConverter;
2829
import org.mvplugins.multiverse.inventories.util.Perm;
2930
import org.bukkit.Bukkit;
3031
import org.mvplugins.multiverse.core.commandtools.MVCommandManager;
@@ -96,6 +97,8 @@ public final void onEnable() {
9697
initializeDependencyInjection();
9798
Sharables.init(this);
9899
Perm.register(this);
100+
ItemStackConverter.init(this);
101+
Logging.fine("ItemStackConverter is using byte serialization: " + ItemStackConverter.hasByteSerializeSupport);
99102
this.reloadConfig();
100103
inventoriesConfig.get().save().onFailure(e -> Logging.severe("Failed to save config file!"));
101104

src/main/java/org/mvplugins/multiverse/inventories/config/InventoriesConfig.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,14 @@ public Try<Void> setApplyLastLocationForAllTeleports(boolean applyLastLocationFo
167167
return this.configHandle.set(configNodes.applyLastLocationForAllTeleports, applyLastLocationForAllTeleports);
168168
}
169169

170+
public boolean getUseByteSerializationForInventoryData() {
171+
return this.configHandle.get(configNodes.useByteSerializationForInventoryData);
172+
}
173+
174+
public Try<Void> setUseByteSerializationForInventoryData(boolean useByteSerializationForInventoryData) {
175+
return this.configHandle.set(configNodes.useByteSerializationForInventoryData, useByteSerializationForInventoryData);
176+
}
177+
170178
/**
171179
* Tells whether Multiverse-Inventories should save on player logout.
172180
*

src/main/java/org/mvplugins/multiverse/inventories/config/InventoriesConfigNodes.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,13 @@ public Object serialize(Shares sharables, Class<Shares> aClass) {
135135
.name("apply-last-location-for-all-teleports")
136136
.build());
137137

138+
final ConfigNode<Boolean> useByteSerializationForInventoryData = node(ConfigNode.builder("sharables.use-byte-serialization-for-inventory-data", Boolean.class)
139+
.comment("")
140+
.comment("When enabled, we will use byte serialization for inventory data.")
141+
.defaultValue(false)
142+
.name("use-byte-serialization-for-inventory-data")
143+
.build());
144+
138145
private final ConfigHeaderNode performanceHeader = node(ConfigHeaderNode.builder("performance")
139146
.comment("")
140147
.comment("")

src/main/java/org/mvplugins/multiverse/inventories/handleshare/ShareHandler.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ private void updatePersistingProfile(PersistingProfile persistingProfile, Profil
115115
}
116116

117117
private void logHandlingComplete(double timeTaken, ShareHandlingEvent event) {
118-
Logging.fine("=== %s complete for %s | time taken: %4.4f ms ===", player.getName(), event.getEventName(), timeTaken);
118+
Logging.fine("=== %s complete for %s | \u001B[32mtime taken: %4.4f ms\u001B[0m ===",
119+
player.getName(), event.getEventName(), timeTaken);
119120
}
120121
}

src/main/java/org/mvplugins/multiverse/inventories/share/InventorySerializer.java

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.mvplugins.multiverse.inventories.share;
22

3+
import org.mvplugins.multiverse.inventories.util.ItemStackConverter;
34
import org.mvplugins.multiverse.inventories.util.MinecraftTools;
45
import org.bukkit.Material;
56
import org.bukkit.inventory.ItemStack;
@@ -29,11 +30,14 @@ public Object serialize(ItemStack[] itemStacks) {
2930
return mapSlots(itemStacks);
3031
}
3132

32-
private Map<String, ItemStack> mapSlots(ItemStack[] itemStacks) {
33-
Map<String, ItemStack> result = new HashMap<>(itemStacks.length);
33+
private Map<String, Object> mapSlots(ItemStack[] itemStacks) {
34+
Map<String, Object> result = new HashMap<>(itemStacks.length);
3435
for (int i = 0; i < itemStacks.length; i++) {
3536
if (itemStacks[i] != null && itemStacks[i].getType() != Material.AIR) {
36-
result.put(Integer.toString(i), itemStacks[i]);
37+
Object serialize = ItemStackConverter.serialize(itemStacks[i]);
38+
if (serialize != null) {
39+
result.put(Integer.toString(i), serialize);
40+
}
3741
}
3842
}
3943
return result;
@@ -46,7 +50,16 @@ private ItemStack[] unmapSlots(Object obj) {
4650
}
4751
for (int i = 0; i < inventory.length; i++) {
4852
Object value = invMap.get(Integer.toString(i));
49-
inventory[i] = value instanceof ItemStack item ? item : new ItemStack(Material.AIR);
53+
if (value == null) {
54+
inventory[i] = new ItemStack(Material.AIR);
55+
continue;
56+
}
57+
ItemStack item = ItemStackConverter.deserialize(value);
58+
if (item == null) {
59+
inventory[i] = new ItemStack(Material.AIR);
60+
continue;
61+
}
62+
inventory[i] = item;
5063
}
5164
return inventory;
5265
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package org.mvplugins.multiverse.inventories.share;
2+
3+
import org.bukkit.inventory.ItemStack;
4+
import org.mvplugins.multiverse.inventories.util.ItemStackConverter;
5+
6+
final class ItemStackSerializer implements SharableSerializer<ItemStack> {
7+
8+
@Override
9+
public ItemStack deserialize(Object obj) {
10+
return ItemStackConverter.deserialize(obj);
11+
}
12+
13+
@Override
14+
public Object serialize(ItemStack itemStack) {
15+
return ItemStackConverter.serialize(itemStack);
16+
}
17+
}

src/main/java/org/mvplugins/multiverse/inventories/share/Sharables.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ public boolean updatePlayer(Player player, ProfileData profile) {
188188
return true;
189189
}
190190
}).serializer(new ProfileEntry(false, DataStrings.PLAYER_OFF_HAND_ITEM),
191-
new DefaultSerializer<>(ItemStack.class)).altName("shield").build();
191+
new ItemStackSerializer()).altName("shield").build();
192192

193193
/**
194194
* Sharing Max Health.
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package org.mvplugins.multiverse.inventories.util;
2+
3+
import com.dumptruckman.minecraft.util.Logging;
4+
import org.bukkit.Material;
5+
import org.bukkit.inventory.ItemStack;
6+
import org.jetbrains.annotations.Nullable;
7+
import org.mvplugins.multiverse.external.vavr.control.Try;
8+
import org.mvplugins.multiverse.inventories.MultiverseInventories;
9+
import org.mvplugins.multiverse.inventories.config.InventoriesConfig;
10+
11+
import java.util.Base64;
12+
13+
public final class ItemStackConverter {
14+
15+
public final static boolean hasByteSerializeSupport;
16+
17+
static {
18+
hasByteSerializeSupport = Try.run(() -> ItemStack.class.getMethod("deserializeBytes", byte[].class))
19+
.map(ignore -> true)
20+
.recover(ignore -> false)
21+
.getOrElse(false);
22+
}
23+
24+
private static InventoriesConfig config = null;
25+
26+
public static void init(MultiverseInventories plugin) {
27+
config = plugin.getServiceLocator().getService(InventoriesConfig.class);
28+
}
29+
30+
@Nullable
31+
public static ItemStack deserialize(Object obj) {
32+
if (obj instanceof ItemStack itemStack) {
33+
// Already handled by ConfigurationSerialization
34+
return itemStack;
35+
}
36+
if (hasByteSerializeSupport && obj instanceof String string) {
37+
byte[] bytes = Base64.getDecoder().decode(string);
38+
return ItemStack.deserializeBytes(bytes);
39+
}
40+
return null;
41+
}
42+
43+
@Nullable
44+
public static Object serialize(ItemStack itemStack) {
45+
if (config != null && config.getUseByteSerializationForInventoryData() && hasByteSerializeSupport) {
46+
if (itemStack.getType() == Material.AIR) {
47+
return null;
48+
}
49+
return Try.of(() -> Base64.getEncoder().encodeToString(itemStack.serializeAsBytes()))
50+
.onFailure(e -> Logging.severe("Could not serialize item stack: %s", e.getMessage()))
51+
.getOrNull();
52+
}
53+
// let ConfigurationSerialization handle it
54+
return itemStack;
55+
}
56+
57+
private ItemStackConverter() {
58+
// no instantiation
59+
}
60+
}

src/test/resources/config/fresh_config.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ sharables:
99
use-improved-respawn-location-detection: true
1010
reset-last-location-on-death: false
1111
apply-last-location-for-all-teleports: true
12+
use-byte-serialization-for-inventory-data: false
1213

1314
performance:
1415
save-playerdata-on-quit: false

0 commit comments

Comments
 (0)