diff --git a/src/main/java/com/laytonsmith/abstraction/Convertor.java b/src/main/java/com/laytonsmith/abstraction/Convertor.java index 208ed02a7..bfac3e234 100644 --- a/src/main/java/com/laytonsmith/abstraction/Convertor.java +++ b/src/main/java/com/laytonsmith/abstraction/Convertor.java @@ -2,6 +2,7 @@ import com.laytonsmith.PureUtilities.DaemonManager; import com.laytonsmith.abstraction.blocks.MCMaterial; +import com.laytonsmith.abstraction.entities.MCTransformation; import com.laytonsmith.abstraction.enums.MCAttribute; import com.laytonsmith.abstraction.enums.MCDyeColor; import com.laytonsmith.abstraction.enums.MCEquipmentSlot; @@ -17,6 +18,8 @@ import java.util.List; import java.util.UUID; import java.util.concurrent.Callable; +import org.joml.Quaternionf; +import org.joml.Vector3f; /** * This should be implemented once for each server type. It mostly wraps static methods, but also provides methods for @@ -281,4 +284,14 @@ public interface Convertor { * @return a key object */ MCNamespacedKey GetNamespacedKey(String key); + + /** + * Returns a new Transformation object. + * @param leftRotation + * @param rightRotation + * @param scale + * @param translation + * @return + */ + public MCTransformation GetTransformation(Quaternionf leftRotation, Quaternionf rightRotation, Vector3f scale, Vector3f translation); } diff --git a/src/main/java/com/laytonsmith/abstraction/StaticLayer.java b/src/main/java/com/laytonsmith/abstraction/StaticLayer.java index 4374ced86..9ed07c5ec 100644 --- a/src/main/java/com/laytonsmith/abstraction/StaticLayer.java +++ b/src/main/java/com/laytonsmith/abstraction/StaticLayer.java @@ -4,12 +4,15 @@ import com.laytonsmith.PureUtilities.Common.StreamUtils; import com.laytonsmith.PureUtilities.DaemonManager; import com.laytonsmith.abstraction.blocks.MCMaterial; +import com.laytonsmith.abstraction.entities.MCTransformation; import com.laytonsmith.abstraction.enums.MCPotionType; import com.laytonsmith.abstraction.enums.MCRecipeType; import com.laytonsmith.annotations.convert; import com.laytonsmith.commandhelper.CommandHelperPlugin; import java.util.Set; +import org.joml.Quaternionf; +import org.joml.Vector3f; /** * Unfortunately some methods just can't be overridden. @@ -151,6 +154,10 @@ public static MCRecipe GetNewRecipe(String key, MCRecipeType type, MCItemStack r return convertor.GetNewRecipe(key, type, result); } + public static MCTransformation GetTransformation(Quaternionf leftRotation, Quaternionf rightRotation, Vector3f scale, Vector3f translation) { + return convertor.GetTransformation(leftRotation, rightRotation, scale, translation); + } + public static String GetPluginName() { return convertor.GetPluginName(); } diff --git a/src/main/java/com/laytonsmith/abstraction/bukkit/BukkitConvertor.java b/src/main/java/com/laytonsmith/abstraction/bukkit/BukkitConvertor.java index 8bae13fe7..edaba908a 100644 --- a/src/main/java/com/laytonsmith/abstraction/bukkit/BukkitConvertor.java +++ b/src/main/java/com/laytonsmith/abstraction/bukkit/BukkitConvertor.java @@ -64,6 +64,7 @@ import com.laytonsmith.abstraction.bukkit.entities.BukkitMCSizedFireball; import com.laytonsmith.abstraction.bukkit.entities.BukkitMCTameable; import com.laytonsmith.abstraction.bukkit.entities.BukkitMCItemProjectile; +import com.laytonsmith.abstraction.bukkit.entities.BukkitMCTransformation; import com.laytonsmith.abstraction.bukkit.entities.BukkitMCVehicle; import com.laytonsmith.abstraction.bukkit.events.BukkitAbstractEventMixin; import com.laytonsmith.abstraction.bukkit.events.drivers.BukkitBlockListener; @@ -74,6 +75,7 @@ import com.laytonsmith.abstraction.bukkit.events.drivers.BukkitVehicleListener; import com.laytonsmith.abstraction.bukkit.events.drivers.BukkitWeatherListener; import com.laytonsmith.abstraction.bukkit.events.drivers.BukkitWorldListener; +import com.laytonsmith.abstraction.entities.MCTransformation; import com.laytonsmith.abstraction.enums.MCAttribute; import com.laytonsmith.abstraction.enums.MCDyeColor; import com.laytonsmith.abstraction.enums.MCEquipmentSlot; @@ -195,6 +197,9 @@ import java.util.concurrent.ExecutionException; import java.util.logging.Level; import org.bukkit.command.RemoteConsoleCommandSender; +import org.bukkit.util.Transformation; +import org.joml.Quaternionf; +import org.joml.Vector3f; @convert(type = Implementation.Type.BUKKIT) public class BukkitConvertor extends AbstractConvertor { @@ -891,4 +896,9 @@ public String GetUser(Environment env) { public MCNamespacedKey GetNamespacedKey(String key) { return new BukkitMCNamespacedKey(NamespacedKey.fromString(key, CommandHelperPlugin.self)); } + + @Override + public MCTransformation GetTransformation(Quaternionf leftRotation, Quaternionf rightRotation, Vector3f scale, Vector3f translation) { + return new BukkitMCTransformation(new Transformation(translation, leftRotation, scale, rightRotation)); + } } diff --git a/src/main/java/com/laytonsmith/abstraction/bukkit/entities/BukkitMCDisplay.java b/src/main/java/com/laytonsmith/abstraction/bukkit/entities/BukkitMCDisplay.java index 8e759ec43..58e0a42d1 100644 --- a/src/main/java/com/laytonsmith/abstraction/bukkit/entities/BukkitMCDisplay.java +++ b/src/main/java/com/laytonsmith/abstraction/bukkit/entities/BukkitMCDisplay.java @@ -3,9 +3,11 @@ import com.laytonsmith.abstraction.MCColor; import com.laytonsmith.abstraction.bukkit.BukkitMCColor; import com.laytonsmith.abstraction.entities.MCDisplay; +import com.laytonsmith.abstraction.entities.MCTransformation; import org.bukkit.Color; import org.bukkit.entity.Display; import org.bukkit.entity.Entity; +import org.joml.Matrix4f; public class BukkitMCDisplay extends BukkitMCEntity implements MCDisplay { @@ -141,4 +143,24 @@ public float getViewRange() { public void setViewRange(float range) { this.d.setViewRange(range); } + + @Override + public MCTransformation getTransformation() { + return new BukkitMCTransformation(this.d.getTransformation()); + } + + @Override + public void setTransformation(MCTransformation transformation) { + this.d.setTransformation(((BukkitMCTransformation) transformation).transformation); + } + + @Override + public void setTransformationMatrix(float[] mtrxf) { + Matrix4f matrix = new Matrix4f( + mtrxf[0], mtrxf[1], mtrxf[2], mtrxf[3], + mtrxf[4], mtrxf[5], mtrxf[6], mtrxf[7], + mtrxf[8], mtrxf[9], mtrxf[10], mtrxf[11], + mtrxf[12], mtrxf[13], mtrxf[14], mtrxf[15]); + this.d.setTransformationMatrix(matrix); + } } diff --git a/src/main/java/com/laytonsmith/abstraction/bukkit/entities/BukkitMCTransformation.java b/src/main/java/com/laytonsmith/abstraction/bukkit/entities/BukkitMCTransformation.java new file mode 100644 index 000000000..0fabfd0ad --- /dev/null +++ b/src/main/java/com/laytonsmith/abstraction/bukkit/entities/BukkitMCTransformation.java @@ -0,0 +1,38 @@ +package com.laytonsmith.abstraction.bukkit.entities; + +import com.laytonsmith.abstraction.entities.MCTransformation; +import org.bukkit.util.Transformation; +import org.joml.Quaternionf; +import org.joml.Vector3f; + +/** + * + */ +public class BukkitMCTransformation implements MCTransformation { + + Transformation transformation; + + public BukkitMCTransformation(Transformation transformation) { + this.transformation = transformation; + } + + @Override + public Vector3f getTranslation() { + return transformation.getTranslation(); + } + + @Override + public Quaternionf getLeftRotation() { + return transformation.getLeftRotation(); + } + + @Override + public Vector3f getScale() { + return transformation.getScale(); + } + + @Override + public Quaternionf getRightRotation() { + return transformation.getRightRotation(); + } +} diff --git a/src/main/java/com/laytonsmith/abstraction/entities/MCDisplay.java b/src/main/java/com/laytonsmith/abstraction/entities/MCDisplay.java index 8971691f8..b9e56431a 100644 --- a/src/main/java/com/laytonsmith/abstraction/entities/MCDisplay.java +++ b/src/main/java/com/laytonsmith/abstraction/entities/MCDisplay.java @@ -57,6 +57,12 @@ public interface MCDisplay extends MCEntity { void setViewRange(float range); + public MCTransformation getTransformation(); + + public void setTransformation(MCTransformation transformation); + + public void setTransformationMatrix(float[] mtrxf); + enum Billboard { CENTER, FIXED, diff --git a/src/main/java/com/laytonsmith/abstraction/entities/MCTransformation.java b/src/main/java/com/laytonsmith/abstraction/entities/MCTransformation.java new file mode 100644 index 000000000..f10274880 --- /dev/null +++ b/src/main/java/com/laytonsmith/abstraction/entities/MCTransformation.java @@ -0,0 +1,20 @@ +package com.laytonsmith.abstraction.entities; + +import org.joml.Quaternionf; +import org.joml.Vector3f; + +/** + * + * @author Cailin + */ +public interface MCTransformation { + + public Vector3f getTranslation(); + + public Quaternionf getLeftRotation(); + + public Vector3f getScale(); + + public Quaternionf getRightRotation(); + +} diff --git a/src/main/java/com/laytonsmith/abstraction/enums/MCVersion.java b/src/main/java/com/laytonsmith/abstraction/enums/MCVersion.java index adf833398..1b7e16299 100644 --- a/src/main/java/com/laytonsmith/abstraction/enums/MCVersion.java +++ b/src/main/java/com/laytonsmith/abstraction/enums/MCVersion.java @@ -63,10 +63,12 @@ public enum MCVersion implements Version { MC1_19_1, MC1_19_2, MC1_19_3, + MC1_19_4, MC1_19_X, MC1_20, MC1_20_1, MC1_20_2, + MC1_20_4, MC1_20_X, MC1_X, MC2_X, diff --git a/src/main/java/com/laytonsmith/core/constructs/CArray.java b/src/main/java/com/laytonsmith/core/constructs/CArray.java index 512863a7a..50a670803 100644 --- a/src/main/java/com/laytonsmith/core/constructs/CArray.java +++ b/src/main/java/com/laytonsmith/core/constructs/CArray.java @@ -392,6 +392,10 @@ public final void set(String index, String value) { set(index, value, Target.UNKNOWN); } + public final void set(String index, float value) { + set(index, new CDouble(value, Target.UNKNOWN), Target.UNKNOWN); + } + @Override public Mixed get(Mixed index, Target t) { if(!associativeMode) { diff --git a/src/main/java/com/laytonsmith/core/functions/EntityManagement.java b/src/main/java/com/laytonsmith/core/functions/EntityManagement.java index 7fe586ce0..896b2c007 100644 --- a/src/main/java/com/laytonsmith/core/functions/EntityManagement.java +++ b/src/main/java/com/laytonsmith/core/functions/EntityManagement.java @@ -87,6 +87,7 @@ import com.laytonsmith.abstraction.entities.MCTNT; import com.laytonsmith.abstraction.entities.MCTextDisplay; import com.laytonsmith.abstraction.entities.MCThrownPotion; +import com.laytonsmith.abstraction.entities.MCTransformation; import com.laytonsmith.abstraction.entities.MCTrident; import com.laytonsmith.abstraction.entities.MCTropicalFish; import com.laytonsmith.abstraction.entities.MCVex; @@ -163,6 +164,8 @@ import java.util.logging.Level; import java.util.logging.Logger; import java.util.stream.Collectors; +import org.joml.Quaternionf; +import org.joml.Vector3f; public class EntityManagement { @@ -4996,32 +4999,37 @@ public String docs() { + " Array keys are: 'billboard', 'brightness', 'glowcolor', 'height', 'width'," + " 'viewrange', 'shadowradius', 'shadowstrength', and 'teleportduration'. ---- " + " The following values are common to all display entity types. Data about specific display entity" - + " types (block, text, and item display entities) can be found in {{function|entity_spec}}." + + " types (block, text, and item display entities) can be found in {{function|entity_spec}}.\n" + " * '''billboard''' (string) : Controls which axes the rendered entity rotates around the entity" + " location when the viewing player's position or facing changes. FIXED (default) will not rotate." - + " HORIZONTAL or VERTICAL rotate on their respective axes. CENTER rotates on both axes." + + " HORIZONTAL or VERTICAL rotate on their respective axes. CENTER rotates on both axes.\n" + " * '''brightness''' (array) : Controls the brightness when rendering the display entity." + " A null value (default) will render the entity based on the environment." + " An array with int values for the keys '''\"block\"''' and '''\"sky\"''' simulate the rendering" + " brightness from those respective light sources. Each must be from 0 - 15." - + " Optionally a single int can be provided and will be used for both sky and block sources." + + " Optionally a single int can be provided and will be used for both sky and block sources.\n" + " * '''glowcolor''' (array) : An RGB array for the entity glow color. If null (default), the" - + " entity will use its scoreboard team color, if it has one." + + " entity will use its scoreboard team color, if it has one.\n" + " * '''height''' (double) : The maximum height of the entity's bounding box. (default: 0.0)" + " Spans vertically from the entity's y location to (y+height), and is used for culling." + " If the client's field of view does not include this box, the entity will not be rendered." - + " If either width or height is 0.0, culling is disabled." + + " If either width or height is 0.0, culling is disabled.\n" + " * '''width''' (double) : The maximum width of the entity's bounding box. (default: 0.0)" - + " Spans horizontally (width/2) from entity location." + + " Spans horizontally (width/2) from entity location.\n" + " * '''viewrange''' (double) : The relative distance the entity will be viewable." + " The default is 1.0, which is 64 meters multiplied by the player's entity distance scaling." - + " This can also be limited by the world's entity-tracking-range for display entities." + + " This can also be limited by the world's entity-tracking-range for display entities.\n" + " * '''shadowradius''' (double) : The visible radius in meters of the entity's shadow." - + " Effective range is from 0.0 (default) to 64.0." + + " Effective range is from 0.0 (default) to 64.0.\n" + " * '''shadowstrength''' (double) : The opacity of the entity's shadow as a function of distance" - + " to a block below the entity within shadowradius. (default: 1.0)" + + " to a block below the entity within shadowradius. (default: 1.0)\n" + " * '''teleportduration''' (int) : The duration in ticks a teleport is interpolated on the client." - + " Range is strictly from 0 - 59. (default: 0) (MC 1.20.2+)"; + + " Range is strictly from 0 - 59. (default: 0) (MC 1.20.2+)\n" + + " * '''translation''' (array) : An associative array that includes 4 values, leftRotation," + + " rightRotation, scale, and translation. Both leftRotation and rightRotation have x, y, z, and w" + + " values, and scale and translation have x, y, and z values. For leftRotation and rightRotation," + + " these are full width 64 bit doubles, but scale and translation are only 32 bit floats." + + " (MC 1.19.4+)"; } @Override @@ -5055,6 +5063,37 @@ public Mixed exec(Target t, com.laytonsmith.core.environments.Environment enviro if(Static.getServer().getMinecraftVersion().gte(MCVersion.MC1_20_2)) { info.set("teleportduration", new CInt(display.getTeleportDuration(), t), t); } + if(Static.getServer().getMinecraftVersion().gte(MCVersion.MC1_19_4)) { + CArray transformation = new CArray(t, 16); + MCTransformation tr = display.getTransformation(); + Quaternionf leftRotationT = tr.getLeftRotation(); + Quaternionf rightRotationT = tr.getRightRotation(); + Vector3f scaleT = tr.getScale(); + Vector3f translationT = tr.getTranslation(); + CArray leftRotation = new CArray(t, 4); + leftRotation.set("w", leftRotationT.w); + leftRotation.set("x", leftRotationT.x); + leftRotation.set("y", leftRotationT.y); + leftRotation.set("z", leftRotationT.z); + CArray rightRotation = new CArray(t, 4); + rightRotation.set("w", rightRotationT.w); + rightRotation.set("x", rightRotationT.x); + rightRotation.set("y", rightRotationT.y); + rightRotation.set("z", rightRotationT.z); + CArray scale = new CArray(t, 3); + scale.set("x", scaleT.x); + scale.set("y", scaleT.y); + scale.set("z", scaleT.z); + CArray translation = new CArray(t, 3); + translation.set("x", translationT.x); + translation.set("y", translationT.y); + translation.set("z", translationT.z); + transformation.set("leftRotation", leftRotation, t); + transformation.set("rightRotation", rightRotation, t); + transformation.set("scale", scale, t); + transformation.set("translation", translation, t); + info.set("transformation", transformation, t); + } return info; } @@ -5174,6 +5213,33 @@ public Mixed exec(Target t, com.laytonsmith.core.environments.Environment enviro } display.setTeleportDuration(ticks); } + if(info.containsKey("transformation") && Static.getServer().getMinecraftVersion().gte(MCVersion.MC1_19_4)) { + CArray transformation = ArgumentValidation.getArray(info.get("transformation", t), t); + CArray leftRotationC = ArgumentValidation.getArray(transformation.get("leftRotation", t), t); + Quaternionf leftRotation = new Quaternionf( + ArgumentValidation.getDouble(leftRotationC.get("x", t), t), + ArgumentValidation.getDouble(leftRotationC.get("y", t), t), + ArgumentValidation.getDouble(leftRotationC.get("z", t), t), + ArgumentValidation.getDouble(leftRotationC.get("w", t), t)); + CArray rightRotationC = ArgumentValidation.getArray(transformation.get("rightRotation", t), t); + Quaternionf rightRotation = new Quaternionf( + ArgumentValidation.getDouble(rightRotationC.get("x", t), t), + ArgumentValidation.getDouble(rightRotationC.get("y", t), t), + ArgumentValidation.getDouble(rightRotationC.get("z", t), t), + ArgumentValidation.getDouble(rightRotationC.get("w", t), t)); + CArray scaleC = ArgumentValidation.getArray(transformation.get("scale", t), t); + Vector3f scale = new Vector3f( + ArgumentValidation.getDouble32(scaleC.get("x", t), t), + ArgumentValidation.getDouble32(scaleC.get("y", t), t), + ArgumentValidation.getDouble32(scaleC.get("z", t), t)); + CArray translationC = ArgumentValidation.getArray(transformation.get("translation", t), t); + Vector3f translation = new Vector3f( + ArgumentValidation.getDouble32(translationC.get("x", t), t), + ArgumentValidation.getDouble32(translationC.get("y", t), t), + ArgumentValidation.getDouble32(translationC.get("z", t), t)); + MCTransformation tr = StaticLayer.GetTransformation(leftRotation, rightRotation, scale, translation); + display.setTransformation(tr); + } return CVoid.VOID; } diff --git a/src/main/java/com/laytonsmith/tools/Interpreter.java b/src/main/java/com/laytonsmith/tools/Interpreter.java index 74e6d20bc..f27a6a2d7 100644 --- a/src/main/java/com/laytonsmith/tools/Interpreter.java +++ b/src/main/java/com/laytonsmith/tools/Interpreter.java @@ -131,6 +131,9 @@ import static com.laytonsmith.PureUtilities.TermColors.p; import static com.laytonsmith.PureUtilities.TermColors.pl; import static com.laytonsmith.PureUtilities.TermColors.reset; +import com.laytonsmith.abstraction.entities.MCTransformation; +import org.joml.Quaternionf; +import org.joml.Vector3f; /** * This is a command line implementation of the in game interpreter mode. This should only be run while the server is @@ -1297,6 +1300,11 @@ public String GetUser(Environment env) { public MCNamespacedKey GetNamespacedKey(String key) { throw new UnsupportedOperationException("This method is not supported from a shell."); } + + @Override + public MCTransformation GetTransformation(Quaternionf leftRotation, Quaternionf rightRotation, Vector3f scale, Vector3f translation) { + throw new UnsupportedOperationException("This method is not supported from a shell."); + } } } diff --git a/src/test/java/com/laytonsmith/testing/StaticTest.java b/src/test/java/com/laytonsmith/testing/StaticTest.java index 93bd23a41..67643bc94 100644 --- a/src/test/java/com/laytonsmith/testing/StaticTest.java +++ b/src/test/java/com/laytonsmith/testing/StaticTest.java @@ -35,6 +35,7 @@ import com.laytonsmith.abstraction.bukkit.BukkitConvertor; import com.laytonsmith.abstraction.bukkit.BukkitMCLocation; import com.laytonsmith.abstraction.bukkit.BukkitMCWorld; +import com.laytonsmith.abstraction.entities.MCTransformation; import com.laytonsmith.abstraction.enums.MCAttribute; import com.laytonsmith.abstraction.enums.MCDyeColor; import com.laytonsmith.abstraction.enums.MCEquipmentSlot; @@ -99,6 +100,8 @@ import java.util.UUID; import java.util.logging.Level; import java.util.logging.Logger; +import org.joml.Quaternionf; +import org.joml.Vector3f; import static org.junit.Assert.fail; import static org.mockito.Mockito.mock; @@ -894,6 +897,11 @@ public String GetUser(Environment env) { public MCNamespacedKey GetNamespacedKey(String key) { throw new UnsupportedOperationException("Not supported yet."); } + + @Override + public MCTransformation GetTransformation(Quaternionf leftRotation, Quaternionf rightRotation, Vector3f scale, Vector3f translation) { + throw new UnsupportedOperationException("Not supported yet."); + } } public static class FakeServerMixin implements EventMixinInterface {