diff --git a/src/main/java/net/coreprotect/CoreProtectAPI.java b/src/main/java/net/coreprotect/CoreProtectAPI.java index 757427b3..d149217a 100755 --- a/src/main/java/net/coreprotect/CoreProtectAPI.java +++ b/src/main/java/net/coreprotect/CoreProtectAPI.java @@ -68,7 +68,7 @@ public class CoreProtectAPI extends Queue { if (list != null) { for (Object value : list) { - if (value instanceof Material || value instanceof EntityType) { + if (value instanceof Material || value instanceof EntityType || value instanceof String) { result.put(value, false); } else if (value instanceof Integer) { @@ -341,6 +341,27 @@ public class CoreProtectAPI extends Queue { return true; } + /** + * Logs a block placement by a user with specific block data. + * + * @param user + * The username + * @param location + * The location + * @param blockData + * The block data + * @return True if the placement was logged + */ + public boolean logPlacement(String user, Location location, BlockData blockData) { + if (!isEnabled() || !isValidUserAndLocation(user, location) || blockData == null) { + return false; + } + + Block block = location.getBlock(); + Queue.queueBlockPlace(user, block.getState(), block.getType(), null, block.getType(), -1, 0, blockData.getAsString()); + return true; + } + /** * Logs a block placement by a user with a specific material and data value. * @@ -412,6 +433,28 @@ public class CoreProtectAPI extends Queue { return true; } + /** + * Logs a block removal by a user with specific block data. + * + * @param user + * The username + * @param location + * The location + * @param blockData + * The block data + * @return True if the removal was logged + */ + public boolean logRemoval(String user, Location location, BlockData blockData) { + if (!isEnabled() || !isValidUserAndLocation(user, location) || blockData == null) { + return false; + } + + Block block = location.getBlock(); + Database.containerBreakCheck(user, block.getType(), block, null, location); + Queue.queueBlockBreak(user, block.getState(), block.getType(), blockData.getAsString(), 0); + return true; + } + /** * Logs a block removal by a user with a specific material and data value. * diff --git a/src/main/java/net/coreprotect/api/result/ParseResult.java b/src/main/java/net/coreprotect/api/result/ParseResult.java index 4324715c..4ed86e46 100644 --- a/src/main/java/net/coreprotect/api/result/ParseResult.java +++ b/src/main/java/net/coreprotect/api/result/ParseResult.java @@ -7,6 +7,8 @@ import org.bukkit.Material; import org.bukkit.block.data.BlockData; import net.coreprotect.api.SessionLookup; +import net.coreprotect.utility.BlockUtils; +import net.coreprotect.utility.BlockTypeUtils; import net.coreprotect.utility.EntityUtils; import net.coreprotect.utility.MaterialUtils; import net.coreprotect.utility.StringUtils; @@ -84,7 +86,12 @@ public class ParseResult { typeName = EntityUtils.getEntityType(type).name(); } else { - typeName = MaterialUtils.getType(type).name().toLowerCase(Locale.ROOT); + Material material = MaterialUtils.getType(type); + if (material == null) { + return null; + } + + typeName = material.name().toLowerCase(Locale.ROOT); typeName = StringUtils.nameFilter(typeName, this.getData()); } @@ -98,9 +105,16 @@ public class ParseResult { String blockData = parse[12]; if (blockData == null || blockData.length() == 0) { - return getType().createBlockData(); + Material type = getType(); + if (type != null) { + return type.createBlockData(); + } + + return BlockUtils.createBlockData(Integer.parseInt(parse[5])); } - return Bukkit.getServer().createBlockData(blockData); + + BlockData result = BlockTypeUtils.createBlockDataFromString(blockData); + return result != null ? result : Bukkit.getServer().createBlockData(blockData); } public int getX() { diff --git a/src/main/java/net/coreprotect/bukkit/BukkitAdapter.java b/src/main/java/net/coreprotect/bukkit/BukkitAdapter.java index 5f720b8c..e171016c 100644 --- a/src/main/java/net/coreprotect/bukkit/BukkitAdapter.java +++ b/src/main/java/net/coreprotect/bukkit/BukkitAdapter.java @@ -223,6 +223,21 @@ public class BukkitAdapter implements BukkitInterface { return Material.AIR; } + @Override + public boolean hasBlockType(String key) { + return false; + } + + @Override + public BlockData createBlockData(String key) { + return null; + } + + @Override + public BlockData createBlockDataFromString(String blockData) { + return null; + } + @Override public boolean isInvisible(Material material) { return BlockUtils.isAir(material); diff --git a/src/main/java/net/coreprotect/bukkit/BukkitInterface.java b/src/main/java/net/coreprotect/bukkit/BukkitInterface.java index b45edf21..8ef18ab5 100644 --- a/src/main/java/net/coreprotect/bukkit/BukkitInterface.java +++ b/src/main/java/net/coreprotect/bukkit/BukkitInterface.java @@ -76,6 +76,33 @@ public interface BukkitInterface { */ Material getBucketContents(Material material); + /** + * Checks whether the runtime supports and contains a block type key. + * + * @param key + * The namespaced block key + * @return true if the block type exists, false otherwise + */ + boolean hasBlockType(String key); + + /** + * Creates default block data for a block type key. + * + * @param key + * The namespaced block key + * @return The block data, or null if unsupported/unavailable + */ + BlockData createBlockData(String key); + + /** + * Creates block data from a serialized block data string. + * + * @param blockData + * The serialized block data + * @return The block data, or null if unsupported/unavailable + */ + BlockData createBlockDataFromString(String blockData); + // -------------------------------------------------------------------------- // Material type checking methods // -------------------------------------------------------------------------- diff --git a/src/main/java/net/coreprotect/bukkit/Bukkit_v1_21.java b/src/main/java/net/coreprotect/bukkit/Bukkit_v1_21.java index 825feca0..8597b7c9 100644 --- a/src/main/java/net/coreprotect/bukkit/Bukkit_v1_21.java +++ b/src/main/java/net/coreprotect/bukkit/Bukkit_v1_21.java @@ -10,7 +10,10 @@ import org.bukkit.ExplosionResult; import org.bukkit.Keyed; import org.bukkit.Material; import org.bukkit.NamespacedKey; +import org.bukkit.Registry; import org.bukkit.Tag; +import org.bukkit.block.BlockType; +import org.bukkit.block.data.BlockData; import org.bukkit.entity.EntityType; import org.bukkit.event.Event; import org.bukkit.event.block.BlockExplodeEvent; @@ -19,6 +22,7 @@ import org.bukkit.event.inventory.InventoryType; import net.coreprotect.model.BlockGroup; +import net.coreprotect.utility.BlockTypeUtils; /** * Bukkit adapter implementation for Minecraft 1.21. @@ -103,6 +107,43 @@ public class Bukkit_v1_21 extends Bukkit_v1_20 { } } + @Override + public boolean hasBlockType(String key) { + return getBlockType(key) != null; + } + + @Override + public BlockData createBlockData(String key) { + try { + BlockType blockType = getBlockType(key); + return blockType == null ? null : blockType.createBlockData(); + } + catch (Exception e) { + return null; + } + } + + @Override + public BlockData createBlockDataFromString(String blockData) { + try { + BlockType blockType = getBlockType(BlockTypeUtils.getBlockDataKey(blockData)); + if (blockType == null) { + return null; + } + + String states = BlockTypeUtils.getBlockDataStates(blockData); + return states == null ? blockType.createBlockData() : blockType.createBlockData(states); + } + catch (Exception e) { + return null; + } + } + + private BlockType getBlockType(String key) { + NamespacedKey namespacedKey = NamespacedKey.fromString(BlockTypeUtils.normalizeKey(key)); + return namespacedKey == null ? null : Registry.BLOCK.get(namespacedKey); + } + /** * Gets the EntityType corresponding to a Material. * Maps Material to its equivalent EntityType for entity handling. diff --git a/src/main/java/net/coreprotect/command/LookupCommand.java b/src/main/java/net/coreprotect/command/LookupCommand.java index 9d454bb8..74e5dc13 100755 --- a/src/main/java/net/coreprotect/command/LookupCommand.java +++ b/src/main/java/net/coreprotect/command/LookupCommand.java @@ -67,7 +67,7 @@ public class LookupCommand { boolean hasBlock = false; boolean hasEntity = false; for (Object arg : argBlocks) { - if (arg instanceof Material) { + if (arg instanceof Material || arg instanceof String) { hasBlock = true; } else if (arg instanceof EntityType) { @@ -84,7 +84,7 @@ public class LookupCommand { /* check for invalid block/entity combinations (exclude) */ for (Object arg : argExclude.keySet()) { - if (arg instanceof Material) { + if (arg instanceof Material || arg instanceof String) { hasBlock = true; } else if (arg instanceof EntityType) { diff --git a/src/main/java/net/coreprotect/command/PurgeCommand.java b/src/main/java/net/coreprotect/command/PurgeCommand.java index 7e5ab6dc..5d0efed7 100755 --- a/src/main/java/net/coreprotect/command/PurgeCommand.java +++ b/src/main/java/net/coreprotect/command/PurgeCommand.java @@ -192,6 +192,18 @@ public class PurgeCommand extends Consumer { targetName = ((EntityType) restrictTarget).name().toLowerCase(Locale.ROOT); entity = true; } + else if (restrictTarget instanceof String) { + int blockId = MaterialUtils.getBlockId((String) restrictTarget, false); + if (includeListMaterial.length() == 0) { + includeListMaterial = includeListMaterial.append(blockId); + } + else { + includeListMaterial.append(",").append(blockId); + } + + targetName = ((String) restrictTarget).toLowerCase(Locale.ROOT); + hasBlock = true; + } if (restrictCount == 0) { restrict = restrict.append("" + targetName + ""); diff --git a/src/main/java/net/coreprotect/command/RollbackRestoreCommand.java b/src/main/java/net/coreprotect/command/RollbackRestoreCommand.java index b34f134b..a29558f6 100755 --- a/src/main/java/net/coreprotect/command/RollbackRestoreCommand.java +++ b/src/main/java/net/coreprotect/command/RollbackRestoreCommand.java @@ -61,7 +61,7 @@ public class RollbackRestoreCommand { boolean hasBlock = false; boolean hasEntity = false; for (Object arg : argBlocks) { - if (arg instanceof Material) { + if (arg instanceof Material || arg instanceof String) { hasBlock = true; } else if (arg instanceof EntityType) { @@ -78,7 +78,7 @@ public class RollbackRestoreCommand { /* check for invalid block/entity combinations (exclude) */ for (Object arg : argExclude.keySet()) { - if (arg instanceof Material) { + if (arg instanceof Material || arg instanceof String) { hasBlock = true; } else if (arg instanceof EntityType) { diff --git a/src/main/java/net/coreprotect/command/lookup/StandardLookupThread.java b/src/main/java/net/coreprotect/command/lookup/StandardLookupThread.java index f6540ff0..d5338fdc 100644 --- a/src/main/java/net/coreprotect/command/lookup/StandardLookupThread.java +++ b/src/main/java/net/coreprotect/command/lookup/StandardLookupThread.java @@ -366,10 +366,9 @@ public class StandardLookupThread implements Runnable { } } else { - dname = MaterialUtils.getType(dtype).name().toLowerCase(Locale.ROOT); - dname = StringUtils.nameFilter(dname, ddata); + dname = MaterialUtils.getBlockDisplayName(dtype, ddata); } - if (dname.length() > 0 && !isPlayer) { + if (dname.length() > 0 && !isPlayer && !dname.contains(":")) { dname = "minecraft:" + dname.toLowerCase(Locale.ROOT) + ""; } diff --git a/src/main/java/net/coreprotect/command/parser/MaterialParser.java b/src/main/java/net/coreprotect/command/parser/MaterialParser.java index ef802180..76e17310 100644 --- a/src/main/java/net/coreprotect/command/parser/MaterialParser.java +++ b/src/main/java/net/coreprotect/command/parser/MaterialParser.java @@ -14,6 +14,7 @@ import org.bukkit.entity.EntityType; import net.coreprotect.language.Phrase; import net.coreprotect.model.BlockGroup; +import net.coreprotect.utility.BlockTypeUtils; import net.coreprotect.utility.Chat; import net.coreprotect.utility.Color; import net.coreprotect.utility.EntityUtils; @@ -65,6 +66,9 @@ public class MaterialParser { if (i3_material != null && (i3_material.isBlock() || argAction.contains(4))) { restricted.add(i3_material); } + else if (!argAction.contains(4) && BlockTypeUtils.hasBlockType(i3)) { + restricted.add(BlockTypeUtils.normalizeKey(i3)); + } else { EntityType i3_entity = EntityUtils.getEntityType(i3); if (i3_entity != null) { @@ -94,6 +98,9 @@ public class MaterialParser { if (material != null && (material.isBlock() || argAction.contains(4))) { restricted.add(material); } + else if (!argAction.contains(4) && BlockTypeUtils.hasBlockType(argument)) { + restricted.add(BlockTypeUtils.normalizeKey(argument)); + } else { EntityType entityType = EntityUtils.getEntityType(argument); if (entityType != null) { @@ -157,6 +164,9 @@ public class MaterialParser { if (i3_material != null && (i3_material.isBlock() || argAction.contains(4))) { excluded.put(i3_material, false); } + else if (!argAction.contains(4) && BlockTypeUtils.hasBlockType(i3)) { + excluded.put(BlockTypeUtils.normalizeKey(i3), false); + } else { EntityType i3_entity = EntityUtils.getEntityType(i3); if (i3_entity != null) { @@ -181,6 +191,9 @@ public class MaterialParser { if (iMaterial != null && (iMaterial.isBlock() || argAction.contains(4))) { excluded.put(iMaterial, false); } + else if (!argAction.contains(4) && BlockTypeUtils.hasBlockType(argument)) { + excluded.put(BlockTypeUtils.normalizeKey(argument), false); + } else { EntityType iEntity = EntityUtils.getEntityType(argument); if (iEntity != null) { @@ -299,6 +312,9 @@ public class MaterialParser { if (material != null) { isBlock = true; } + else if (BlockTypeUtils.hasBlockType(argument)) { + isBlock = true; + } else { EntityType entityType = EntityUtils.getEntityType(argument); if (entityType != null) { diff --git a/src/main/java/net/coreprotect/consumer/Queue.java b/src/main/java/net/coreprotect/consumer/Queue.java index eb0cf300..76cfd56d 100755 --- a/src/main/java/net/coreprotect/consumer/Queue.java +++ b/src/main/java/net/coreprotect/consumer/Queue.java @@ -2,6 +2,7 @@ package net.coreprotect.consumer; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import org.bukkit.Bukkit; import org.bukkit.Location; @@ -93,7 +94,7 @@ public class Queue { protected static void queueBlockBreakValidate(final String user, final Block block, final BlockState blockState, final Material type, final String blockData, final int extraData, int ticks) { Scheduler.scheduleSyncDelayedTask(CoreProtect.getInstance(), () -> { try { - if (!block.getType().equals(type)) { + if (!Objects.equals(block.getType(), type)) { queueBlockBreak(user, blockState, type, blockData, null, extraData, 0); } } @@ -108,7 +109,7 @@ public class Queue { CreatureSpawner mobSpawner = (CreatureSpawner) block; extraData = EntityUtils.getSpawnerType(mobSpawner.getSpawnedType()); } - else if (type == Material.IRON_DOOR || BlockGroup.DOORS.contains(type) || type.equals(Material.SUNFLOWER) || type.equals(Material.LILAC) || type.equals(Material.TALL_GRASS) || type.equals(Material.LARGE_FERN) || type.equals(Material.ROSE_BUSH) || type.equals(Material.PEONY)) { // Double plant + else if (type != null && (type == Material.IRON_DOOR || BlockGroup.DOORS.contains(type) || type.equals(Material.SUNFLOWER) || type.equals(Material.LILAC) || type.equals(Material.TALL_GRASS) || type.equals(Material.LARGE_FERN) || type.equals(Material.ROSE_BUSH) || type.equals(Material.PEONY))) { // Double plant if (block.getBlockData() instanceof Bisected) { if (((Bisected) block.getBlockData()).getHalf().equals(Half.TOP)) { if (blockNumber == 5) { @@ -126,7 +127,7 @@ public class Queue { } } } - else if (type.name().endsWith("_BED") && block.getBlockData() instanceof Bed) { + else if (type != null && type.name().endsWith("_BED") && block.getBlockData() instanceof Bed) { if (((Bed) block.getBlockData()).getPart().equals(Part.HEAD)) { return; } @@ -155,7 +156,7 @@ public class Queue { replaceType = blockReplaced.getType(); replaceData = 0; - if ((replaceType == Material.IRON_DOOR || BlockGroup.DOORS.contains(replaceType) || replaceType.equals(Material.SUNFLOWER) || replaceType.equals(Material.LILAC) || replaceType.equals(Material.TALL_GRASS) || replaceType.equals(Material.LARGE_FERN) || replaceType.equals(Material.ROSE_BUSH) || replaceType.equals(Material.PEONY)) && replaceData >= 8) { // Double plant top half + if (replaceType != null && (replaceType == Material.IRON_DOOR || BlockGroup.DOORS.contains(replaceType) || replaceType.equals(Material.SUNFLOWER) || replaceType.equals(Material.LILAC) || replaceType.equals(Material.TALL_GRASS) || replaceType.equals(Material.LARGE_FERN) || replaceType.equals(Material.ROSE_BUSH) || replaceType.equals(Material.PEONY)) && replaceData >= 8) { // Double plant top half BlockState blockBelow = blockReplaced.getWorld().getBlockAt(blockReplaced.getX(), blockReplaced.getY() - 1, blockReplaced.getZ()).getState(); Material belowType = blockBelow.getType(); Queue.queueBlockBreak(user, blockBelow, belowType, blockBelow.getBlockData().getAsString(), 0); @@ -203,7 +204,7 @@ public class Queue { try { Material blockType = block.getType(); BlockState replacedBlock = blockReplaced; - boolean placed = blockType.equals(forceT); + boolean placed = Objects.equals(blockType, forceT); if (!placed && forceT == Material.WATER) { BlockData currentBlockData = block.getBlockData(); if (currentBlockData instanceof Waterlogged) { @@ -227,7 +228,7 @@ public class Queue { if (placed) { BlockState blockStateLocation = blockLocation; - if (blockType.equals(forceT) && Config.getConfig(blockLocation.getWorld()).BLOCK_MOVEMENT) { + if (blockType != null && Objects.equals(blockType, forceT) && Config.getConfig(blockLocation.getWorld()).BLOCK_MOVEMENT) { blockStateLocation = BlockUtil.gravityScan(blockLocation.getLocation(), blockType, user).getState(); } diff --git a/src/main/java/net/coreprotect/consumer/process/BlockPlaceProcess.java b/src/main/java/net/coreprotect/consumer/process/BlockPlaceProcess.java index 2610ff00..b1217cfc 100644 --- a/src/main/java/net/coreprotect/consumer/process/BlockPlaceProcess.java +++ b/src/main/java/net/coreprotect/consumer/process/BlockPlaceProcess.java @@ -17,7 +17,7 @@ class BlockPlaceProcess { if (object instanceof BlockState) { BlockState block = (BlockState) object; List meta = BlockUtils.processMeta(block); - if (blockType.equals(Material.SKELETON_SKULL) || blockType.equals(Material.SKELETON_WALL_SKULL) || blockType.equals(Material.WITHER_SKELETON_SKULL) || blockType.equals(Material.WITHER_SKELETON_WALL_SKULL) || blockType.equals(Material.ZOMBIE_HEAD) || blockType.equals(Material.ZOMBIE_WALL_HEAD) || blockType.equals(Material.PLAYER_HEAD) || blockType.equals(Material.PLAYER_WALL_HEAD) || blockType.equals(Material.CREEPER_HEAD) || blockType.equals(Material.CREEPER_WALL_HEAD) || blockType.equals(Material.DRAGON_HEAD) || blockType.equals(Material.DRAGON_WALL_HEAD)) { + if (blockType != null && (blockType.equals(Material.SKELETON_SKULL) || blockType.equals(Material.SKELETON_WALL_SKULL) || blockType.equals(Material.WITHER_SKELETON_SKULL) || blockType.equals(Material.WITHER_SKELETON_WALL_SKULL) || blockType.equals(Material.ZOMBIE_HEAD) || blockType.equals(Material.ZOMBIE_WALL_HEAD) || blockType.equals(Material.PLAYER_HEAD) || blockType.equals(Material.PLAYER_WALL_HEAD) || blockType.equals(Material.CREEPER_HEAD) || blockType.equals(Material.CREEPER_WALL_HEAD) || blockType.equals(Material.DRAGON_HEAD) || blockType.equals(Material.DRAGON_WALL_HEAD))) { SkullPlaceLogger.log(preparedStmt, preparedStmtSkulls, batchCount, user, block, MaterialUtils.getBlockId(replaceType), replaceData); } else if (forceData == 1) { diff --git a/src/main/java/net/coreprotect/database/LookupRaw.java b/src/main/java/net/coreprotect/database/LookupRaw.java index 9d79cea1..cdb4f5a8 100644 --- a/src/main/java/net/coreprotect/database/LookupRaw.java +++ b/src/main/java/net/coreprotect/database/LookupRaw.java @@ -314,6 +314,15 @@ public class LookupRaw extends Queue { includeListEntity.append(",").append(EntityUtils.getEntityId(targetName, false)); } } + else if (restrictTarget instanceof String) { + int blockId = MaterialUtils.getBlockId((String) restrictTarget, false); + if (includeListMaterial.length() == 0) { + includeListMaterial = includeListMaterial.append(blockId); + } + else { + includeListMaterial.append(",").append(blockId); + } + } } includeBlock = includeListMaterial.toString(); @@ -351,6 +360,17 @@ public class LookupRaw extends Queue { excludeListEntity.append(",").append(EntityUtils.getEntityId(targetName, false)); } } + else if (restrictTarget instanceof String) { + int blockId = MaterialUtils.getBlockId((String) restrictTarget, false); + if (blockId > -1) { + if (excludeListMaterial.length() == 0) { + excludeListMaterial = excludeListMaterial.append(blockId); + } + else { + excludeListMaterial.append(",").append(blockId); + } + } + } } excludeBlock = excludeListMaterial.toString(); diff --git a/src/main/java/net/coreprotect/database/logger/BlockBreakLogger.java b/src/main/java/net/coreprotect/database/logger/BlockBreakLogger.java index 16111e24..d6423a87 100644 --- a/src/main/java/net/coreprotect/database/logger/BlockBreakLogger.java +++ b/src/main/java/net/coreprotect/database/logger/BlockBreakLogger.java @@ -16,6 +16,7 @@ import net.coreprotect.database.statement.BlockStatement; import net.coreprotect.database.statement.UserStatement; import net.coreprotect.event.CoreProtectPreLogEvent; import net.coreprotect.thread.CacheHandler; +import net.coreprotect.utility.BlockTypeUtils; import net.coreprotect.utility.WorldUtils; public class BlockBreakLogger { @@ -27,14 +28,19 @@ public class BlockBreakLogger { public static void log(PreparedStatement preparedStmt, int batchCount, String user, Location location, int type, int data, List meta, String blockData, String overrideData) { try { Material checkType = net.coreprotect.utility.MaterialUtils.getType(type); - if (checkType == null) { + String blockKey = BlockTypeUtils.getBlockDataKey(blockData); + if (blockKey.length() == 0 && checkType != null) { + blockKey = checkType.getKey().toString(); + } + + if (checkType == null && blockKey.length() == 0) { return; } - else if (checkType.equals(Material.AIR) || checkType.equals(Material.CAVE_AIR)) { + else if (checkType != null && (checkType.equals(Material.AIR) || checkType.equals(Material.CAVE_AIR)) && BlockTypeUtils.isAir(blockKey)) { return; } - if (ConfigHandler.isBlacklisted(user, checkType.getKey().toString())) { + if (ConfigHandler.isBlacklisted(user, blockKey)) { return; } @@ -46,7 +52,7 @@ public class BlockBreakLogger { if (checkType == Material.LECTERN) { blockData = blockData.replaceFirst("has_book=true", "has_book=false"); } - else if (checkType == Material.PAINTING || BukkitAdapter.ADAPTER.isItemFrame(checkType)) { + else if (checkType != null && (checkType == Material.PAINTING || BukkitAdapter.ADAPTER.isItemFrame(checkType))) { blockData = overrideData; } @@ -68,7 +74,8 @@ public class BlockBreakLogger { return; } - BlockStatement.insert(preparedStmt, batchCount, time, userId, wid, x, y, z, type, data, meta, blockData, 0, 0); + int internalType = blockKey.length() > 0 ? net.coreprotect.utility.MaterialUtils.getBlockId(blockKey, true) : type; + BlockStatement.insert(preparedStmt, batchCount, time, userId, wid, x, y, z, internalType, data, meta, blockData, 0, 0); } catch (Exception e) { e.printStackTrace(); diff --git a/src/main/java/net/coreprotect/database/logger/BlockPlaceLogger.java b/src/main/java/net/coreprotect/database/logger/BlockPlaceLogger.java index 8a7bd94c..0b438bde 100644 --- a/src/main/java/net/coreprotect/database/logger/BlockPlaceLogger.java +++ b/src/main/java/net/coreprotect/database/logger/BlockPlaceLogger.java @@ -17,6 +17,7 @@ import net.coreprotect.database.statement.BlockStatement; import net.coreprotect.database.statement.UserStatement; import net.coreprotect.event.CoreProtectPreLogEvent; import net.coreprotect.thread.CacheHandler; +import net.coreprotect.utility.BlockTypeUtils; import net.coreprotect.utility.MaterialUtils; import net.coreprotect.utility.WorldUtils; @@ -31,10 +32,11 @@ public class BlockPlaceLogger { Material type = block.getType(); if (blockData == null && (forceType == null || (!forceType.equals(Material.WATER)) && (!forceType.equals(Material.LAVA)))) { blockData = block.getBlockData().getAsString(); - if (blockData.equals("minecraft:air")) { + if (BlockTypeUtils.isAir(BlockTypeUtils.getBlockDataKey(blockData))) { blockData = null; } } + String blockKey = BlockTypeUtils.getBlockDataKey(blockData); int data = 0; if (forceType != null && force) { type = forceType; @@ -45,16 +47,22 @@ public class BlockPlaceLogger { data = forceData; } } - else if (forceType != null && !type.equals(forceType)) { + else if (forceType != null && (type == null || !type.equals(forceType))) { type = forceType; data = forceData; } + if (blockKey.length() == 0) { + if (type == null) { + return; + } + blockKey = type.getKey().toString(); + } - if (type.equals(Material.AIR) || type.equals(Material.CAVE_AIR)) { + if (type != null && (type.equals(Material.AIR) || type.equals(Material.CAVE_AIR)) && BlockTypeUtils.isAir(blockKey)) { return; } - if (ConfigHandler.isBlacklisted(user, type.getKey().toString())){ + if (ConfigHandler.isBlacklisted(user, blockKey)){ return; } @@ -105,9 +113,10 @@ public class BlockPlaceLogger { return; } - int internalType = MaterialUtils.getBlockId(type.name(), true); - if (replacedType > 0 && MaterialUtils.getType(replacedType) != Material.AIR && MaterialUtils.getType(replacedType) != Material.CAVE_AIR) { - BlockStatement.insert(preparedStmt, batchCount, time, userId, wid, x, y, z, replacedType, replacedData, null, replaceBlockData, 0, 0); + int internalType = MaterialUtils.getBlockId(blockKey, true); + int replacedInternalType = MaterialUtils.getBlockId(replaceBlockData, MaterialUtils.getType(replacedType), true); + if (replacedInternalType > 0 && !BlockTypeUtils.isAir(MaterialUtils.getBlockName(replacedInternalType))) { + BlockStatement.insert(preparedStmt, batchCount, time, userId, wid, x, y, z, replacedInternalType, replacedData, null, replaceBlockData, 0, 0); } BlockStatement.insert(preparedStmt, batchCount, time, userId, wid, x, y, z, internalType, data, meta, blockData, 1, 0); diff --git a/src/main/java/net/coreprotect/database/logger/PlayerInteractLogger.java b/src/main/java/net/coreprotect/database/logger/PlayerInteractLogger.java index 00ad5c7f..728cf864 100644 --- a/src/main/java/net/coreprotect/database/logger/PlayerInteractLogger.java +++ b/src/main/java/net/coreprotect/database/logger/PlayerInteractLogger.java @@ -1,8 +1,6 @@ package net.coreprotect.database.logger; import java.sql.PreparedStatement; -import java.util.Locale; - import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.Location; @@ -14,6 +12,7 @@ import net.coreprotect.config.ConfigHandler; import net.coreprotect.database.statement.BlockStatement; import net.coreprotect.database.statement.UserStatement; import net.coreprotect.event.CoreProtectPreLogEvent; +import net.coreprotect.utility.BlockTypeUtils; import net.coreprotect.utility.MaterialUtils; import net.coreprotect.utility.WorldUtils; @@ -25,8 +24,17 @@ public class PlayerInteractLogger { public static void log(PreparedStatement preparedStmt, int batchCount, String user, BlockState block, Material blockType) { try { - int type = MaterialUtils.getBlockId(blockType.name(), true); - if (ConfigHandler.isBlacklisted(user) || MaterialUtils.getType(type).equals(Material.AIR) || MaterialUtils.getType(type).equals(Material.CAVE_AIR)) { + String blockData = block.getBlockData().getAsString(); + String blockKey = BlockTypeUtils.getBlockDataKey(blockData); + if (blockKey.length() == 0 && blockType != null) { + blockKey = blockType.getKey().toString(); + } + if (blockKey.length() == 0) { + return; + } + + int type = MaterialUtils.getBlockId(blockKey, true); + if (ConfigHandler.isBlacklisted(user) || BlockTypeUtils.isAir(blockKey)) { return; } @@ -47,7 +55,7 @@ public class PlayerInteractLogger { int y = eventLocation.getBlockY(); int z = eventLocation.getBlockZ(); int data = 0; - BlockStatement.insert(preparedStmt, batchCount, time, userId, wid, x, y, z, type, data, null, null, 2, 0); + BlockStatement.insert(preparedStmt, batchCount, time, userId, wid, x, y, z, type, data, null, blockData, 2, 0); } catch (Exception e) { e.printStackTrace(); diff --git a/src/main/java/net/coreprotect/database/lookup/BlockLookup.java b/src/main/java/net/coreprotect/database/lookup/BlockLookup.java index 475aede3..a4d6119f 100644 --- a/src/main/java/net/coreprotect/database/lookup/BlockLookup.java +++ b/src/main/java/net/coreprotect/database/lookup/BlockLookup.java @@ -112,12 +112,10 @@ public class BlockLookup { target = EntityUtils.getEntityType(resultType).name(); } else { - Material resultMaterial = MaterialUtils.getType(resultType); - if (resultMaterial == null) { - resultMaterial = Material.AIR; + target = MaterialUtils.getBlockDisplayName(resultType, resultData); + if (target.length() > 0 && !target.contains(":")) { + target = "minecraft:" + target.toLowerCase(Locale.ROOT); } - target = StringUtils.nameFilter(resultMaterial.name().toLowerCase(Locale.ROOT), resultData); - target = "minecraft:" + target.toLowerCase(Locale.ROOT); } if (target.length() > 0) { target = "" + target + ""; diff --git a/src/main/java/net/coreprotect/database/lookup/ChestTransactionLookup.java b/src/main/java/net/coreprotect/database/lookup/ChestTransactionLookup.java index f4dd1f24..f557f63b 100644 --- a/src/main/java/net/coreprotect/database/lookup/ChestTransactionLookup.java +++ b/src/main/java/net/coreprotect/database/lookup/ChestTransactionLookup.java @@ -108,13 +108,8 @@ public class ChestTransactionLookup { rbFormat = Color.STRIKETHROUGH; } - Material resultMaterial = MaterialUtils.getType(resultType); - if (resultMaterial == null) { - resultMaterial = Material.AIR; - } - String target = resultMaterial.name().toLowerCase(Locale.ROOT); - target = StringUtils.nameFilter(target, resultData); - if (target.length() > 0) { + String target = MaterialUtils.getBlockDisplayName(resultType, resultData); + if (target.length() > 0 && !target.contains(":")) { target = "minecraft:" + target.toLowerCase(Locale.ROOT) + ""; } diff --git a/src/main/java/net/coreprotect/database/lookup/InteractionLookup.java b/src/main/java/net/coreprotect/database/lookup/InteractionLookup.java index bd0d6aac..5a353295 100644 --- a/src/main/java/net/coreprotect/database/lookup/InteractionLookup.java +++ b/src/main/java/net/coreprotect/database/lookup/InteractionLookup.java @@ -4,7 +4,6 @@ import java.sql.ResultSet; import java.sql.Statement; import java.util.Locale; -import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.command.CommandSender; @@ -16,7 +15,6 @@ import net.coreprotect.listener.channel.PluginChannelListener; import net.coreprotect.utility.ChatUtils; import net.coreprotect.utility.Color; import net.coreprotect.utility.MaterialUtils; -import net.coreprotect.utility.StringUtils; import net.coreprotect.utility.WorldUtils; public class InteractionLookup { @@ -96,13 +94,8 @@ public class InteractionLookup { rbFormat = Color.STRIKETHROUGH; } - Material resultMaterial = MaterialUtils.getType(resultType); - if (resultMaterial == null) { - resultMaterial = Material.AIR; - } - String target = resultMaterial.name().toLowerCase(Locale.ROOT); - target = StringUtils.nameFilter(target, resultData); - if (target.length() > 0) { + String target = MaterialUtils.getBlockDisplayName(resultType, resultData); + if (target.length() > 0 && !target.contains(":")) { target = "minecraft:" + target.toLowerCase(Locale.ROOT) + ""; } diff --git a/src/main/java/net/coreprotect/database/rollback/RollbackBlockHandler.java b/src/main/java/net/coreprotect/database/rollback/RollbackBlockHandler.java index 9cff929d..da83fc01 100644 --- a/src/main/java/net/coreprotect/database/rollback/RollbackBlockHandler.java +++ b/src/main/java/net/coreprotect/database/rollback/RollbackBlockHandler.java @@ -77,6 +77,15 @@ public class RollbackBlockHandler extends Queue { ((Piston) blockData).setFacing(technicalPiston.getFacing()); } + if (rowType == null) { + if (blockData != null) { + BlockUtils.prepareTypeAndData(chunkChanges, block, null, blockData, true); + return countBlock; + } + + return false; + } + if ((rowType == Material.AIR) && ((BukkitAdapter.ADAPTER.isItemFrame(oldTypeMaterial)) || (oldTypeMaterial == Material.PAINTING))) { HangingUtil.removeHanging(block.getState(), blockDataString); } diff --git a/src/main/java/net/coreprotect/database/rollback/RollbackComplete.java b/src/main/java/net/coreprotect/database/rollback/RollbackComplete.java index 451bea39..4dce9243 100644 --- a/src/main/java/net/coreprotect/database/rollback/RollbackComplete.java +++ b/src/main/java/net/coreprotect/database/rollback/RollbackComplete.java @@ -124,6 +124,10 @@ public class RollbackComplete { item = (!item ? !(((Material) restrictTarget).isBlock()) : item); material = true; } + else if (restrictTarget instanceof String) { + targetName = ((String) restrictTarget).toLowerCase(Locale.ROOT); + material = true; + } else if (restrictTarget instanceof EntityType) { targetName = ((EntityType) restrictTarget).name().toLowerCase(Locale.ROOT); entity = true; @@ -182,6 +186,10 @@ public class RollbackComplete { item = (!item ? !(((Material) excludeTarget).isBlock()) : item); material = true; } + else if (excludeTarget instanceof String) { + targetName = ((String) excludeTarget).toLowerCase(Locale.ROOT); + material = true; + } else if (excludeTarget instanceof EntityType) { targetName = ((EntityType) excludeTarget).name().toLowerCase(Locale.ROOT); entity = true; diff --git a/src/main/java/net/coreprotect/database/rollback/RollbackProcessor.java b/src/main/java/net/coreprotect/database/rollback/RollbackProcessor.java index 5b98848e..21a0e985 100644 --- a/src/main/java/net/coreprotect/database/rollback/RollbackProcessor.java +++ b/src/main/java/net/coreprotect/database/rollback/RollbackProcessor.java @@ -33,6 +33,7 @@ import net.coreprotect.database.logger.ItemLogger; import net.coreprotect.model.BlockGroup; import net.coreprotect.thread.Scheduler; import net.coreprotect.utility.BlockUtils; +import net.coreprotect.utility.BlockTypeUtils; import net.coreprotect.utility.ItemUtils; import net.coreprotect.utility.MaterialUtils; import net.coreprotect.utility.Teleport; @@ -101,7 +102,10 @@ public class RollbackProcessor { BlockData blockData = null; if (blockDataString != null && blockDataString.contains(":")) { try { - blockData = Bukkit.getServer().createBlockData(blockDataString); + blockData = BlockTypeUtils.createBlockDataFromString(blockDataString); + if (blockData == null) { + blockData = Bukkit.getServer().createBlockData(blockDataString); + } } catch (Exception e) { // corrupt BlockData, let the server automatically set the BlockData instead @@ -112,8 +116,8 @@ public class RollbackProcessor { if (blockData != null) { rawBlockData = blockData.clone(); } - if (rawBlockData == null && rowType != null && rowType.isBlock()) { - rawBlockData = BlockUtils.createBlockData(rowType); + if (rawBlockData == null) { + rawBlockData = BlockUtils.createBlockData(rowTypeRaw); } String rowUser = ConfigHandler.playerIdCacheReversed.get((Integer) row[2]); diff --git a/src/main/java/net/coreprotect/utility/BlockTypeUtils.java b/src/main/java/net/coreprotect/utility/BlockTypeUtils.java new file mode 100644 index 00000000..cbf34d0d --- /dev/null +++ b/src/main/java/net/coreprotect/utility/BlockTypeUtils.java @@ -0,0 +1,94 @@ +package net.coreprotect.utility; + +import java.util.Locale; + +import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.Waterlogged; + +import net.coreprotect.bukkit.BukkitAdapter; + +public class BlockTypeUtils { + + private static final String NAMESPACE = "minecraft:"; + + private BlockTypeUtils() { + throw new IllegalStateException("Utility class"); + } + + public static String normalizeKey(String key) { + if (key == null) { + return ""; + } + + key = key.toLowerCase(Locale.ROOT).trim(); + if (key.length() > 0 && !key.contains(":")) { + key = NAMESPACE + key; + } + + return key; + } + + public static String getBlockDataKey(String blockData) { + if (blockData == null) { + return ""; + } + + String key = blockData; + int propertyIndex = key.indexOf('['); + if (propertyIndex > -1) { + key = key.substring(0, propertyIndex); + } + + return normalizeKey(key); + } + + public static String getBlockDataStates(String blockData) { + if (blockData == null) { + return null; + } + + int propertyIndex = blockData.indexOf('['); + if (propertyIndex == -1 || !blockData.endsWith("]")) { + return null; + } + + return blockData.substring(propertyIndex); + } + + public static boolean hasBlockType(String key) { + return BukkitAdapter.ADAPTER != null && BukkitAdapter.ADAPTER.hasBlockType(normalizeKey(key)); + } + + public static BlockData createBlockData(String key) { + if (BukkitAdapter.ADAPTER == null) { + return null; + } + + return normalizeBlockData(BukkitAdapter.ADAPTER.createBlockData(normalizeKey(key))); + } + + public static BlockData createBlockDataFromString(String blockData) { + if (BukkitAdapter.ADAPTER == null) { + return null; + } + + return normalizeBlockData(BukkitAdapter.ADAPTER.createBlockDataFromString(blockData)); + } + + public static boolean isAir(String key) { + key = normalizeKey(key); + return "minecraft:air".equals(key) || "minecraft:cave_air".equals(key) || "minecraft:void_air".equals(key); + } + + private static BlockData normalizeBlockData(BlockData blockData) { + if (blockData == null) { + return null; + } + + if (blockData instanceof Waterlogged) { + ((Waterlogged) blockData).setWaterlogged(false); + } + + return blockData; + } +} diff --git a/src/main/java/net/coreprotect/utility/BlockUtils.java b/src/main/java/net/coreprotect/utility/BlockUtils.java index fadac292..c59241eb 100644 --- a/src/main/java/net/coreprotect/utility/BlockUtils.java +++ b/src/main/java/net/coreprotect/utility/BlockUtils.java @@ -3,7 +3,6 @@ package net.coreprotect.utility; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; -import java.util.Locale; import java.util.Map; import org.bukkit.Material; @@ -26,8 +25,6 @@ import net.coreprotect.thread.Scheduler; public class BlockUtils { - private static final String NAMESPACE = "minecraft:"; - private BlockUtils() { throw new IllegalStateException("Utility class"); } @@ -36,12 +33,17 @@ public class BlockUtils { byte[] result = null; if (string != null) { Material material = MaterialUtils.getType(type); - if (material == null) { + String blockKey = MaterialUtils.getBlockName(type); + if ((blockKey == null || blockKey.length() == 0) && material != null) { + blockKey = material.getKey().toString(); + } + if (blockKey == null || blockKey.length() == 0) { return result; } - if (material.isBlock() && !createBlockData(material).getAsString().equals(string) && string.startsWith(NAMESPACE + material.name().toLowerCase(Locale.ROOT) + "[") && string.endsWith("]")) { - String substring = string.substring(material.name().length() + 11, string.length() - 1); + BlockData defaultBlockData = createBlockData(type); + if (defaultBlockData != null && !defaultBlockData.getAsString().equals(string) && string.startsWith(blockKey + "[") && string.endsWith("]")) { + String substring = string.substring(blockKey.length() + 1, string.length() - 1); String[] blockDataSplit = substring.split(","); ArrayList blockDataArray = new ArrayList<>(); for (String data : blockDataSplit) { @@ -52,7 +54,7 @@ public class BlockUtils { } string = String.join(",", blockDataArray); } - else if (!string.contains(":") && (material == Material.PAINTING || BukkitAdapter.ADAPTER.isItemFrame(material))) { + else if (material != null && !string.contains(":") && (material == Material.PAINTING || BukkitAdapter.ADAPTER.isItemFrame(material))) { int id = MaterialUtils.getBlockdataId(string, true); if (id > -1) { string = Integer.toString(id); @@ -75,7 +77,11 @@ public class BlockUtils { String result = ""; if (data != null) { Material material = MaterialUtils.getType(type); - if (material == null) { + String blockKey = MaterialUtils.getBlockName(type); + if ((blockKey == null || blockKey.length() == 0) && material != null) { + blockKey = material.getKey().toString(); + } + if (blockKey == null || blockKey.length() == 0) { return result; } @@ -94,11 +100,11 @@ public class BlockUtils { } } - if (material == Material.PAINTING || BukkitAdapter.ADAPTER.isItemFrame(material)) { + if (material != null && (material == Material.PAINTING || BukkitAdapter.ADAPTER.isItemFrame(material))) { result = String.join(",", blockDataArray); } else { - result = NAMESPACE + material.name().toLowerCase(Locale.ROOT) + "[" + String.join(",", blockDataArray) + "]"; + result = blockKey + "[" + String.join(",", blockDataArray) + "]"; } } else { @@ -161,6 +167,15 @@ public class BlockUtils { } } + public static BlockData createBlockData(int type) { + Material material = MaterialUtils.getType(type); + if (material != null && material.isBlock()) { + return createBlockData(material); + } + + return BlockTypeUtils.createBlockData(MaterialUtils.getBlockName(type)); + } + public static void prepareTypeAndData(Map map, Block block, Material type, BlockData blockData, boolean update) { if (blockData == null) { blockData = createBlockData(type); diff --git a/src/main/java/net/coreprotect/utility/MaterialUtils.java b/src/main/java/net/coreprotect/utility/MaterialUtils.java index 19d282d4..0f686068 100644 --- a/src/main/java/net/coreprotect/utility/MaterialUtils.java +++ b/src/main/java/net/coreprotect/utility/MaterialUtils.java @@ -24,6 +24,15 @@ public class MaterialUtils extends Queue { return getBlockId(material.name(), true); } + public static int getBlockId(String blockData, Material fallback, boolean internal) { + String name = BlockTypeUtils.getBlockDataKey(blockData); + if (name.length() == 0 && fallback != null) { + name = fallback.getKey().toString(); + } + + return name.length() == 0 ? -1 : getBlockId(name, internal); + } + public static int getBlockId(String name, boolean internal) { int id = -1; @@ -95,6 +104,15 @@ public class MaterialUtils extends Queue { return name; } + public static String getBlockDisplayName(int id, int data) { + Material material = getType(id); + if (material != null) { + return StringUtils.nameFilter(material.name().toLowerCase(Locale.ROOT), data); + } + + return getBlockName(id); + } + public static String getBlockNameShort(int id) { String name = getBlockName(id); if (name.contains(":")) {