mirror of
https://github.com/DieReicheErethons/Brewery.git
synced 2025-01-23 21:21:20 +01:00
Implemented NBT Saving
1.13: CustomItemTagContainer 1.14: PersistentDataContainer
This commit is contained in:
parent
f431c13100
commit
4909e59c90
4
pom.xml
4
pom.xml
@ -76,7 +76,7 @@
|
||||
</repository>
|
||||
<repository>
|
||||
<id>spigot-repo</id>
|
||||
<url>https://hub.spigotmc.org/nexus/content/groups/public/</url>
|
||||
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>vault-repo</id>
|
||||
@ -111,7 +111,7 @@
|
||||
<dependency>
|
||||
<groupId>org.bukkit</groupId>
|
||||
<artifactId>bukkit</artifactId>
|
||||
<version>1.14-R0.1-SNAPSHOT</version>
|
||||
<version>1.14.4-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
|
@ -60,7 +60,9 @@ public class BDistiller {
|
||||
final int fuel = standInv.getHolder().getFuelLevel();
|
||||
|
||||
// Now check if we should bother to track it.
|
||||
trackedDistillers.put(standBlock, new BDistiller(standBlock, fuel)).start();
|
||||
distiller = new BDistiller(standBlock, fuel);
|
||||
trackedDistillers.put(standBlock, distiller);
|
||||
distiller.start();
|
||||
}
|
||||
|
||||
// Returns a Brew or null for every Slot in the BrewerInventory
|
||||
|
@ -16,10 +16,7 @@ import org.bukkit.potion.PotionEffectType;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.*;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.ArrayList;
|
||||
@ -44,6 +41,7 @@ public class Brew {
|
||||
private boolean persistent; // Only for legacy
|
||||
private boolean immutable; // static/immutable potions should not be changed
|
||||
private int lastUpdate; // last update in hours after install time
|
||||
private boolean needsSave; // There was a change that has not yet been saved
|
||||
|
||||
public Brew(BIngredients ingredients) {
|
||||
this.ingredients = ingredients;
|
||||
@ -78,7 +76,7 @@ public class Brew {
|
||||
// returns a Brew by ItemMeta
|
||||
@Nullable
|
||||
public static Brew get(ItemMeta meta) {
|
||||
if (!meta.hasLore()) return null;
|
||||
if (!P.useNBT && !meta.hasLore()) return null;
|
||||
|
||||
Brew brew = load(meta);
|
||||
|
||||
@ -96,7 +94,7 @@ public class Brew {
|
||||
if (!item.hasItemMeta()) return null;
|
||||
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
if (!meta.hasLore()) return null;
|
||||
if (!P.useNBT && !meta.hasLore()) return null;
|
||||
|
||||
Brew brew = load(meta);
|
||||
|
||||
@ -104,7 +102,16 @@ public class Brew {
|
||||
// Load Legacy and convert
|
||||
brew = getFromPotionEffect(((PotionMeta) meta), true);
|
||||
if (brew == null) return null;
|
||||
new BrewLore(brew, ((PotionMeta) meta)).removeLegacySpacing();
|
||||
new BrewLore(brew, (PotionMeta) meta).removeLegacySpacing();
|
||||
brew.save(meta);
|
||||
item.setItemMeta(meta);
|
||||
} else if (brew != null && brew.needsSave) {
|
||||
// Brew needs saving from a previous format
|
||||
P.p.debugLog("Brew needs saving from previous format");
|
||||
if (P.useNBT) {
|
||||
new BrewLore(brew, (PotionMeta) meta).removeLoreData();
|
||||
P.p.debugLog("removed Data from Lore");
|
||||
}
|
||||
brew.save(meta);
|
||||
item.setItemMeta(meta);
|
||||
}
|
||||
@ -434,6 +441,14 @@ public class Brew {
|
||||
return unlabeled;
|
||||
}
|
||||
|
||||
public boolean needsSave() {
|
||||
return needsSave;
|
||||
}
|
||||
|
||||
public void setNeedsSave(boolean needsSave) {
|
||||
this.needsSave = needsSave;
|
||||
}
|
||||
|
||||
// Set the Static flag, so potion is unchangeable
|
||||
public void setStatic(boolean immutable, ItemStack potion) {
|
||||
this.immutable = immutable;
|
||||
@ -660,14 +675,25 @@ public class Brew {
|
||||
}
|
||||
|
||||
private static Brew load(ItemMeta meta) {
|
||||
LoreLoadStream loreStream;
|
||||
try {
|
||||
loreStream = new LoreLoadStream(meta, 0);
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
// No Brew data found in Meta
|
||||
return null;
|
||||
InputStream itemLoadStream = null;
|
||||
if (P.useNBT) {
|
||||
// Try loading the Item Data from PersistentDataContainer
|
||||
NBTLoadStream nbtStream = new NBTLoadStream(meta);
|
||||
if (nbtStream.hasData()) {
|
||||
itemLoadStream = nbtStream;
|
||||
}
|
||||
}
|
||||
XORUnscrambleStream unscrambler = new XORUnscrambleStream(new Base91DecoderStream(loreStream), saveSeed, prevSaveSeeds);
|
||||
if (itemLoadStream == null) {
|
||||
// If either NBT is not supported or no data was found in NBT, try loading from Lore
|
||||
try {
|
||||
itemLoadStream = new Base91DecoderStream(new LoreLoadStream(meta, 0));
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
// No Brew data found in Meta
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
XORUnscrambleStream unscrambler = new XORUnscrambleStream(itemLoadStream, saveSeed, prevSaveSeeds);
|
||||
try (DataInputStream in = new DataInputStream(unscrambler)) {
|
||||
boolean parityFailed = false;
|
||||
if (in.readByte() != 86) {
|
||||
@ -678,8 +704,10 @@ public class Brew {
|
||||
byte ver = in.readByte();
|
||||
switch (ver) {
|
||||
case 1:
|
||||
|
||||
unscrambler.start();
|
||||
brew.loadFromStream(in);
|
||||
|
||||
break;
|
||||
default:
|
||||
if (parityFailed) {
|
||||
@ -689,6 +717,18 @@ public class Brew {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
XORUnscrambleStream.SuccessType successType = unscrambler.getSuccessType();
|
||||
if (successType == XORUnscrambleStream.SuccessType.PREV_SEED) {
|
||||
brew.setNeedsSave(true);
|
||||
} else if (BConfig.enableEncode != (successType == XORUnscrambleStream.SuccessType.MAIN_SEED)) {
|
||||
// We have either enabled encode and the data was not encoded or the other way round
|
||||
brew.setNeedsSave(true);
|
||||
} else if (P.useNBT && itemLoadStream instanceof Base91DecoderStream) {
|
||||
// We are on a version that supports nbt but the data is still in the lore of the item
|
||||
// Just save it again so that it gets saved to nbt
|
||||
brew.setNeedsSave(true);
|
||||
}
|
||||
return brew;
|
||||
} catch (IOException e) {
|
||||
P.p.errorLog("IO Error while loading Brew");
|
||||
@ -723,9 +763,15 @@ public class Brew {
|
||||
ingredients = BIngredients.load(in);
|
||||
}
|
||||
|
||||
// Save brew data into meta/lore
|
||||
// Save brew data into meta: lore/nbt
|
||||
public void save(ItemMeta meta) {
|
||||
XORScrambleStream scrambler = new XORScrambleStream(new Base91EncoderStream(new LoreSaveStream(meta, 0)), saveSeed);
|
||||
OutputStream itemSaveStream;
|
||||
if (P.useNBT) {
|
||||
itemSaveStream = new NBTSaveStream(meta);
|
||||
} else {
|
||||
itemSaveStream = new Base91EncoderStream(new LoreSaveStream(meta, 0));
|
||||
}
|
||||
XORScrambleStream scrambler = new XORScrambleStream(itemSaveStream, saveSeed);
|
||||
try (DataOutputStream out = new DataOutputStream(scrambler)) {
|
||||
out.writeByte(86); // Parity/sanity
|
||||
out.writeByte(1); // Version
|
||||
|
@ -9,6 +9,7 @@ import com.dre.brewery.integration.IntegrationListener;
|
||||
import com.dre.brewery.integration.LogBlockBarrel;
|
||||
import com.dre.brewery.listeners.*;
|
||||
import com.dre.brewery.utility.BUtil;
|
||||
import com.dre.brewery.utility.LegacyUtil;
|
||||
import org.apache.commons.lang.math.NumberUtils;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
@ -22,6 +23,7 @@ public class P extends JavaPlugin {
|
||||
public static P p;
|
||||
public static boolean debug;
|
||||
public static boolean useUUID;
|
||||
public static boolean useNBT;
|
||||
public static boolean use1_9;
|
||||
public static boolean use1_11;
|
||||
public static boolean use1_13;
|
||||
@ -51,6 +53,13 @@ public class P extends JavaPlugin {
|
||||
use1_13 = !v.matches("(^|.*[^.\\d])1\\.1[0-2]([^\\d].*|$)") && !v.matches("(^|.*[^.\\d])1\\.[0-9]([^\\d].*|$)");
|
||||
use1_14 = !v.matches("(^|.*[^.\\d])1\\.1[0-3]([^\\d].*|$)") && !v.matches("(^|.*[^.\\d])1\\.[0-9]([^\\d].*|$)");
|
||||
|
||||
//MC 1.13 uses a different NBT API than the newer versions..
|
||||
// We decide here which to use, the new or the old or none at all
|
||||
P.debug = true;
|
||||
if (LegacyUtil.initNbt()) {
|
||||
useNBT = true;
|
||||
}
|
||||
|
||||
//P.p.log("§" + (use1_9 ? "a":"c") + "1.9 " + "§" + (use1_11 ? "a":"c") + "1.11 " + "§" + (use1_13 ? "a":"c") + "1.13 " + "§" + (use1_14 ? "a":"c") + "1.14");
|
||||
|
||||
/*long master = new SecureRandom().nextLong();
|
||||
|
@ -189,12 +189,24 @@ public class BrewLore {
|
||||
}
|
||||
|
||||
public void removeLegacySpacing() {
|
||||
if (P.useNBT) {
|
||||
// Using NBT we don't get the invisible line, so we keep our spacing
|
||||
return;
|
||||
}
|
||||
if (lore.size() > 0 && lore.get(0).equals("")) {
|
||||
lore.remove(0);
|
||||
write();
|
||||
}
|
||||
}
|
||||
|
||||
public void removeLoreData() {
|
||||
int index = BUtil.indexOfStart(lore, LoreSaveStream.IDENTIFIER);
|
||||
if (index != -1) {
|
||||
lore.set(index, "");
|
||||
write();
|
||||
}
|
||||
}
|
||||
|
||||
// True if the PotionMeta has Lore in quality color
|
||||
public static boolean hasColorLore(PotionMeta meta) {
|
||||
if (!meta.hasLore()) return false;
|
||||
|
@ -8,6 +8,8 @@ import java.util.List;
|
||||
|
||||
public class LoreLoadStream extends ByteArrayInputStream {
|
||||
|
||||
public static final String IDENTIFIER = "§%";
|
||||
|
||||
public LoreLoadStream(ItemMeta meta) throws IllegalArgumentException {
|
||||
this(meta, -1);
|
||||
}
|
||||
@ -21,12 +23,12 @@ public class LoreLoadStream extends ByteArrayInputStream {
|
||||
List<String> lore = meta.getLore();
|
||||
if (lineNum >= 0) {
|
||||
String line = lore.get(lineNum);
|
||||
if (line.startsWith("§%")) {
|
||||
if (line.startsWith(IDENTIFIER)) {
|
||||
return loreLineToBytes(line);
|
||||
}
|
||||
}
|
||||
for (String line : lore) {
|
||||
if (line.startsWith("§%")) {
|
||||
if (line.startsWith(IDENTIFIER)) {
|
||||
return loreLineToBytes(line);
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,8 @@ import java.util.List;
|
||||
|
||||
public class LoreSaveStream extends ByteArrayOutputStream {
|
||||
|
||||
public static final String IDENTIFIER = "§%";
|
||||
|
||||
private ItemMeta meta;
|
||||
private int line;
|
||||
private boolean flushed = false;
|
||||
@ -38,7 +40,7 @@ public class LoreSaveStream extends ByteArrayOutputStream {
|
||||
String s = toString();
|
||||
|
||||
StringBuilder loreLineBuilder = new StringBuilder((s.length() * 2) + 6);
|
||||
loreLineBuilder.append("§%");
|
||||
loreLineBuilder.append(IDENTIFIER);
|
||||
for (char c : s.toCharArray()) {
|
||||
loreLineBuilder.append('§').append(c);
|
||||
}
|
||||
@ -50,7 +52,7 @@ public class LoreSaveStream extends ByteArrayOutputStream {
|
||||
}
|
||||
int prev = 0;
|
||||
for (Iterator<String> iterator = lore.iterator(); iterator.hasNext(); ) {
|
||||
if (iterator.next().startsWith("§%")) {
|
||||
if (iterator.next().startsWith(IDENTIFIER)) {
|
||||
iterator.remove();
|
||||
break;
|
||||
}
|
||||
|
28
src/com/dre/brewery/lore/NBTLoadStream.java
Normal file
28
src/com/dre/brewery/lore/NBTLoadStream.java
Normal file
@ -0,0 +1,28 @@
|
||||
package com.dre.brewery.lore;
|
||||
|
||||
import com.dre.brewery.P;
|
||||
import com.dre.brewery.utility.LegacyUtil;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
|
||||
public class NBTLoadStream extends ByteArrayInputStream {
|
||||
private static final String TAG = "brewdata";
|
||||
|
||||
public NBTLoadStream(ItemMeta meta) {
|
||||
super(getNBTBytes(meta));
|
||||
}
|
||||
|
||||
private static byte[] getNBTBytes(ItemMeta meta) {
|
||||
byte[] bytes = LegacyUtil.readBytesItem(meta, new NamespacedKey(P.p, TAG));
|
||||
if (bytes == null) {
|
||||
return new byte[0];
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public boolean hasData() {
|
||||
return count > 0;
|
||||
}
|
||||
}
|
26
src/com/dre/brewery/lore/NBTSaveStream.java
Normal file
26
src/com/dre/brewery/lore/NBTSaveStream.java
Normal file
@ -0,0 +1,26 @@
|
||||
package com.dre.brewery.lore;
|
||||
|
||||
import com.dre.brewery.P;
|
||||
import com.dre.brewery.utility.LegacyUtil;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class NBTSaveStream extends ByteArrayOutputStream {
|
||||
private static final String TAG = "brewdata";
|
||||
private final ItemMeta meta;
|
||||
|
||||
public NBTSaveStream(ItemMeta meta) {
|
||||
super(128);
|
||||
this.meta = meta;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() throws IOException {
|
||||
super.flush();
|
||||
if (size() <= 0) return;
|
||||
LegacyUtil.writeBytesItem(toByteArray(), meta, new NamespacedKey(P.p, TAG));
|
||||
}
|
||||
}
|
@ -23,6 +23,8 @@ public class XORUnscrambleStream extends FilterInputStream {
|
||||
private boolean markRunning;
|
||||
private boolean markxor;
|
||||
|
||||
private SuccessType successType = SuccessType.NONE;
|
||||
|
||||
/**
|
||||
* Create a new instance of an XORUnscrambler, unscrambling the given inputstream
|
||||
*
|
||||
@ -62,19 +64,24 @@ public class XORUnscrambleStream extends FilterInputStream {
|
||||
short id = (short) (in.read() << 8 | in.read());
|
||||
if (id == 0) {
|
||||
running = false;
|
||||
successType = SuccessType.UNSCRAMBLED;
|
||||
P.p.debugLog("Unscrambled data");
|
||||
return;
|
||||
}
|
||||
int parity = in.read();
|
||||
xorStream = new SeedInputStream(seed ^ id);
|
||||
boolean success = checkParity(parity);
|
||||
if (success) P.p.debugLog("Using main Seed to unscramble");
|
||||
if (success) {
|
||||
successType = SuccessType.MAIN_SEED;
|
||||
P.p.debugLog("Using main Seed to unscramble");
|
||||
}
|
||||
|
||||
if (!success && prevSeeds != null) {
|
||||
for (int i = prevSeeds.size() - 1; i >= 0; i--) {
|
||||
seed = prevSeeds.get(i);
|
||||
xorStream = new SeedInputStream(seed ^ id);
|
||||
if (success = checkParity(parity)) {
|
||||
successType = SuccessType.PREV_SEED;
|
||||
P.p.debugLog("Had to use prevSeed to unscramble");
|
||||
break;
|
||||
}
|
||||
@ -118,6 +125,15 @@ public class XORUnscrambleStream extends FilterInputStream {
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* What was used to unscramble the stream, it was already unscrambled, Main Seed, Prev Seed
|
||||
*
|
||||
* @return The Type of Seed used to unscramble this, if any
|
||||
*/
|
||||
public SuccessType getSuccessType() {
|
||||
return successType;
|
||||
}
|
||||
|
||||
@SuppressWarnings("ResultOfMethodCallIgnored")
|
||||
@Override
|
||||
public long skip(long n) throws IOException {
|
||||
@ -163,4 +179,11 @@ public class XORUnscrambleStream extends FilterInputStream {
|
||||
}
|
||||
markRunning = running;
|
||||
}
|
||||
|
||||
public static enum SuccessType {
|
||||
UNSCRAMBLED,
|
||||
MAIN_SEED,
|
||||
PREV_SEED,
|
||||
NONE;
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,11 @@
|
||||
package com.dre.brewery.utility;
|
||||
|
||||
import com.dre.brewery.P;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.TreeSpecies;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.block.data.Levelled;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.material.Cauldron;
|
||||
import org.bukkit.material.MaterialData;
|
||||
import org.bukkit.material.Tree;
|
||||
@ -30,6 +27,8 @@ public class LegacyUtil {
|
||||
private static Method GET_BLOCK_TYPE_ID_AT;
|
||||
private static Method SET_DATA;
|
||||
|
||||
public static boolean NewNbtVer;
|
||||
|
||||
static {
|
||||
// <= 1.12.2 methods
|
||||
// These will be rarely used
|
||||
@ -248,4 +247,48 @@ public class LegacyUtil {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* MC 1.13 uses a different NBT API than the newer versions..
|
||||
* We decide here which to use, the new or the old
|
||||
*
|
||||
* @return true if we can use nbt at all
|
||||
*/
|
||||
public static boolean initNbt() {
|
||||
try {
|
||||
Class.forName("org.bukkit.persistence.PersistentDataContainer");
|
||||
NewNbtVer = true;
|
||||
P.p.debugLog("Using the NEW nbt api");
|
||||
return true;
|
||||
} catch (ClassNotFoundException e) {
|
||||
try {
|
||||
Class.forName("org.bukkit.inventory.meta.tags.CustomItemTagContainer");
|
||||
NewNbtVer = false;
|
||||
P.p.debugLog("Using the OLD nbt api");
|
||||
return true;
|
||||
} catch (ClassNotFoundException ex) {
|
||||
NewNbtVer = false;
|
||||
P.p.debugLog("No nbt api found, using Lore Save System");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static void writeBytesItem(byte[] bytes, ItemMeta meta, NamespacedKey key) {
|
||||
if (NewNbtVer) {
|
||||
meta.getPersistentDataContainer().set(key, org.bukkit.persistence.PersistentDataType.BYTE_ARRAY, bytes);
|
||||
} else {
|
||||
meta.getCustomTagContainer().setCustomTag(key, org.bukkit.inventory.meta.tags.ItemTagType.BYTE_ARRAY, bytes);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static byte[] readBytesItem(ItemMeta meta, NamespacedKey key) {
|
||||
if (NewNbtVer) {
|
||||
return meta.getPersistentDataContainer().get(key, org.bukkit.persistence.PersistentDataType.BYTE_ARRAY);
|
||||
} else {
|
||||
return meta.getCustomTagContainer().getCustomTag(key, org.bukkit.inventory.meta.tags.ItemTagType.BYTE_ARRAY);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user