3636import com .sk89q .worldedit .util .Location ;
3737import com .sk89q .worldedit .util .concurrency .LazyReference ;
3838import com .sk89q .worldedit .world .entity .EntityTypes ;
39+ import org .enginehub .linbus .tree .LinByteTag ;
3940import org .enginehub .linbus .tree .LinCompoundTag ;
4041import org .enginehub .linbus .tree .LinIntArrayTag ;
4142import org .enginehub .linbus .tree .LinNumberTag ;
43+ import org .enginehub .linbus .tree .LinStringTag ;
4244import org .enginehub .linbus .tree .LinTagType ;
4345
4446import 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