Added ReflectionStorage (mostly version-independent)
(Started on 2019.08.29.) This means it supports 1.14.4 It automatically falls back to the previous storage if the newer version is not found
This commit is contained in:
parent
14bdf0ebe0
commit
6d5f42b2a5
3 changed files with 355 additions and 142 deletions
4
pom.xml
4
pom.xml
|
@ -159,8 +159,8 @@
|
|||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>2.3.2</version>
|
||||
<configuration>
|
||||
<source>1.6</source>
|
||||
<target>1.6</target>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
<annotationProcessors>
|
||||
<!-- Needed to fetch DocComments from Source -->
|
||||
<annotationProcessor>de.jaschastarke.maven.AnnotationProcessor</annotationProcessor>
|
||||
|
|
|
@ -1,140 +1,136 @@
|
|||
package de.jaschastarke.minecraft.limitedcreative;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import de.jaschastarke.bukkit.lib.CoreModule;
|
||||
import de.jaschastarke.minecraft.limitedcreative.inventories.ArmoryConfig;
|
||||
import de.jaschastarke.minecraft.limitedcreative.inventories.Inventory;
|
||||
import de.jaschastarke.minecraft.limitedcreative.inventories.InventoryConfig;
|
||||
import de.jaschastarke.minecraft.limitedcreative.inventories.InventoryPermissions;
|
||||
import de.jaschastarke.minecraft.limitedcreative.inventories.PlayerListener;
|
||||
import de.jaschastarke.minecraft.limitedcreative.inventories.store.InvYamlStorage;
|
||||
import de.jaschastarke.minecraft.limitedcreative.inventories.store.PlayerInventoryStorage;
|
||||
import de.jaschastarke.modularize.IModule;
|
||||
import de.jaschastarke.modularize.ModuleEntry;
|
||||
|
||||
public class ModInventories extends CoreModule<LimitedCreative> {
|
||||
protected PlayerInventoryStorage storage;
|
||||
protected Map<Player, Inventory> inventories;
|
||||
protected InventoryConfig config;
|
||||
protected ArmoryConfig armor_config;
|
||||
|
||||
public ModInventories(LimitedCreative plugin) {
|
||||
super(plugin);
|
||||
}
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Inventory";
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public void initialize(ModuleEntry<IModule> entry) {
|
||||
super.initialize(entry);
|
||||
listeners.addListener(new PlayerListener(this));
|
||||
config = plugin.getPluginConfig().registerSection(new InventoryConfig(this, entry));
|
||||
armor_config = config.registerSection(new ArmoryConfig(this));
|
||||
|
||||
if (Hooks.isAuthMePresent()) {
|
||||
addModule(new de.jaschastarke.minecraft.limitedcreative.inventories.AuthMeInventories(plugin, this));
|
||||
}
|
||||
String incomp = Hooks.InventoryIncompatible.test();
|
||||
if (config.getEnabled() && incomp != null) {
|
||||
getLog().warn(plugin.getLocale().trans("inventory.warning.conflict", incomp, this.getName()));
|
||||
entry.deactivateUsage();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void onEnable() {
|
||||
String incomp = Hooks.InventoryIncompatible.test();
|
||||
if (incomp != null) {
|
||||
throw new IllegalAccessError(plugin.getLocale().trans("inventory.warning.conflict", incomp, this.getName()));
|
||||
}
|
||||
super.onEnable();
|
||||
storage = new InvYamlStorage(this, new File(plugin.getDataFolder(), config.getFolder()));
|
||||
inventories = new WeakHashMap<Player, Inventory>();
|
||||
getLog().info(plugin.getLocale().trans("basic.loaded.module"));
|
||||
}
|
||||
public InventoryConfig getConfig() {
|
||||
return config;
|
||||
}
|
||||
public ArmoryConfig getArmorConfig() {
|
||||
return armor_config;
|
||||
}
|
||||
|
||||
public PlayerInventoryStorage getStorage() {
|
||||
return storage;
|
||||
}
|
||||
|
||||
public Inventory getInventory(Player player) {
|
||||
if (inventories.containsKey(player)) {
|
||||
return inventories.get(player);
|
||||
} else {
|
||||
Inventory inv = new Inventory(storage, player);
|
||||
inventories.put(player, inv);
|
||||
return inv;
|
||||
}
|
||||
}
|
||||
|
||||
public void onSetGameMode(Player player, GameMode gm) {
|
||||
if (plugin.getPermManager().hasPermission(player, InventoryPermissions.KEEP_INVENTORY))
|
||||
return;
|
||||
player.closeInventory();
|
||||
|
||||
GameMode cgm = player.getGameMode();
|
||||
if (gm == GameMode.ADVENTURE && !config.getSeparateAdventure())
|
||||
gm = GameMode.SURVIVAL;
|
||||
else if (gm == GameMode.SPECTATOR)
|
||||
gm = GameMode.CREATIVE;
|
||||
if (cgm == GameMode.ADVENTURE && !config.getSeparateAdventure())
|
||||
cgm = GameMode.SURVIVAL;
|
||||
else if (cgm == GameMode.SPECTATOR)
|
||||
cgm = GameMode.CREATIVE;
|
||||
|
||||
if (gm != cgm) {
|
||||
if (gm != GameMode.CREATIVE || config.getStoreCreative()) {
|
||||
getInventory(player).save(cgm);
|
||||
}
|
||||
if (gm == GameMode.CREATIVE) {
|
||||
if (config.getStoreCreative() && getInventory(player).isStored(GameMode.CREATIVE)) {
|
||||
getInventory(player).load(GameMode.CREATIVE);
|
||||
} else {
|
||||
getInventory(player).clear();
|
||||
}
|
||||
setCreativeArmor(player);
|
||||
} else if (gm == GameMode.SURVIVAL) {
|
||||
if (getInventory(player).isStored(GameMode.SURVIVAL))
|
||||
getInventory(player).load(GameMode.SURVIVAL);
|
||||
} else if (gm == GameMode.ADVENTURE) {
|
||||
if (getInventory(player).isStored(GameMode.ADVENTURE))
|
||||
getInventory(player).load(GameMode.ADVENTURE);
|
||||
else
|
||||
getInventory(player).clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setCreativeArmor(Player player) {
|
||||
if (!getPlugin().getPermManager().hasPermission(player, InventoryPermissions.BYPASS_CREATIVE_ARMOR)) {
|
||||
Map<String, ItemStack> armor = armor_config.getCreativeArmor();
|
||||
if (armor != null) {
|
||||
ItemStack[] is = new ItemStack[4];
|
||||
if (armor.containsKey("feet"))
|
||||
is[0] = armor.get("feet");
|
||||
if (armor.containsKey("legs"))
|
||||
is[1] = armor.get("legs");
|
||||
if (armor.containsKey("chest"))
|
||||
is[2] = armor.get("chest");
|
||||
if (armor.containsKey("head"))
|
||||
is[3] = armor.get("head");
|
||||
player.getInventory().setArmorContents(is);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
package de.jaschastarke.minecraft.limitedcreative;
|
||||
|
||||
import de.jaschastarke.bukkit.lib.CoreModule;
|
||||
import de.jaschastarke.minecraft.limitedcreative.inventories.*;
|
||||
import de.jaschastarke.minecraft.limitedcreative.inventories.store.PlayerInventoryStorage;
|
||||
import de.jaschastarke.minecraft.limitedcreative.inventories.store.ReflectionStorage;
|
||||
import de.jaschastarke.modularize.IModule;
|
||||
import de.jaschastarke.modularize.ModuleEntry;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
public class ModInventories extends CoreModule<LimitedCreative> {
|
||||
protected PlayerInventoryStorage storage;
|
||||
protected Map<Player, Inventory> inventories;
|
||||
protected InventoryConfig config;
|
||||
protected ArmoryConfig armor_config;
|
||||
|
||||
public ModInventories(LimitedCreative plugin) {
|
||||
super(plugin);
|
||||
}
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Inventory";
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public void initialize(ModuleEntry<IModule> entry) {
|
||||
super.initialize(entry);
|
||||
listeners.addListener(new PlayerListener(this));
|
||||
config = plugin.getPluginConfig().registerSection(new InventoryConfig(this, entry));
|
||||
armor_config = config.registerSection(new ArmoryConfig(this));
|
||||
|
||||
if (Hooks.isAuthMePresent()) {
|
||||
addModule(new de.jaschastarke.minecraft.limitedcreative.inventories.AuthMeInventories(plugin, this));
|
||||
}
|
||||
String incomp = Hooks.InventoryIncompatible.test();
|
||||
if (config.getEnabled() && incomp != null) {
|
||||
getLog().warn(plugin.getLocale().trans("inventory.warning.conflict", incomp, this.getName()));
|
||||
entry.deactivateUsage();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void onEnable() {
|
||||
String incomp = Hooks.InventoryIncompatible.test();
|
||||
if (incomp != null) {
|
||||
throw new IllegalAccessError(plugin.getLocale().trans("inventory.warning.conflict", incomp, this.getName()));
|
||||
}
|
||||
super.onEnable();
|
||||
//storage = new InvYamlStorage(this, new File(plugin.getDataFolder(), config.getFolder()));
|
||||
storage = new ReflectionStorage(this, new File(plugin.getDataFolder(), config.getFolder()));
|
||||
inventories = new WeakHashMap<Player, Inventory>();
|
||||
getLog().info(plugin.getLocale().trans("basic.loaded.module"));
|
||||
}
|
||||
public InventoryConfig getConfig() {
|
||||
return config;
|
||||
}
|
||||
public ArmoryConfig getArmorConfig() {
|
||||
return armor_config;
|
||||
}
|
||||
|
||||
public PlayerInventoryStorage getStorage() {
|
||||
return storage;
|
||||
}
|
||||
|
||||
public Inventory getInventory(Player player) {
|
||||
if (inventories.containsKey(player)) {
|
||||
return inventories.get(player);
|
||||
} else {
|
||||
Inventory inv = new Inventory(storage, player);
|
||||
inventories.put(player, inv);
|
||||
return inv;
|
||||
}
|
||||
}
|
||||
|
||||
public void onSetGameMode(Player player, GameMode gm) {
|
||||
if (plugin.getPermManager().hasPermission(player, InventoryPermissions.KEEP_INVENTORY))
|
||||
return;
|
||||
player.closeInventory();
|
||||
|
||||
GameMode cgm = player.getGameMode();
|
||||
if (gm == GameMode.ADVENTURE && !config.getSeparateAdventure())
|
||||
gm = GameMode.SURVIVAL;
|
||||
else if (gm == GameMode.SPECTATOR)
|
||||
gm = GameMode.CREATIVE;
|
||||
if (cgm == GameMode.ADVENTURE && !config.getSeparateAdventure())
|
||||
cgm = GameMode.SURVIVAL;
|
||||
else if (cgm == GameMode.SPECTATOR)
|
||||
cgm = GameMode.CREATIVE;
|
||||
|
||||
if (gm != cgm) {
|
||||
if (gm != GameMode.CREATIVE || config.getStoreCreative()) {
|
||||
getInventory(player).save(cgm);
|
||||
}
|
||||
if (gm == GameMode.CREATIVE) {
|
||||
if (config.getStoreCreative() && getInventory(player).isStored(GameMode.CREATIVE)) {
|
||||
getInventory(player).load(GameMode.CREATIVE);
|
||||
} else {
|
||||
getInventory(player).clear();
|
||||
}
|
||||
setCreativeArmor(player);
|
||||
} else if (gm == GameMode.SURVIVAL) {
|
||||
if (getInventory(player).isStored(GameMode.SURVIVAL))
|
||||
getInventory(player).load(GameMode.SURVIVAL);
|
||||
} else if (gm == GameMode.ADVENTURE) {
|
||||
if (getInventory(player).isStored(GameMode.ADVENTURE))
|
||||
getInventory(player).load(GameMode.ADVENTURE);
|
||||
else
|
||||
getInventory(player).clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setCreativeArmor(Player player) {
|
||||
if (!getPlugin().getPermManager().hasPermission(player, InventoryPermissions.BYPASS_CREATIVE_ARMOR)) {
|
||||
Map<String, ItemStack> armor = armor_config.getCreativeArmor();
|
||||
if (armor != null) {
|
||||
ItemStack[] is = new ItemStack[4];
|
||||
if (armor.containsKey("feet"))
|
||||
is[0] = armor.get("feet");
|
||||
if (armor.containsKey("legs"))
|
||||
is[1] = armor.get("legs");
|
||||
if (armor.containsKey("chest"))
|
||||
is[2] = armor.get("chest");
|
||||
if (armor.containsKey("head"))
|
||||
is[3] = armor.get("head");
|
||||
player.getInventory().setArmorContents(is);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,217 @@
|
|||
package de.jaschastarke.minecraft.limitedcreative.inventories.store;
|
||||
|
||||
import de.jaschastarke.bukkit.lib.CoreModule;
|
||||
import de.jaschastarke.bukkit.lib.ModuleLogger;
|
||||
import de.jaschastarke.minecraft.limitedcreative.inventories.Inventory;
|
||||
import org.bukkit.configuration.Configuration;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.Base64;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class ReflectionStorage extends PlayerInventoryStorage {
|
||||
private CoreModule<?> mod;
|
||||
private File dir;
|
||||
private String nms;
|
||||
private InvYamlStorage yamlStorage;
|
||||
|
||||
public ReflectionStorage(CoreModule<?> mod, File file) {
|
||||
this.mod = mod;
|
||||
dir = file;
|
||||
yamlStorage = new InvYamlStorage(mod, file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModuleLogger getLog() {
|
||||
return mod.getLog();
|
||||
}
|
||||
|
||||
private File getFile(UUID uuid) {
|
||||
return new File(dir, uuid.toString() + "_ref.yml");
|
||||
}
|
||||
|
||||
private Object getInventory(Player player) throws Exception {
|
||||
org.bukkit.inventory.Inventory inv = player.getInventory();
|
||||
if (getInventory == null)
|
||||
getInventory = inv.getClass().getMethod("getInventory");
|
||||
Object handle = getInventory.invoke(inv);
|
||||
if (nms == null)
|
||||
nms = handle.getClass().getPackage().getName();
|
||||
return handle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void store(Inventory pinv, Inventory.Target target) {
|
||||
try {
|
||||
File f = getFile(pinv.getPlayer().getUniqueId());
|
||||
YamlConfiguration config = YamlConfiguration.loadConfiguration(f);
|
||||
config.set(target.name(), serialize(getInventory(pinv.getPlayer())));
|
||||
config.save(f);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private Method getInventory;
|
||||
|
||||
@Override
|
||||
public void load(Inventory pinv, Inventory.Target target) {
|
||||
Player player = pinv.getPlayer();
|
||||
try {
|
||||
File f = getFile(player.getUniqueId());
|
||||
if (!f.exists()) { //If not found use the older file(s)
|
||||
yamlStorage.load(pinv, target);
|
||||
return;
|
||||
}
|
||||
//String content = new String(Files.readAllBytes(f.toPath()));
|
||||
Configuration config = YamlConfiguration.loadConfiguration(f);
|
||||
String content = config.getString(target.name());
|
||||
if (content == null) {
|
||||
yamlStorage.load(pinv, target);
|
||||
return;
|
||||
}
|
||||
setFromSerialized(getInventory(player), content);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(Inventory pinv, Inventory.Target target) {
|
||||
File f = getFile(pinv.getPlayer().getUniqueId());
|
||||
if (!f.exists()) return;
|
||||
Configuration config = YamlConfiguration.loadConfiguration(f);
|
||||
config.set(target.name(), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Inventory pinv, Inventory.Target target) {
|
||||
File f = getFile(pinv.getPlayer().getUniqueId());
|
||||
if (!f.exists()) return yamlStorage.contains(pinv, target);
|
||||
Configuration config = YamlConfiguration.loadConfiguration(f);
|
||||
return config.contains(target.name()) || yamlStorage.contains(pinv, target);
|
||||
}
|
||||
|
||||
//Based on iie's per-world inventory
|
||||
//https://github.com/TBMCPlugins/iiePerWorldInventory/blob/master/src/buttondevteam/perworld/serializers/inventory.java
|
||||
|
||||
private Method save;
|
||||
private Class<?> nbtcl;
|
||||
private Method nbtcsta;
|
||||
private Class<?> nbtcstcl;
|
||||
|
||||
//SERIALIZE ITEMSTACK
|
||||
private String serializeItemStack(Object itemStack) throws Exception {
|
||||
if (nbtcl == null)
|
||||
nbtcl = Class.forName(nms + ".NBTTagCompound");
|
||||
if (save == null)
|
||||
save = itemStack.getClass().getMethod("save", nbtcl);
|
||||
if (nbtcstcl == null)
|
||||
nbtcstcl = Class.forName(nms + ".NBTCompressedStreamTools");
|
||||
if (nbtcsta == null)
|
||||
nbtcsta = nbtcstcl.getMethod("a", nbtcl, OutputStream.class);
|
||||
Object tag = save.invoke(itemStack, nbtcl.newInstance());
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
|
||||
nbtcsta.invoke(null, tag, outputStream);
|
||||
|
||||
return Base64.getEncoder().encodeToString(outputStream.toByteArray());
|
||||
}
|
||||
|
||||
|
||||
private Method nbtcstaa;
|
||||
private Function<Object, Object> createStack;
|
||||
|
||||
//DESERIALIZE ITEMSTACK
|
||||
private Object deserializeItemStack(String itemStackString) throws Exception {
|
||||
if (nbtcstcl == null)
|
||||
nbtcstcl = Class.forName(nms + ".NBTCompressedStreamTools");
|
||||
if (nbtcstaa == null)
|
||||
nbtcstaa = nbtcstcl.getMethod("a", InputStream.class);
|
||||
if (nbtcl == null)
|
||||
nbtcl = Class.forName(nms + ".NBTTagCompound");
|
||||
try {
|
||||
if (createStack == null) {
|
||||
final Method a = iscl.getMethod("a", nbtcl);
|
||||
createStack = nbt -> {
|
||||
try {
|
||||
return a.invoke(null, nbt);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
};
|
||||
}
|
||||
} catch (NoSuchMethodException ex) { //It can only get here inside the if
|
||||
final Constructor<?> constructor = iscl.getConstructor(nbtcl);
|
||||
createStack = nbt -> {
|
||||
try {
|
||||
return constructor.newInstance(nbt);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
};
|
||||
}
|
||||
ByteArrayInputStream inputStream = new ByteArrayInputStream(Base64.getDecoder().decode(itemStackString));
|
||||
|
||||
Object nbtTagCompound = nbtcstaa.invoke(null, inputStream);
|
||||
return createStack.apply(nbtTagCompound);
|
||||
}
|
||||
|
||||
private Method getSize;
|
||||
private Method getItem;
|
||||
|
||||
//SERIALIZE INVENTORY
|
||||
private String serialize(Object invInventory) throws Exception {
|
||||
if (getSize == null)
|
||||
getSize = invInventory.getClass().getMethod("getSize");
|
||||
if (getItem == null)
|
||||
getItem = invInventory.getClass().getMethod("getItem", int.class);
|
||||
return IntStream.range(0, (int) getSize.invoke(invInventory))
|
||||
.mapToObj(s -> {
|
||||
try {
|
||||
//nms ItemStack
|
||||
Object i = getItem.invoke(invInventory, s);
|
||||
return Objects.isNull(i) ? null : s + "#" + serializeItemStack(i);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.joining(";"));
|
||||
}
|
||||
|
||||
private Method clear;
|
||||
private Method setItem;
|
||||
private Class<?> iscl;
|
||||
|
||||
//SET INVENTORY FROM SERIALIZED
|
||||
private void setFromSerialized(Object invInventory, String invString) throws Exception {
|
||||
if (clear == null)
|
||||
clear = invInventory.getClass().getMethod("clear");
|
||||
if (iscl == null)
|
||||
iscl = Class.forName(nms + ".ItemStack");
|
||||
if (setItem == null)
|
||||
setItem = invInventory.getClass().getMethod("setItem", int.class, iscl);
|
||||
clear.invoke(invInventory); //clear inventory
|
||||
if (invString != null && !invString.isEmpty())
|
||||
Arrays.asList(invString.split(";"))
|
||||
.parallelStream()
|
||||
.forEach(s -> {
|
||||
String[] e = s.split("#");
|
||||
try {
|
||||
setItem.invoke(invInventory, Integer.parseInt(e[0]), deserializeItemStack(e[1]));
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue