Skip to content

Commit cb571b2

Browse files
committed
fix item frame rotation
1 parent ca02ca1 commit cb571b2

File tree

1 file changed

+77
-12
lines changed

1 file changed

+77
-12
lines changed

worldedit-core/src/main/java/com/sk89q/worldedit/function/entity/ExtentEntityCopy.java

Lines changed: 77 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,11 @@
3636
import com.sk89q.worldedit.util.Location;
3737
import com.sk89q.worldedit.util.concurrency.LazyReference;
3838
import com.sk89q.worldedit.world.entity.EntityTypes;
39+
import org.enginehub.linbus.tree.LinByteTag;
3940
import org.enginehub.linbus.tree.LinCompoundTag;
4041
import org.enginehub.linbus.tree.LinIntArrayTag;
4142
import org.enginehub.linbus.tree.LinNumberTag;
43+
import org.enginehub.linbus.tree.LinStringTag;
4244
import org.enginehub.linbus.tree.LinTagType;
4345

4446
import static com.google.common.base.Preconditions.checkNotNull;
@@ -218,23 +220,42 @@ private BaseEntity transformNbtData(BaseEntity state) {
218220
}
219221

220222
if (tryGetFacingData(tag) instanceof FacingTagData(String facingKey, LinNumberTag<?> tagFacing)) {
221-
boolean isPainting = state.getType() == EntityTypes.PAINTING; // Paintings have different facing values
222-
Direction direction = isPainting
223-
? MCDirections.fromHorizontalHanging(tagFacing.value().intValue())
224-
: MCDirections.fromHanging(tagFacing.value().intValue());
225-
226-
if (direction != null) {
223+
if (state.getType() == EntityTypes.PAINTING) { // Paintings have different facing values
224+
Direction direction = MCDirections.fromHorizontalHanging(tagFacing.value().intValue());
227225
Vector3 vector = transform.apply(direction.toVector()).subtract(transform.apply(Vector3.ZERO)).normalize();
228226
Direction newDirection = Direction.findClosest(vector, Flag.CARDINAL);
227+
byte facingValue = (byte) MCDirections.toHorizontalHanging(newDirection);
228+
builder.putByte(facingKey, facingValue);
229+
} else {
230+
Direction facingDirection = MCDirections.fromHanging(tagFacing.value().intValue());
231+
Vector3 facingVector = transform.apply(facingDirection.toVector()).subtract(transform.apply(Vector3.ZERO)).normalize();
232+
Direction newFacingDirection = Direction.findClosest(facingVector, Flag.CARDINAL | Flag.UPRIGHT);
233+
byte facingValue = (byte) MCDirections.toHanging(newFacingDirection);
234+
builder.putByte(facingKey, facingValue);
229235

230-
if (newDirection != null) {
231-
byte facingValue = (byte) (
232-
isPainting
233-
? MCDirections.toHorizontalHanging(newDirection)
234-
: MCDirections.toHanging(newDirection)
236+
String itemRotationKey = "ItemRotation";
237+
if (!transform.isIdentity() && tag.value().get(itemRotationKey) instanceof LinByteTag tagItemRotation) {
238+
String itemId = getItemInItemFrame(tag);
239+
int availableRotations = itemId != null && itemId.equals("minecraft:filled_map") ? 4 : 8;
240+
Direction rotationBaseDirection =
241+
facingDirection == Direction.UP || facingDirection == Direction.DOWN
242+
? Direction.NORTH
243+
: Direction.UP;
244+
int itemRotation = tagItemRotation.value().intValue();
245+
Vector3 rotationVector = getItemRotationVector(
246+
rotationBaseDirection, facingDirection.toVector(), itemRotation, availableRotations
247+
);
248+
Vector3 newRotationVector = transform.apply(rotationVector);
249+
Direction newRotationBaseDirection =
250+
newFacingDirection == Direction.UP || newFacingDirection == Direction.DOWN
251+
? Direction.NORTH
252+
: Direction.UP;
253+
byte newItemRotation = (byte) getItemRotationSteps(
254+
newRotationBaseDirection, newFacingDirection, newRotationVector, availableRotations
235255
);
236-
builder.putByte(facingKey, facingValue);
256+
builder.putByte(itemRotationKey, newItemRotation);
237257
}
258+
238259
}
239260
}
240261

@@ -245,6 +266,50 @@ private BaseEntity transformNbtData(BaseEntity state) {
245266
return state;
246267
}
247268

269+
private Vector3 getItemRotationVector(Direction baseDirection, Vector3 facingVector, int itemRotation, int rotations) {
270+
Vector3 baseVec = baseDirection.toVector().normalize();
271+
double angle = Math.toRadians(itemRotation * (360f / rotations));
272+
Vector3 rotated = rotateAroundAxis(baseVec, facingVector, -angle);
273+
return rotated.normalize();
274+
}
275+
276+
private Vector3 rotateAroundAxis(Vector3 vec, Vector3 axis, double angle) {
277+
axis = axis.normalize();
278+
double cos = Math.cos(angle);
279+
double sin = Math.sin(angle);
280+
return vec.multiply(cos).add(axis.cross(vec).multiply(sin)).add(axis.multiply(axis.dot(vec) * (1 - cos)));
281+
}
282+
283+
private int getItemRotationSteps(Direction baseDirection, Direction facingDirection, Vector3 targetVector, int rotations) {
284+
Vector3 baseVec = baseDirection.toVector();
285+
286+
double det = facingDirection.toVector().dot(baseVec.cross(targetVector));
287+
double dot = baseVec.dot(targetVector);
288+
double signedAngle = Math.atan2(det, dot);
289+
290+
double stepsDouble = -signedAngle / (Math.PI / (rotations / 2f));
291+
int steps = (int) Math.round(stepsDouble) % rotations;
292+
if (steps < 0) {
293+
steps += rotations;
294+
}
295+
296+
if (facingDirection == Direction.DOWN) {
297+
steps = (steps + (rotations / 2)) % rotations;
298+
}
299+
300+
return steps;
301+
}
302+
303+
private String getItemInItemFrame(LinCompoundTag tag) {
304+
if (tag.value().get("Item") instanceof LinCompoundTag tagItem) {
305+
if (tagItem.value().get("id") instanceof LinStringTag tagId) {
306+
return tagId.value();
307+
}
308+
}
309+
310+
return null;
311+
}
312+
248313
private record FacingTagData(String facingKey, LinNumberTag<?> tagFacing) {
249314
}
250315

0 commit comments

Comments
 (0)