diff --git a/abstraction/src/main/java/me/gamercoder215/starcosmetics/util/StarAnimator.java b/abstraction/src/main/java/me/gamercoder215/starcosmetics/util/StarAnimator.java new file mode 100644 index 00000000..a94d626c --- /dev/null +++ b/abstraction/src/main/java/me/gamercoder215/starcosmetics/util/StarAnimator.java @@ -0,0 +1,325 @@ +package me.gamercoder215.starcosmetics.util; + +import me.gamercoder215.starcosmetics.api.StarConfig; +import org.bukkit.Location; +import org.bukkit.entity.ArmorStand; +import org.bukkit.util.EulerAngle; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.HashSet; +import java.util.Set; + +/** + * The original thread that the original code belongs to can be found here: + * https://www.spigotmc.org/threads/armor-stand-animator-class.152863/ + * MIT License + + Copyright (c) 2016 Bram Stout + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + * @author Bram + * @author gamer + */ +public final class StarAnimator { + + public static Set animators = new HashSet<>(); + + public static void updateAll() { + animators.forEach(StarAnimator::update); + } + + private ArmorStand armorStand; + private int length; + private Frame[] frames; + private boolean paused = false; + private int currentFrame; + private Location startLocation; + private boolean interpolate = false; + + private void readFrames(InputStream stream) { + BufferedReader br = null; + try { + br = new BufferedReader(new InputStreamReader(stream)); + String line; + Frame currentFrame = null; + while ((line = br.readLine()) != null) { + String[] split = line.split("\\s"); + + if (line.startsWith("length")) { + length = (int) Float.parseFloat(split[1]); + frames = new Frame[length]; + } + else if (line.startsWith("frame")) { + if (currentFrame != null) { + frames[currentFrame.frameID] = currentFrame; + } + int frameID = Integer.parseInt(split[1]); + currentFrame = new Frame(); + currentFrame.frameID = frameID; + } + else if (line.contains("interpolate")) + interpolate = true; + else if (line.contains("Armorstand_Position")) { + currentFrame.x = Float.parseFloat(split[1]); + currentFrame.y = Float.parseFloat(split[2]); + currentFrame.z = Float.parseFloat(split[3]); + currentFrame.r = Float.parseFloat(split[4]); + } + else if (line.contains("Armorstand_Middle")) { + float x = (float) Math.toRadians(Float.parseFloat(split[1])); + float y = (float) Math.toRadians(Float.parseFloat(split[2])); + float z = (float) Math.toRadians(Float.parseFloat(split[3])); + currentFrame.middle = new EulerAngle(x, y, z); + } + else if (line.contains("Armorstand_Right_Leg")) { + float x = (float) Math.toRadians(Float.parseFloat(split[1])); + float y = (float) Math.toRadians(Float.parseFloat(split[2])); + float z = (float) Math.toRadians(Float.parseFloat(split[3])); + currentFrame.rightLeg = new EulerAngle(x, y, z); + } + else if (line.contains("Armorstand_Left_Leg")) { + float x = (float) Math.toRadians(Float.parseFloat(split[1])); + float y = (float) Math.toRadians(Float.parseFloat(split[2])); + float z = (float) Math.toRadians(Float.parseFloat(split[3])); + currentFrame.leftLeg = new EulerAngle(x, y, z); + } + else if (line.contains("Armorstand_Left_Arm")) { + float x = (float) Math.toRadians(Float.parseFloat(split[1])); + float y = (float) Math.toRadians(Float.parseFloat(split[2])); + float z = (float) Math.toRadians(Float.parseFloat(split[3])); + currentFrame.leftArm = new EulerAngle(x, y, z); + } + else if (line.contains("Armorstand_Right_Arm")) { + float x = (float) Math.toRadians(Float.parseFloat(split[1])); + float y = (float) Math.toRadians(Float.parseFloat(split[2])); + float z = (float) Math.toRadians(Float.parseFloat(split[3])); + currentFrame.rightArm = new EulerAngle(x, y, z); + } + else if (line.contains("Armorstand_Head")) { + float x = (float) Math.toRadians(Float.parseFloat(split[1])); + float y = (float) Math.toRadians(Float.parseFloat(split[2])); + float z = (float) Math.toRadians(Float.parseFloat(split[3])); + currentFrame.head = new EulerAngle(x, y, z); + } + } + if (currentFrame != null) { + frames[currentFrame.frameID] = currentFrame; + } + } catch (Exception ex) { + StarConfig.print(ex); + } finally { + if (br != null) { + try { + br.close(); + } catch (Exception ex) { + StarConfig.print(ex); + } + } + } + } + + /** + * Constructor of the animator. Takes in the path to the file with the animation and the armor stand to animate. + * @param armorStand + */ + public StarAnimator(String name, ArmorStand armorStand) { + this.armorStand = armorStand; + startLocation = armorStand.getLocation(); + readFrames(StarConfig.class.getResourceAsStream("/animations/" + name + ".animc")); + + animators.add(this); + } + + /** + * This method removes this instance from the animator instances list. When you don't want to use this instance any more, you can call this method. + */ + public void remove() { + animators.remove(this); + } + + public void pause() { + paused = true; + } + + public void stop() { + currentFrame = 0; + update(); + currentFrame = 0; + paused = true; + } + + public void play() { + paused = false; + } + + public void update() { + if (!paused) { + if (currentFrame >= (length - 1) || currentFrame < 0) + currentFrame = 0; + + Frame f = frames[currentFrame]; + if (interpolate && f == null) + f = interpolate(currentFrame); + + if (f != null) { + Location newLoc = startLocation.clone().add(f.x, f.y, f.z); + newLoc.setYaw(f.r + newLoc.getYaw()); + armorStand.teleport(newLoc); + armorStand.setBodyPose(f.middle); + armorStand.setLeftLegPose(f.leftLeg); + armorStand.setRightLegPose(f.rightLeg); + armorStand.setLeftArmPose(f.leftArm); + armorStand.setRightArmPose(f.rightArm); + armorStand.setHeadPose(f.head); + } + currentFrame++; + } + } + + public int getCurrentFrame() { + return currentFrame; + } + + public void setCurrentFrame(int currentFrame) { + this.currentFrame = currentFrame; + } + + public ArmorStand getArmorStand() { + return armorStand; + } + + public int getLength() { + return length; + } + + public Frame[] getFrames() { + return frames; + } + + public boolean isPaused() { + return paused; + } + + public Location getStartLocation() { + return startLocation; + } + + /** + * Sets the start location. If you want to teleport the armor stand this is the recommended function + * + * @param location + */ + public void setStartLocation(Location location) { + startLocation = location; + } + + public boolean isInterpolated() { + return interpolate; + } + + public void setInterpolated(boolean interpolate) { + this.interpolate = interpolate; + } + + private Frame interpolate(int frameID) { + Frame minFrame = null; + for (int i = frameID; i >= 0; i--) { + if (frames[i] != null) { + minFrame = frames[i]; + break; + } + } + Frame maxFrame = null; + for (int i = frameID; i < frames.length; i++) + if (frames[i] != null) { + maxFrame = frames[i]; + break; + } + + Frame res; + + if (maxFrame == null || minFrame == null) { + if (maxFrame == null && minFrame != null) return minFrame; + if (minFrame == null && maxFrame != null) return maxFrame; + + res = new Frame(); + res.frameID = frameID; + return res; + } + res = new Frame(); + res.frameID = frameID; + + float Dmin = frameID - minFrame.frameID; + float D = maxFrame.frameID - minFrame.frameID; + float D0 = Dmin / D; + + res = minFrame.mult(1 - D0, frameID).add(maxFrame.mult(D0, frameID), frameID); + + return res; + } + + /** + * The frame class. This class holds all the information of one frame. + */ + public static class Frame { + int frameID; + float x, y, z, r; + EulerAngle middle; + EulerAngle rightLeg; + EulerAngle leftLeg; + EulerAngle rightArm; + EulerAngle leftArm; + EulerAngle head; + + public Frame mult(float a, int frameID) { + Frame f = new Frame(); + f.frameID = frameID; + f.x = f.x * a; + f.y = f.y * a; + f.z = f.z * a; + f.r = f.r * a; + f.middle = new EulerAngle(middle.getX() * a, middle.getY() * a, middle.getZ() * a); + f.rightLeg = new EulerAngle(rightLeg.getX() * a, rightLeg.getY() * a, rightLeg.getZ() * a); + f.leftLeg = new EulerAngle(leftLeg.getX() * a, leftLeg.getY() * a, leftLeg.getZ() * a); + f.rightArm = new EulerAngle(rightArm.getX() * a, rightArm.getY() * a, rightArm.getZ() * a); + f.leftArm = new EulerAngle(leftArm.getX() * a, leftArm.getY() * a, leftArm.getZ() * a); + f.head = new EulerAngle(head.getX() * a, head.getY() * a, head.getZ() * a); + return f; + } + + public Frame add(Frame a, int frameID) { + Frame f = new Frame(); + f.frameID = frameID; + f.x = f.x + a.x; + f.y = f.y + a.y; + f.z = f.z + a.z; + f.r = f.r + a.r; + f.middle = new EulerAngle(middle.getX() + a.middle.getX(), middle.getY() + a.middle.getY(), middle.getZ() + a.middle.getZ()); + f.rightLeg = new EulerAngle(rightLeg.getX() + a.rightLeg.getX(), rightLeg.getY() + a.rightLeg.getY(), rightLeg.getZ() + a.rightLeg.getZ()); + f.leftLeg = new EulerAngle(leftLeg.getX() + a.leftLeg.getX(), leftLeg.getY() + a.leftLeg.getY(), leftLeg.getZ() + a.leftLeg.getZ()); + f.rightArm = new EulerAngle(rightArm.getX() + a.rightArm.getX(), rightArm.getY() + a.rightArm.getY(), rightArm.getZ() + a.rightArm.getZ()); + f.leftArm = new EulerAngle(leftArm.getX() + a.leftArm.getX(), leftArm.getY() + a.leftArm.getY(), leftArm.getZ() + a.leftArm.getZ()); + f.head = new EulerAngle(head.getX() + a.head.getX(), head.getY() + a.head.getY(), head.getZ() + a.head.getZ()); + return f; + } + } + +} \ No newline at end of file diff --git a/abstraction/src/main/resources/animations/wave.animc b/abstraction/src/main/resources/animations/wave.animc new file mode 100644 index 00000000..eeed7656 --- /dev/null +++ b/abstraction/src/main/resources/animations/wave.animc @@ -0,0 +1,60 @@ +interpolate +length 30 +frame 1 +Armorstand_Right_Arm 180.00000500895632 -0.0 39.235553819180105 +frame 2 +Armorstand_Right_Arm 180.00000500895632 -0.0 37.08444038159794 +frame 3 +Armorstand_Right_Arm 180.00000500895632 -0.0 33.759999482350565 +frame 4 +Armorstand_Right_Arm 180.00000500895632 -0.0 29.475551589595796 +frame 5 +Armorstand_Right_Arm 180.00000500895632 -0.0 24.444441077153574 +frame 6 +Armorstand_Right_Arm 180.00000500895632 -0.0 18.879998658465492 +frame 7 +Armorstand_Right_Arm 180.00000500895632 -0.0 12.995555900746787 +frame 8 +Armorstand_Right_Arm 180.00000500895632 -0.0 7.004440956118116 +frame 9 +Armorstand_Right_Arm 180.00000500895632 -0.0 1.1199956370784734 +frame 10 +Armorstand_Right_Arm 180.00000500895632 -0.0 -4.444451904251487 +frame 11 +Armorstand_Right_Arm 180.00000500895632 -0.0 -9.475555586504539 +frame 12 +Armorstand_Right_Arm 180.00000500895632 -0.0 -13.760003479259307 +frame 13 +Armorstand_Right_Arm 180.00000500895632 -0.0 -17.084454623790446 +frame 14 +Armorstand_Right_Arm 180.00000500895632 -0.0 -19.23555440099426 +frame 15 +Armorstand_Right_Arm 180.00000500895632 -0.0 -20.000002833280426 +frame 16 +Armorstand_Right_Arm 180.00000500895632 -0.0 -19.235559523636137 +frame 17 +Armorstand_Right_Arm 180.00000500895632 -0.0 -17.084447793601274 +frame 18 +Armorstand_Right_Arm 180.00000500895632 -0.0 -13.760002625485662 +frame 19 +Armorstand_Right_Arm 180.00000500895632 -0.0 -9.475557294051832 +frame 20 +Armorstand_Right_Arm 180.00000500895632 -0.0 -4.444445074062317 +frame 21 +Armorstand_Right_Arm 180.00000500895632 -0.0 1.119998198399412 +frame 22 +Armorstand_Right_Arm 180.00000500895632 -0.0 7.0044401023444705 +frame 23 +Armorstand_Right_Arm 180.00000500895632 -0.0 12.995555046973141 +frame 24 +Armorstand_Right_Arm 180.00000500895632 -0.0 18.880000366012784 +frame 25 +Armorstand_Right_Arm 180.00000500895632 -0.0 24.444447907342745 +frame 26 +Armorstand_Right_Arm 180.00000500895632 -0.0 29.475551589595796 +frame 27 +Armorstand_Right_Arm 180.00000500895632 -0.0 33.759999482350565 +frame 28 +Armorstand_Right_Arm 180.00000500895632 -0.0 37.08445745707087 +frame 29 +Armorstand_Right_Arm 180.00000500895632 -0.0 39.235550404085515