DREAMFIRE Docs ← Back to site
Loading...
Searching...
No Matches
DreamArmorStandAnimator.java
Go to the documentation of this file.
1/*
2 * MIT License
3 *
4 * Copyright (c) 2025 Dreamfire Studio
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in all
14 * copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24package com.dreamfirestudios.dreamcore.DreamArmorStand;
25
26import lombok.Getter;
27import org.bukkit.entity.ArmorStand;
28import org.bukkit.util.EulerAngle;
29
30import java.util.List;
31import java.util.UUID;
32import java.util.concurrent.CopyOnWriteArrayList;
33
43 @Getter
44 private UUID animatorID;
45 @Getter
46 private ArmorStand targetArmorStand;
47 private List<ArmorStandAnimationFrameData> frames = new CopyOnWriteArrayList<>();
48 private int currentFrameIndex = 0;
49 private int currentFrameTick = 0;
50 @Getter
51 private volatile boolean paused = true;
52
53 private DreamArmorStandAnimator() {
54 }
55
66 public boolean displayNextFrame() {
67 if (frames.isEmpty() || targetArmorStand == null) return true;
68 if (paused) return false;
69
70 ArmorStandAnimationFrameData frame = frames.get(currentFrameIndex);
71 double t = (double) currentFrameTick / frame.getDurationTicks();
72 if (t > 1.0) t = 1.0;
73
74 if (frame.getHeadStart() != null && frame.getHeadEnd() != null) {
75 EulerAngle newHead = new EulerAngle(
76 interpolate(frame.getHeadStart().getX(), frame.getHeadEnd().getX(), t),
77 interpolate(frame.getHeadStart().getY(), frame.getHeadEnd().getY(), t),
78 interpolate(frame.getHeadStart().getZ(), frame.getHeadEnd().getZ(), t)
79 );
80 targetArmorStand.setHeadPose(newHead);
81 }
82
83 if (frame.getBodyStart() != null && frame.getBodyEnd() != null) {
84 EulerAngle newBody = new EulerAngle(
85 interpolate(frame.getBodyStart().getX(), frame.getBodyEnd().getX(), t),
86 interpolate(frame.getBodyStart().getY(), frame.getBodyEnd().getY(), t),
87 interpolate(frame.getBodyStart().getZ(), frame.getBodyEnd().getZ(), t)
88 );
89 targetArmorStand.setBodyPose(newBody);
90 }
91
92 if (frame.getLeftArmStart() != null && frame.getLeftArmEnd() != null) {
93 EulerAngle newLeftArm = new EulerAngle(
94 interpolate(frame.getLeftArmStart().getX(), frame.getLeftArmEnd().getX(), t),
95 interpolate(frame.getLeftArmStart().getY(), frame.getLeftArmEnd().getY(), t),
96 interpolate(frame.getLeftArmStart().getZ(), frame.getLeftArmEnd().getZ(), t)
97 );
98 targetArmorStand.setLeftArmPose(newLeftArm);
99 }
100
101 if (frame.getRightArmStart() != null && frame.getRightArmEnd() != null) {
102 EulerAngle newRightArm = new EulerAngle(
103 interpolate(frame.getRightArmStart().getX(), frame.getRightArmEnd().getX(), t),
104 interpolate(frame.getRightArmStart().getY(), frame.getRightArmEnd().getY(), t),
105 interpolate(frame.getRightArmStart().getZ(), frame.getRightArmEnd().getZ(), t)
106 );
107 targetArmorStand.setRightArmPose(newRightArm);
108 }
109
110 if (frame.getLeftLegStart() != null && frame.getLeftLegEnd() != null) {
111 EulerAngle newLeftLeg = new EulerAngle(
112 interpolate(frame.getLeftLegStart().getX(), frame.getLeftLegEnd().getX(), t),
113 interpolate(frame.getLeftLegStart().getY(), frame.getLeftLegEnd().getY(), t),
114 interpolate(frame.getLeftLegStart().getZ(), frame.getLeftLegEnd().getZ(), t)
115 );
116 targetArmorStand.setLeftLegPose(newLeftLeg);
117 }
118
119 if (frame.getRightLegStart() != null && frame.getRightLegEnd() != null) {
120 EulerAngle newRightLeg = new EulerAngle(
121 interpolate(frame.getRightLegStart().getX(), frame.getRightLegEnd().getX(), t),
122 interpolate(frame.getRightLegStart().getY(), frame.getRightLegEnd().getY(), t),
123 interpolate(frame.getRightLegStart().getZ(), frame.getRightLegEnd().getZ(), t)
124 );
125 targetArmorStand.setRightLegPose(newRightLeg);
126 }
127
128 currentFrameTick++;
129 if (currentFrameTick >= frame.getDurationTicks()) {
130 currentFrameIndex = (currentFrameIndex + 1) % frames.size();
131 currentFrameTick = 0;
132 }
133 return false;
134 }
135
136 private double interpolate(double start, double end, double t) {
137 return start + (end - start) * t;
138 }
139
143 public void pause() {
144 if (!paused) paused = true;
145 }
146
150 public void play() {
151 if (paused) paused = false;
152 }
153
157 public void stop() {
158 paused = true;
159 frames.clear();
160 }
161
165 public static class Builder {
166 private UUID animatorID = UUID.randomUUID();
167 private final List<ArmorStandAnimationFrameData> frames = new CopyOnWriteArrayList<>();
168 private ArmorStand targetArmorStand;
169
175 public Builder animatorID(UUID animatorID) {
176 if (animatorID != null) this.animatorID = animatorID;
177 return this;
178 }
179
188 public Builder targetArmorStand(ArmorStand armorStand) {
189 if (armorStand == null) throw new IllegalArgumentException("ArmorStand cannot be null");
190 this.targetArmorStand = armorStand;
191 return this;
192 }
193
200 public Builder addFrame(ArmorStandAnimationFrameData frame, int repeatFrames) {
201 if (frame == null || repeatFrames <= 0) return this;
202 for (int i = 0; i < repeatFrames; i++) {
203 frames.add(frame);
204 }
205 return this;
206 }
207
214 if (frame != null) frames.add(frame);
215 return this;
216 }
217
226 if (targetArmorStand == null)
227 throw new IllegalArgumentException("Target ArmorStand must be set");
228 if (frames.isEmpty())
229 throw new IllegalArgumentException("At least one frame must be added");
231 animator.animatorID = animatorID;
232 animator.targetArmorStand = targetArmorStand;
233 animator.frames = frames;
234 return animator;
235 }
236 }
237}
Represents a single animation frame for an armor stand, defining start and end angles for each body p...
DreamArmorStandAnimator build()
Builds and returns a DreamArmorStandAnimator.
Builder targetArmorStand(ArmorStand armorStand)
Sets the target armor stand to animate.
Builder addFrame(ArmorStandAnimationFrameData frame)
Adds a single frame to the animation.
Builder addFrame(ArmorStandAnimationFrameData frame, int repeatFrames)
Adds a frame to the animation with a specified number of repeats.
Provides functionality to animate an ArmorStand by interpolating between ArmorStandAnimationFrameData...
boolean displayNextFrame()
Displays the next frame on the target armor stand.