From 4a7683d5bf59da1532ab38dcbe69322b8ff4f174 Mon Sep 17 00:00:00 2001 From: FrozenBrain Date: Thu, 19 May 2016 19:16:59 +0200 Subject: [PATCH] Apply transformations to NBT data of tile entities (fixes rotation of skulls) --- .../function/block/ExtentBlockCopy.java | 46 ++++++++++- .../internal/helper/MCDirections.java | 78 +++++++++++++++++++ 2 files changed, 123 insertions(+), 1 deletion(-) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/block/ExtentBlockCopy.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/block/ExtentBlockCopy.java index f7bdf8e11..94e39cd0c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/block/ExtentBlockCopy.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/block/ExtentBlockCopy.java @@ -19,12 +19,17 @@ package com.sk89q.worldedit.function.block; -import com.sk89q.worldedit.extent.Extent; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.CompoundTagBuilder; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.internal.helper.MCDirections; import com.sk89q.worldedit.math.transform.Transform; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.util.Direction.Flag; import static com.google.common.base.Preconditions.checkNotNull; @@ -66,7 +71,46 @@ public class ExtentBlockCopy implements RegionFunction { BaseBlock block = source.getBlock(position); Vector orig = position.subtract(from); Vector transformed = transform.apply(orig); + + // Apply transformations to NBT data if necessary + block = transformNbtData(block); + return destination.setBlock(transformed.add(to), block); } + /** + * Transform NBT data in the given block state and return a new instance + * if the NBT data needs to be transformed. + * + * @param state the existing state + * @return a new state or the existing one + */ + private BaseBlock transformNbtData(BaseBlock state) { + CompoundTag tag = state.getNbtData(); + + if (tag != null) { + // Handle blocks which store their rotation in NBT + if (tag.containsKey("Rot")) { + int rot = tag.asInt("Rot"); + + Direction direction = MCDirections.fromRotation(rot); + + if (direction != null) { + Vector vector = transform.apply(direction.toVector()).subtract(transform.apply(Vector.ZERO)).normalize(); + Direction newDirection = Direction.findClosest(vector, Flag.CARDINAL | Flag.ORDINAL | Flag.SECONDARY_ORDINAL); + + if (newDirection != null) { + CompoundTagBuilder builder = tag.createBuilder(); + + builder.putByte("Rot", (byte) MCDirections.toRotation(newDirection)); + + return new BaseBlock(state.getId(), state.getData(), builder.build()); + } + } + } + } + + return state; + } + } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/helper/MCDirections.java b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/helper/MCDirections.java index d9e75d62f..16e25e354 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/internal/helper/MCDirections.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/internal/helper/MCDirections.java @@ -77,4 +77,82 @@ public final class MCDirections { } } + public static Direction fromRotation(int i) { + switch (i) { + case 0: + return Direction.SOUTH; + case 1: + return Direction.SOUTH_SOUTHWEST; + case 2: + return Direction.SOUTHWEST; + case 3: + return Direction.WEST_SOUTHWEST; + case 4: + return Direction.WEST; + case 5: + return Direction.WEST_NORTHWEST; + case 6: + return Direction.NORTHWEST; + case 7: + return Direction.NORTH_NORTHWEST; + case 8: + return Direction.NORTH; + case 9: + return Direction.NORTH_NORTHEAST; + case 10: + return Direction.NORTHEAST; + case 11: + return Direction.EAST_NORTHEAST; + case 12: + return Direction.EAST; + case 13: + return Direction.EAST_SOUTHEAST; + case 14: + return Direction.SOUTHEAST; + case 15: + return Direction.SOUTH_SOUTHEAST; + default: + return Direction.NORTH; + } + } + + public static int toRotation(Direction direction) { + switch (direction) { + case SOUTH: + return 0; + case SOUTH_SOUTHWEST: + return 1; + case SOUTHWEST: + return 2; + case WEST_SOUTHWEST: + return 3; + case WEST: + return 4; + case WEST_NORTHWEST: + return 5; + case NORTHWEST: + return 6; + case NORTH_NORTHWEST: + return 7; + case NORTH: + return 8; + case NORTH_NORTHEAST: + return 9; + case NORTHEAST: + return 10; + case EAST_NORTHEAST: + return 11; + case EAST: + return 12; + case EAST_SOUTHEAST: + return 13; + case SOUTHEAST: + return 14; + case SOUTH_SOUTHEAST: + return 15; + default: + return 0; + } + } + }