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:
Norbi Peti 2019-09-21 16:14:58 +02:00
parent 14bdf0ebe0
commit 6d5f42b2a5
No known key found for this signature in database
GPG key ID: DBA4C4549A927E56
3 changed files with 355 additions and 142 deletions

View file

@ -159,8 +159,8 @@
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version> <version>2.3.2</version>
<configuration> <configuration>
<source>1.6</source> <source>1.8</source>
<target>1.6</target> <target>1.8</target>
<annotationProcessors> <annotationProcessors>
<!-- Needed to fetch DocComments from Source --> <!-- Needed to fetch DocComments from Source -->
<annotationProcessor>de.jaschastarke.maven.AnnotationProcessor</annotationProcessor> <annotationProcessor>de.jaschastarke.maven.AnnotationProcessor</annotationProcessor>

View file

@ -1,140 +1,136 @@
package de.jaschastarke.minecraft.limitedcreative; package de.jaschastarke.minecraft.limitedcreative;
import java.io.File; import de.jaschastarke.bukkit.lib.CoreModule;
import java.util.Map; import de.jaschastarke.minecraft.limitedcreative.inventories.*;
import java.util.WeakHashMap; import de.jaschastarke.minecraft.limitedcreative.inventories.store.PlayerInventoryStorage;
import de.jaschastarke.minecraft.limitedcreative.inventories.store.ReflectionStorage;
import org.bukkit.GameMode; import de.jaschastarke.modularize.IModule;
import org.bukkit.entity.Player; import de.jaschastarke.modularize.ModuleEntry;
import org.bukkit.inventory.ItemStack; import org.bukkit.GameMode;
import org.bukkit.entity.Player;
import de.jaschastarke.bukkit.lib.CoreModule; import org.bukkit.inventory.ItemStack;
import de.jaschastarke.minecraft.limitedcreative.inventories.ArmoryConfig;
import de.jaschastarke.minecraft.limitedcreative.inventories.Inventory; import java.io.File;
import de.jaschastarke.minecraft.limitedcreative.inventories.InventoryConfig; import java.util.Map;
import de.jaschastarke.minecraft.limitedcreative.inventories.InventoryPermissions; import java.util.WeakHashMap;
import de.jaschastarke.minecraft.limitedcreative.inventories.PlayerListener;
import de.jaschastarke.minecraft.limitedcreative.inventories.store.InvYamlStorage; public class ModInventories extends CoreModule<LimitedCreative> {
import de.jaschastarke.minecraft.limitedcreative.inventories.store.PlayerInventoryStorage; protected PlayerInventoryStorage storage;
import de.jaschastarke.modularize.IModule; protected Map<Player, Inventory> inventories;
import de.jaschastarke.modularize.ModuleEntry; protected InventoryConfig config;
protected ArmoryConfig armor_config;
public class ModInventories extends CoreModule<LimitedCreative> {
protected PlayerInventoryStorage storage; public ModInventories(LimitedCreative plugin) {
protected Map<Player, Inventory> inventories; super(plugin);
protected InventoryConfig config; }
protected ArmoryConfig armor_config; @Override
public String getName() {
public ModInventories(LimitedCreative plugin) { return "Inventory";
super(plugin); }
}
@Override @SuppressWarnings("deprecation")
public String getName() { @Override
return "Inventory"; public void initialize(ModuleEntry<IModule> entry) {
} super.initialize(entry);
listeners.addListener(new PlayerListener(this));
@SuppressWarnings("deprecation") config = plugin.getPluginConfig().registerSection(new InventoryConfig(this, entry));
@Override armor_config = config.registerSection(new ArmoryConfig(this));
public void initialize(ModuleEntry<IModule> entry) {
super.initialize(entry); if (Hooks.isAuthMePresent()) {
listeners.addListener(new PlayerListener(this)); addModule(new de.jaschastarke.minecraft.limitedcreative.inventories.AuthMeInventories(plugin, this));
config = plugin.getPluginConfig().registerSection(new InventoryConfig(this, entry)); }
armor_config = config.registerSection(new ArmoryConfig(this)); String incomp = Hooks.InventoryIncompatible.test();
if (config.getEnabled() && incomp != null) {
if (Hooks.isAuthMePresent()) { getLog().warn(plugin.getLocale().trans("inventory.warning.conflict", incomp, this.getName()));
addModule(new de.jaschastarke.minecraft.limitedcreative.inventories.AuthMeInventories(plugin, this)); entry.deactivateUsage();
} }
String incomp = Hooks.InventoryIncompatible.test(); }
if (config.getEnabled() && incomp != null) { @Override
getLog().warn(plugin.getLocale().trans("inventory.warning.conflict", incomp, this.getName())); public void onEnable() {
entry.deactivateUsage(); String incomp = Hooks.InventoryIncompatible.test();
} if (incomp != null) {
} throw new IllegalAccessError(plugin.getLocale().trans("inventory.warning.conflict", incomp, this.getName()));
@Override }
public void onEnable() { super.onEnable();
String incomp = Hooks.InventoryIncompatible.test(); //storage = new InvYamlStorage(this, new File(plugin.getDataFolder(), config.getFolder()));
if (incomp != null) { storage = new ReflectionStorage(this, new File(plugin.getDataFolder(), config.getFolder()));
throw new IllegalAccessError(plugin.getLocale().trans("inventory.warning.conflict", incomp, this.getName())); inventories = new WeakHashMap<Player, Inventory>();
} getLog().info(plugin.getLocale().trans("basic.loaded.module"));
super.onEnable(); }
storage = new InvYamlStorage(this, new File(plugin.getDataFolder(), config.getFolder())); public InventoryConfig getConfig() {
inventories = new WeakHashMap<Player, Inventory>(); return config;
getLog().info(plugin.getLocale().trans("basic.loaded.module")); }
} public ArmoryConfig getArmorConfig() {
public InventoryConfig getConfig() { return armor_config;
return config; }
}
public ArmoryConfig getArmorConfig() { public PlayerInventoryStorage getStorage() {
return armor_config; return storage;
} }
public PlayerInventoryStorage getStorage() { public Inventory getInventory(Player player) {
return storage; if (inventories.containsKey(player)) {
} return inventories.get(player);
} else {
public Inventory getInventory(Player player) { Inventory inv = new Inventory(storage, player);
if (inventories.containsKey(player)) { inventories.put(player, inv);
return inventories.get(player); return inv;
} 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();
public void onSetGameMode(Player player, GameMode gm) {
if (plugin.getPermManager().hasPermission(player, InventoryPermissions.KEEP_INVENTORY)) GameMode cgm = player.getGameMode();
return; if (gm == GameMode.ADVENTURE && !config.getSeparateAdventure())
player.closeInventory(); gm = GameMode.SURVIVAL;
else if (gm == GameMode.SPECTATOR)
GameMode cgm = player.getGameMode(); gm = GameMode.CREATIVE;
if (gm == GameMode.ADVENTURE && !config.getSeparateAdventure()) if (cgm == GameMode.ADVENTURE && !config.getSeparateAdventure())
gm = GameMode.SURVIVAL; cgm = GameMode.SURVIVAL;
else if (gm == GameMode.SPECTATOR) else if (cgm == GameMode.SPECTATOR)
gm = GameMode.CREATIVE; cgm = GameMode.CREATIVE;
if (cgm == GameMode.ADVENTURE && !config.getSeparateAdventure())
cgm = GameMode.SURVIVAL; if (gm != cgm) {
else if (cgm == GameMode.SPECTATOR) if (gm != GameMode.CREATIVE || config.getStoreCreative()) {
cgm = GameMode.CREATIVE; getInventory(player).save(cgm);
}
if (gm != cgm) { if (gm == GameMode.CREATIVE) {
if (gm != GameMode.CREATIVE || config.getStoreCreative()) { if (config.getStoreCreative() && getInventory(player).isStored(GameMode.CREATIVE)) {
getInventory(player).save(cgm); getInventory(player).load(GameMode.CREATIVE);
} } else {
if (gm == GameMode.CREATIVE) { getInventory(player).clear();
if (config.getStoreCreative() && getInventory(player).isStored(GameMode.CREATIVE)) { }
getInventory(player).load(GameMode.CREATIVE); setCreativeArmor(player);
} else { } else if (gm == GameMode.SURVIVAL) {
getInventory(player).clear(); if (getInventory(player).isStored(GameMode.SURVIVAL))
} getInventory(player).load(GameMode.SURVIVAL);
setCreativeArmor(player); } else if (gm == GameMode.ADVENTURE) {
} else if (gm == GameMode.SURVIVAL) { if (getInventory(player).isStored(GameMode.ADVENTURE))
if (getInventory(player).isStored(GameMode.SURVIVAL)) getInventory(player).load(GameMode.ADVENTURE);
getInventory(player).load(GameMode.SURVIVAL); else
} else if (gm == GameMode.ADVENTURE) { getInventory(player).clear();
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) {
public void setCreativeArmor(Player player) { ItemStack[] is = new ItemStack[4];
if (!getPlugin().getPermManager().hasPermission(player, InventoryPermissions.BYPASS_CREATIVE_ARMOR)) { if (armor.containsKey("feet"))
Map<String, ItemStack> armor = armor_config.getCreativeArmor(); is[0] = armor.get("feet");
if (armor != null) { if (armor.containsKey("legs"))
ItemStack[] is = new ItemStack[4]; is[1] = armor.get("legs");
if (armor.containsKey("feet")) if (armor.containsKey("chest"))
is[0] = armor.get("feet"); is[2] = armor.get("chest");
if (armor.containsKey("legs")) if (armor.containsKey("head"))
is[1] = armor.get("legs"); is[3] = armor.get("head");
if (armor.containsKey("chest")) player.getInventory().setArmorContents(is);
is[2] = armor.get("chest"); }
if (armor.containsKey("head")) }
is[3] = armor.get("head"); }
player.getInventory().setArmorContents(is); }
}
}
}
}

View file

@ -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);
}
});
}
}