Fix PlayerBounties-OG head compatibility
This commit is contained in:
1 parent
d150f0ddc2
commit
9f5a4065d9
5 files changed
+442
-11
No files matched your search
@@ -186,3 +186,4 @@ docs/dev/
|
||||
# Extensions
|
||||
/src/main/java/net/coreprotect/extensions/*.java
|
||||
!/src/main/java/net/coreprotect/extensions/Extensions.java
|
||||
!/src/main/java/net/coreprotect/extensions/PlayerBountiesHeadCompatibility.java
|
||||
@@ -2,6 +2,7 @@ package net.coreprotect.consumer.process;
|
||||
|
||||
import java.sql.Statement;
|
||||
import net.coreprotect.config.ConfigHandler;
|
||||
import net.coreprotect.database.Database;
|
||||
import net.coreprotect.database.statement.SkullStatement;
|
||||
import net.coreprotect.utility.Util;
|
||||
import org.bukkit.block.BlockState;
|
||||
@@ -17,9 +18,22 @@ class SkullUpdateProcess {
|
||||
if (object instanceof BlockState) {
|
||||
|
||||
BlockState block = (BlockState) object;
|
||||
String query = "SELECT owner, skin, metadata FROM " + ConfigHandler.prefix + "skull WHERE rowid='" + rowId
|
||||
+ "' LIMIT 0, 1";
|
||||
SkullStatement.getData(statement, block, query);
|
||||
StringBuilder query = new StringBuilder("SELECT owner");
|
||||
if (Database.hasSkullSkinColumn()) {
|
||||
|
||||
query.append(", skin");
|
||||
|
||||
}
|
||||
|
||||
if (Database.hasSkullMetadataColumn()) {
|
||||
|
||||
query.append(", metadata");
|
||||
|
||||
}
|
||||
|
||||
query.append(" FROM ").append(ConfigHandler.prefix).append("skull WHERE rowid='").append(rowId)
|
||||
.append("' LIMIT 0, 1");
|
||||
SkullStatement.getData(statement, block, query.toString());
|
||||
Util.updateBlock(block);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package net.coreprotect.database;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
@@ -40,6 +41,8 @@ public class Database extends Queue {
|
||||
public static final int ENTITY_MAP = 11;
|
||||
public static final int BLOCKDATA = 12;
|
||||
public static final int ITEM = 13;
|
||||
private static volatile Boolean skullHasSkinColumn = null;
|
||||
private static volatile Boolean skullHasMetadataColumn = null;
|
||||
|
||||
public static void beginTransaction(Statement statement, boolean isMySQL) {
|
||||
|
||||
@@ -142,6 +145,48 @@ public class Database extends Queue {
|
||||
|
||||
}
|
||||
|
||||
public static boolean hasSkullSkinColumn() {
|
||||
|
||||
return Boolean.TRUE.equals(skullHasSkinColumn);
|
||||
|
||||
}
|
||||
|
||||
public static boolean hasSkullMetadataColumn() {
|
||||
|
||||
return Boolean.TRUE.equals(skullHasMetadataColumn);
|
||||
|
||||
}
|
||||
|
||||
public static void initializeSkullColumnCache(Connection connection) {
|
||||
|
||||
if (connection == null) {
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
if (skullHasSkinColumn == null) {
|
||||
|
||||
skullHasSkinColumn = hasColumn(connection, ConfigHandler.prefix + "skull", "skin");
|
||||
|
||||
}
|
||||
|
||||
if (skullHasMetadataColumn == null) {
|
||||
|
||||
skullHasMetadataColumn = hasColumn(connection, ConfigHandler.prefix + "skull", "metadata");
|
||||
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
|
||||
e.printStackTrace();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void containerBreakCheck(String user, Material type, Object container, ItemStack[] contents,
|
||||
Location location)
|
||||
{
|
||||
@@ -319,8 +364,25 @@ public class Database extends Queue {
|
||||
+ "sign (time, user, wid, x, y, z, action, color, color_secondary, data, waxed, face, line_1, line_2, line_3, line_4, line_5, line_6, line_7, line_8) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||
String blockInsert = "INSERT INTO " + ConfigHandler.prefix
|
||||
+ "block (time, user, wid, x, y, z, type, data, meta, blockdata, action, rolled_back) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||
String skullInsert = "INSERT INTO " + ConfigHandler.prefix
|
||||
+ "skull (time, owner, skin, metadata) VALUES (?, ?, ?, ?)";
|
||||
initializeSkullColumnCache(connection);
|
||||
String skullColumns = "time, owner";
|
||||
String skullValues = "?, ?";
|
||||
if (hasSkullSkinColumn()) {
|
||||
|
||||
skullColumns = skullColumns + ", skin";
|
||||
skullValues = skullValues + ", ?";
|
||||
|
||||
}
|
||||
|
||||
if (hasSkullMetadataColumn()) {
|
||||
|
||||
skullColumns = skullColumns + ", metadata";
|
||||
skullValues = skullValues + ", ?";
|
||||
|
||||
}
|
||||
|
||||
String skullInsert = "INSERT INTO " + ConfigHandler.prefix + "skull (" + skullColumns + ") VALUES ("
|
||||
+ skullValues + ")";
|
||||
String containerInsert = "INSERT INTO " + ConfigHandler.prefix
|
||||
+ "container (time, user, wid, x, y, z, type, data, amount, metadata, action, rolled_back) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||
String itemInsert = "INSERT INTO " + ConfigHandler.prefix
|
||||
@@ -476,6 +538,9 @@ public class Database extends Queue {
|
||||
|
||||
public static void createDatabaseTables(String prefix, Connection forceConnection, boolean mySQL, boolean purge) {
|
||||
|
||||
skullHasSkinColumn = null;
|
||||
skullHasMetadataColumn = null;
|
||||
|
||||
ConfigHandler.databaseTables.clear();
|
||||
ConfigHandler.databaseTables.addAll(Arrays.asList("art_map", "block", "chat", "command", "container", "item",
|
||||
"database_lock", "entity", "entity_map", "material_map", "blockdata_map", "session", "sign", "skull",
|
||||
@@ -542,6 +607,7 @@ public class Database extends Queue {
|
||||
+ index + ") ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
|
||||
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix
|
||||
+ "skull(rowid int NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid), time int, owner varchar(255), skin varchar(255), metadata MEDIUMTEXT) ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4");
|
||||
ensureSkullColumns(connection, statement, prefix);
|
||||
index = ", INDEX(user), INDEX(uuid)";
|
||||
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix
|
||||
+ "user(rowid int NOT NULL AUTO_INCREMENT,PRIMARY KEY(rowid),time int,user varchar(100),uuid varchar(64)"
|
||||
@@ -719,6 +785,8 @@ public class Database extends Queue {
|
||||
|
||||
}
|
||||
|
||||
ensureSkullColumns(connection, statement, prefix);
|
||||
|
||||
if (!tableData.contains(prefix + "user")) {
|
||||
|
||||
statement.executeUpdate("CREATE TABLE IF NOT EXISTS " + prefix
|
||||
@@ -987,4 +1055,62 @@ public class Database extends Queue {
|
||||
|
||||
}
|
||||
|
||||
private static boolean hasColumn(Connection connection, String tableName, String columnName) throws SQLException {
|
||||
|
||||
DatabaseMetaData metaData = connection.getMetaData();
|
||||
try (ResultSet resultSet = metaData.getColumns(connection.getCatalog(), null, tableName, columnName)) {
|
||||
|
||||
if (resultSet.next()) {
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
try (ResultSet resultSet = metaData.getColumns(connection.getCatalog(), null,
|
||||
tableName.toUpperCase(Locale.ROOT), columnName.toUpperCase(Locale.ROOT)))
|
||||
{
|
||||
|
||||
return resultSet.next();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void ensureSkullColumns(Connection connection, Statement statement, String prefix) {
|
||||
|
||||
try {
|
||||
|
||||
String tableName = prefix + "skull";
|
||||
boolean hasMetadata = hasColumn(connection, tableName, "metadata");
|
||||
boolean hasSkin = hasColumn(connection, tableName, "skin");
|
||||
|
||||
if (!hasMetadata) {
|
||||
|
||||
statement.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN metadata "
|
||||
+ (Config.getGlobal().MYSQL ? "MEDIUMTEXT" : "TEXT") + ";");
|
||||
hasMetadata = true;
|
||||
|
||||
}
|
||||
|
||||
if (!hasSkin) {
|
||||
|
||||
statement.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN skin "
|
||||
+ (Config.getGlobal().MYSQL ? "VARCHAR(255)" : "TEXT") + ";");
|
||||
hasSkin = true;
|
||||
|
||||
}
|
||||
|
||||
skullHasMetadataColumn = hasMetadata;
|
||||
skullHasSkinColumn = hasSkin;
|
||||
|
||||
} catch (Exception e) {
|
||||
|
||||
initializeSkullColumnCache(connection);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -25,8 +25,19 @@ public class SkullStatement {
|
||||
|
||||
preparedStmt.setInt(1, time);
|
||||
preparedStmt.setString(2, owner);
|
||||
preparedStmt.setString(3, skin);
|
||||
preparedStmt.setString(4, metadata);
|
||||
int parameterIndex = 3;
|
||||
if (Database.hasSkullSkinColumn()) {
|
||||
|
||||
preparedStmt.setString(parameterIndex++, skin);
|
||||
|
||||
}
|
||||
|
||||
if (Database.hasSkullMetadataColumn()) {
|
||||
|
||||
preparedStmt.setString(parameterIndex, metadata);
|
||||
|
||||
}
|
||||
|
||||
if (Database.hasReturningKeys()) {
|
||||
|
||||
return preparedStmt.executeQuery();
|
||||
@@ -69,14 +80,22 @@ public class SkullStatement {
|
||||
|
||||
}
|
||||
|
||||
String skin = resultSet.getString("skin");
|
||||
if (owner != null && skin != null && skin.length() > 0) {
|
||||
if (Database.hasSkullSkinColumn()) {
|
||||
|
||||
PaperAdapter.ADAPTER.setSkullSkin(skull, skin);
|
||||
String skin = resultSet.getString("skin");
|
||||
if (owner != null && skin != null && skin.length() > 0) {
|
||||
|
||||
PaperAdapter.ADAPTER.setSkullSkin(skull, skin);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
PlayerBountiesHeadCompatibility.applySkullMetadata(skull, resultSet.getString("metadata"));
|
||||
if (Database.hasSkullMetadataColumn()) {
|
||||
|
||||
PlayerBountiesHeadCompatibility.applySkullMetadata(skull, resultSet.getString("metadata"));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,271 @@
|
||||
package net.coreprotect.extensions;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.block.Skull;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.persistence.PersistentDataContainer;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
|
||||
public final class PlayerBountiesHeadCompatibility {
|
||||
|
||||
private static final String TARGET_KEY = "bounty_head_target";
|
||||
private static final String UUID_KEY = "bounty_head_target_uuid";
|
||||
private static final String AMOUNT_KEY = "bounty_head_diamonds";
|
||||
private static final String ITEM_MARKER = "playerbounties_head";
|
||||
private static final String SKULL_MARKER = "pbh1";
|
||||
|
||||
private PlayerBountiesHeadCompatibility() {
|
||||
|
||||
throw new IllegalStateException("Utility class");
|
||||
|
||||
}
|
||||
|
||||
public static String serializeSkullMetadata(Skull skull) {
|
||||
|
||||
if (skull == null) {
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
SkullData skullData = readSkullData(skull.getPersistentDataContainer());
|
||||
if (skullData == null) {
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
return String.join("|", SKULL_MARKER, encode(skullData.namespace), encode(skullData.targetName),
|
||||
encode(skullData.targetUuid), Double.toString(skullData.bountyAmount));
|
||||
|
||||
}
|
||||
|
||||
public static void applySkullMetadata(Skull skull, String metadata) {
|
||||
|
||||
if (skull == null || metadata == null || metadata.isBlank()) {
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
SkullData skullData = parseMetadata(metadata);
|
||||
if (skullData == null) {
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
applyPersistentData(skull.getPersistentDataContainer(), skullData);
|
||||
|
||||
}
|
||||
|
||||
public static void appendItemMetadata(ItemStack item, ItemMeta itemMeta, List<List<Map<String, Object>>> metadata) {
|
||||
|
||||
if (item == null || itemMeta == null || metadata == null || item.getType() != Material.PLAYER_HEAD) {
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
SkullData skullData = readSkullData(itemMeta.getPersistentDataContainer());
|
||||
if (skullData == null) {
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("plugin", ITEM_MARKER);
|
||||
data.put("namespace", skullData.namespace);
|
||||
data.put("target", skullData.targetName);
|
||||
data.put("uuid", skullData.targetUuid);
|
||||
data.put("amount", skullData.bountyAmount);
|
||||
|
||||
List<Map<String, Object>> list = new ArrayList<>();
|
||||
list.add(data);
|
||||
metadata.add(list);
|
||||
|
||||
}
|
||||
|
||||
public static boolean applyItemMetadata(ItemStack itemstack, Map<String, Object> mapData) {
|
||||
|
||||
if (itemstack == null || mapData == null || itemstack.getType() != Material.PLAYER_HEAD) {
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
Object marker = mapData.get("plugin");
|
||||
if (!ITEM_MARKER.equals(marker)) {
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
String namespace = asString(mapData.get("namespace"));
|
||||
String target = asString(mapData.get("target"));
|
||||
String uuid = asString(mapData.get("uuid"));
|
||||
Double amount = asDouble(mapData.get("amount"));
|
||||
if (namespace == null || target == null || uuid == null || amount == null) {
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
ItemMeta itemMeta = itemstack.getItemMeta();
|
||||
if (itemMeta == null) {
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
applyPersistentData(itemMeta.getPersistentDataContainer(), new SkullData(namespace, target, uuid, amount));
|
||||
itemstack.setItemMeta(itemMeta);
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
private static SkullData readSkullData(PersistentDataContainer container) {
|
||||
|
||||
if (container == null) {
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
NamespacedKey targetKey = null;
|
||||
NamespacedKey uuidKey = null;
|
||||
NamespacedKey amountKey = null;
|
||||
|
||||
for (NamespacedKey key : container.getKeys()) {
|
||||
|
||||
if (TARGET_KEY.equals(key.getKey())) {
|
||||
|
||||
targetKey = key;
|
||||
|
||||
} else if (UUID_KEY.equals(key.getKey())) {
|
||||
|
||||
uuidKey = key;
|
||||
|
||||
} else if (AMOUNT_KEY.equals(key.getKey())) {
|
||||
|
||||
amountKey = key;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (targetKey == null || uuidKey == null || amountKey == null) {
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
String target = container.get(targetKey, PersistentDataType.STRING);
|
||||
String uuid = container.get(uuidKey, PersistentDataType.STRING);
|
||||
Double amount = container.get(amountKey, PersistentDataType.DOUBLE);
|
||||
if (target == null || uuid == null || amount == null) {
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
return new SkullData(targetKey.getNamespace(), target, uuid, amount);
|
||||
|
||||
}
|
||||
|
||||
private static void applyPersistentData(PersistentDataContainer container, SkullData skullData) {
|
||||
|
||||
NamespacedKey targetKey = new NamespacedKey(skullData.namespace, TARGET_KEY);
|
||||
NamespacedKey uuidKey = new NamespacedKey(skullData.namespace, UUID_KEY);
|
||||
NamespacedKey amountKey = new NamespacedKey(skullData.namespace, AMOUNT_KEY);
|
||||
|
||||
container.set(targetKey, PersistentDataType.STRING, skullData.targetName);
|
||||
container.set(uuidKey, PersistentDataType.STRING, skullData.targetUuid);
|
||||
container.set(amountKey, PersistentDataType.DOUBLE, skullData.bountyAmount);
|
||||
|
||||
}
|
||||
|
||||
private static SkullData parseMetadata(String metadata) {
|
||||
|
||||
String[] parts = metadata.split("\\|", -1);
|
||||
if (parts.length != 5 || !SKULL_MARKER.equals(parts[0])) {
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
return new SkullData(decode(parts[1]), decode(parts[2]), decode(parts[3]), Double.parseDouble(parts[4]));
|
||||
|
||||
} catch (Exception e) {
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static String encode(String value) {
|
||||
|
||||
return Base64.getEncoder().encodeToString(value.getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
}
|
||||
|
||||
private static String decode(String value) {
|
||||
|
||||
return new String(Base64.getDecoder().decode(value), StandardCharsets.UTF_8);
|
||||
|
||||
}
|
||||
|
||||
private static String asString(Object value) {
|
||||
|
||||
if (value == null) {
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
return String.valueOf(value);
|
||||
|
||||
}
|
||||
|
||||
private static Double asDouble(Object value) {
|
||||
|
||||
if (value instanceof Number) {
|
||||
|
||||
return ((Number) value).doubleValue();
|
||||
|
||||
}
|
||||
|
||||
if (value == null) {
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
return Double.parseDouble(String.valueOf(value));
|
||||
|
||||
} catch (NumberFormatException e) {
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private record SkullData(String namespace, String targetName, String targetUuid, double bountyAmount) {
|
||||
}
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user