From 73d3bed941218731c711c895438af592aa0aad0d Mon Sep 17 00:00:00 2001 From: Ian Tapply Date: Sun, 23 Jun 2024 21:32:38 -0400 Subject: [PATCH] Configuration Sector Cleanup (#46) --- .../net/jeqo/bloons/balloon/BalloonCore.java | 62 +-- .../bloons/balloon/model/BalloonModel.java | 6 +- ...ModelType.java => BalloonSegmentType.java} | 2 +- .../multipart/MultipartBalloonModel.java | 31 +- .../multipart/MultipartBalloonType.java | 364 +++++------------- .../multipart/balloon/MultipartBalloon.java | 113 +++--- .../balloon/MultipartBalloonBuilder.java | 9 +- ...delNode.java => MultipartBalloonNode.java} | 64 ++- ...r.java => MultipartBalloonNodeVector.java} | 32 +- .../bloons/balloon/single/SingleBalloon.java | 191 ++++----- .../balloon/single/SingleBalloonType.java | 54 ++- .../configuration/ConfigConfiguration.java | 10 +- .../MultipartBalloonPlayerJoinListener.java | 2 +- .../MultipartBalloonPlayerListener.java | 4 +- .../resources/balloons/color_pack_example.yml | 2 +- .../resources/balloons/dyeable_example.yml | 2 + src/main/resources/balloons/meg_example.yml | 14 + src/main/resources/config.yml | 2 +- 18 files changed, 440 insertions(+), 524 deletions(-) rename src/main/java/net/jeqo/bloons/balloon/model/{BalloonModelType.java => BalloonSegmentType.java} (92%) rename src/main/java/net/jeqo/bloons/balloon/multipart/nodes/{ModelNode.java => MultipartBalloonNode.java} (85%) rename src/main/java/net/jeqo/bloons/balloon/multipart/nodes/{ModelNodeVector.java => MultipartBalloonNodeVector.java} (71%) create mode 100644 src/main/resources/balloons/meg_example.yml diff --git a/src/main/java/net/jeqo/bloons/balloon/BalloonCore.java b/src/main/java/net/jeqo/bloons/balloon/BalloonCore.java index b4ee9f11..fa640f25 100644 --- a/src/main/java/net/jeqo/bloons/balloon/BalloonCore.java +++ b/src/main/java/net/jeqo/bloons/balloon/BalloonCore.java @@ -16,6 +16,9 @@ */ @Setter @Getter public class BalloonCore { + /** + * The plugin instance that runs the balloon core, type org.bukkit.plugin.java.JavaPlugin + */ private JavaPlugin plugin; /** * Contains all valid and loaded multipart balloon types/configurations @@ -25,18 +28,15 @@ public class BalloonCore { * Contains all valid and loaded single balloon types/configurations */ public ArrayList singleBalloonTypes = new ArrayList<>(); - /** - * Creates a new instance of the balloon core manager with preset registered balloons - * @param plugin The plugin instance, type org.bukkit.plugin.java.JavaPlugin - * @param balloons The balloons to register, type java.util.ArrayList[net.jeqo.bloons.balloon.multipart.MultipartBalloonType] - * @param singleBalloons The single balloons to register, type java.util.ArrayList[net.jeqo.bloons.balloon.single.SingleBalloonType] + * Contains all example balloon files to copy to the plugin's data folder */ - public BalloonCore(JavaPlugin plugin, ArrayList balloons, ArrayList singleBalloons) { - this.setPlugin(plugin); - this.setMultipartBalloonTypes(balloons); - this.setSingleBalloonTypes(singleBalloons); - } + private final String[] exampleBalloons = new String[] { + "color_pack_example.yml", + "dyeable_example.yml", + "meg_example.yml", + "multipart_example.yml" + }; /** * Creates a new empty balloon core instance @@ -74,50 +74,19 @@ public void copyExampleBalloons() { }; // Save all example files in the balloons folder in /resources - for (String example : exampleBalloons) { - File file = new File(Bloons.getInstance().getDataFolder() + File.separator + ConfigConfiguration.BALLOON_CONFIGURATION_FOLDER + example); + for (String example : this.getExampleBalloons()) { + File file = new File(Bloons.getInstance().getDataFolder() + File.separator + ConfigConfiguration.BALLOON_CONFIGURATION_FOLDER + File.separator + example); if (file.exists()) continue; Bloons.getInstance().saveResource(ConfigConfiguration.BALLOON_CONFIGURATION_FOLDER + example, false); } } - /** - * Adds a balloon to the registered balloons list - * @param balloon The balloon to add, type net.jeqo.bloons.balloon.multipart.MultipartBalloonType - */ - public void addMultipartBalloon(MultipartBalloonType balloon) { - this.getMultipartBalloonTypes().add(balloon); - } - - /** - * Removes a balloon from the registered balloons list - * @param balloon The balloon to remove, type net.jeqo.bloons.balloon.multipart.MultipartBalloonType - */ - public void removeMultipartBalloon(MultipartBalloonType balloon) { - this.getMultipartBalloonTypes().remove(balloon); - } - - /** - * Adds a single balloon to the registered balloons list - * @param balloon The single balloon to add, type net.jeqo.bloons.balloon.single.SingleBalloonType - */ - public void addSingleBalloon(SingleBalloonType balloon) { - this.getSingleBalloonTypes().add(balloon); - } - - /** - * Removes a single balloon from the registered balloons list - * @param balloon The single balloon to remove, type net.jeqo.bloons.balloon.single.SingleBalloonType - */ - public void removeSingleBalloon(SingleBalloonType balloon) { - this.getSingleBalloonTypes().remove(balloon); - } - /** * Retrieves a balloon by its ID from the registered balloons list * @param ID The ID of the balloon, type java.lang.String - * @return The balloon with the specified name, type net.jeqo.bloons.balloon.multipart.MultipartBalloonType/null + * @return The balloon with the specified name, type net.jeqo.bloons.balloon.multipart.MultipartBalloonType + * Returns null if no balloon is found by the specified ID */ public MultipartBalloonType getMultipartBalloonByID(String ID) { // Loop over every balloon in the registered balloons list @@ -135,7 +104,8 @@ public MultipartBalloonType getMultipartBalloonByID(String ID) { /** * Retrieves a single balloon by its ID from the registered balloons list * @param ID The ID of the balloon, type java.lang.String - * @return The single balloon with the specified ID, type net.jeqo.bloons.balloon.single.SingleBalloonType/null + * @return The single balloon with the specified ID, type net.jeqo.bloons.balloon.single.SingleBalloonType + * Returns null if no balloon is found by the specified ID */ public SingleBalloonType getSingleBalloonByID(String ID) { // Loop over every single balloon in the registered balloons list diff --git a/src/main/java/net/jeqo/bloons/balloon/model/BalloonModel.java b/src/main/java/net/jeqo/bloons/balloon/model/BalloonModel.java index 6cd94a50..1a572073 100644 --- a/src/main/java/net/jeqo/bloons/balloon/model/BalloonModel.java +++ b/src/main/java/net/jeqo/bloons/balloon/model/BalloonModel.java @@ -12,7 +12,7 @@ * A class to handle the creation of balloon models with custom model data and color metadata */ public class BalloonModel { - private static final String leatherMaterialPrefix = "LEATHER_"; // A constant to define a dyeable material + private static final String LEATHER_MATERIAL_PREFIX = "LEATHER_"; // A constant to define a dyeable material /** * Generates a coloured model with the specified colour and custom model data @@ -23,7 +23,7 @@ public class BalloonModel { */ public static ItemStack createColouredModel(Material material, Color colour, int customModelData) { // Check if the material is dyeable and contains leather attributes - if (!material.name().contains(leatherMaterialPrefix)) { + if (!material.name().contains(LEATHER_MATERIAL_PREFIX)) { Logger.logError("Material " + material.name() + " is not a dyeable material."); return new ItemStack(material); } @@ -52,7 +52,7 @@ public static ItemStack createColouredModel(Material material, Color colour, int */ public static ItemStack createColouredModel(Material material, int colourRed, int colourGreen, int colourBlue, int customModelData) { // Check if the material is dyeable and contains leather attributes - if (!material.name().contains(leatherMaterialPrefix)) { + if (!material.name().contains(LEATHER_MATERIAL_PREFIX)) { Logger.logWarning(String.format(Languages.getMessage("material-not-dyeable"), material)); return new ItemStack(material); } diff --git a/src/main/java/net/jeqo/bloons/balloon/model/BalloonModelType.java b/src/main/java/net/jeqo/bloons/balloon/model/BalloonSegmentType.java similarity index 92% rename from src/main/java/net/jeqo/bloons/balloon/model/BalloonModelType.java rename to src/main/java/net/jeqo/bloons/balloon/model/BalloonSegmentType.java index 25dd9ba7..05ecd3dc 100644 --- a/src/main/java/net/jeqo/bloons/balloon/model/BalloonModelType.java +++ b/src/main/java/net/jeqo/bloons/balloon/model/BalloonSegmentType.java @@ -3,7 +3,7 @@ /** * The type of segment that the model accommodates */ -public enum BalloonModelType { +public enum BalloonSegmentType { /** * This is the head of the balloon, indexed as the last index in the multipart balloon */ diff --git a/src/main/java/net/jeqo/bloons/balloon/multipart/MultipartBalloonModel.java b/src/main/java/net/jeqo/bloons/balloon/multipart/MultipartBalloonModel.java index cd663aef..4717dc45 100644 --- a/src/main/java/net/jeqo/bloons/balloon/multipart/MultipartBalloonModel.java +++ b/src/main/java/net/jeqo/bloons/balloon/multipart/MultipartBalloonModel.java @@ -3,7 +3,7 @@ import lombok.Getter; import lombok.Setter; import net.jeqo.bloons.balloon.model.BalloonModel; -import net.jeqo.bloons.balloon.model.BalloonModelType; +import net.jeqo.bloons.balloon.model.BalloonSegmentType; import net.jeqo.bloons.logger.Logger; import net.jeqo.bloons.colors.Color; import net.jeqo.bloons.message.Languages; @@ -15,22 +15,35 @@ */ @Getter @Setter public class MultipartBalloonModel { - private BalloonModelType modelType; - private String material; - private String color; - private Integer customModelData; + /** + * The type of segment that the model accommodates + * This can either be the head, body, or tail of the balloon + */ + private BalloonSegmentType segmentType; + /** + * The material used to create the model + */ + private String material; // required + /** + * The color of the model + */ + private String color = "#ffffff"; // optional + /** + * The custom model data value stored in the item metadata + */ + private Integer customModelData; // required /** * Creates a new model for a multipart balloon - * @param modelType The type of model (head, body, tail), type net.jeqo.bloons.balloon.model.BalloonModelType + * @param segmentType The type of model (head, body, tail), type net.jeqo.bloons.balloon.model.BalloonModelType * @param material The name of the Bukkit Material used to create the item, type java.lang.String * @param color The color of the model as a hex color code value, type java.lang.String * @param customModelData The custom model data value stored in the item metadata, type int */ - public MultipartBalloonModel(BalloonModelType modelType, String material, String color, int customModelData) { - this.setModelType(modelType); + public MultipartBalloonModel(BalloonSegmentType segmentType, String material, String color, int customModelData) { + this.setSegmentType(segmentType); this.setMaterial(material); - this.setColor(color); + if (!color.equals(this.getColor()) && color != null && !color.isEmpty()) this.setColor(color); this.setCustomModelData(customModelData); } diff --git a/src/main/java/net/jeqo/bloons/balloon/multipart/MultipartBalloonType.java b/src/main/java/net/jeqo/bloons/balloon/multipart/MultipartBalloonType.java index 19af1205..57713fd8 100644 --- a/src/main/java/net/jeqo/bloons/balloon/multipart/MultipartBalloonType.java +++ b/src/main/java/net/jeqo/bloons/balloon/multipart/MultipartBalloonType.java @@ -8,24 +8,85 @@ */ @Getter @Setter public class MultipartBalloonType { + /** + * The unique identifier for the balloon type + */ private String id; + /** + * The permission required to use the balloon + */ private String permission; + /** + * The name of the balloon that is displayed both in chat and in the Bloons menu + */ private String name; + /** + * The lore of the item that is displayed in the GUI + */ private String[] lore; - private int nodeCount; - private double distanceBetweenNodes; - private double leashHeight; - private double headNodeOffset = 0.0; - private double bodyNodeOffset = 0.0; - private double tailNodeOffset = 0.0; - private double maxNodeJointAngle = 35.0; - private double yAxisInterpolation = 0.35; - private double turningSplineInterpolation = 0.35; - private double passiveSineWaveSpeed = 0.05; - private double passiveSineWaveAmplitude = 0.5; - private double passiveNoseSineWaveAmplitude = 0.5; + /** + * The number of nodes, or models, in the balloon + */ + private int nodeCount = 5; // optional + /** + * The distance between each node in the balloon measured in blocks + */ + private double distanceBetweenNodes = 2.0D; // optional + /** + * The height of the leash attached to a player relative from the head of the player in blocks + */ + private double leashHeight = 1.2D; // optional + /** + * The offset of the head node from its 0 position measured in blocks + */ + private double headNodeOffset = 0.0D; // optional + /** + * The offset of the body node from its 0 position measured in blocks + */ + private double bodyNodeOffset = 0.0D; // optional + /** + * The offset of the tail node from its 0 position measured in blocks + */ + private double tailNodeOffset = 0.0D; // optional + /** + * The max angle that a segment/node can rotate to in degrees in both directions + * This number *2 is equal to the total range of motion for each segment + */ + private double maxNodeJointAngle = 35.0D; // optional + /** + * The interpolation of the Y-axis motion of every segment + */ + private double yAxisInterpolation = 0.35D; // optional + /** + * The interpolation of the turning spline to prevent overturning and + * to enhance smoother turning + */ + private double turningSplineInterpolation = 0.35D; // optional + /** + * The speed of the passive sine wave animation. This is the amount of blocks it + * will move every tick due to the runnable running every tick. + */ + private double passiveSineWaveSpeed = 0.05D; // optional + /** + * The amplitude of the passive sine wave animation. This is the maximum amount of + * blocks the balloon will move in the positive and negative direction. + */ + private double passiveSineWaveAmplitude = 0.5D; // optional + /** + * The amplitude of the passive sine wave animation starting at the nose + */ + private double passiveNoseSineWaveAmplitude = 0.5D; // optional + /** + * The model used for the head node + */ private MultipartBalloonModel headModel; + /** + * The model used for the body node + */ private MultipartBalloonModel bodyModel; + /** + * The model used for the tail node + */ private MultipartBalloonModel tailModel; /** @@ -52,265 +113,24 @@ public class MultipartBalloonType { * @param tailModel The model used for the tail node, type net.jeqo.bloons.balloon.multipart.MultipartBalloonModel */ public MultipartBalloonType(String id, String permission, String name, String[] lore, int nodeCount, double distanceBetweenNodes, double leashHeight, double headNodeOffset, double bodyNodeOffset, double tailNodeOffset, double maxNodeJointAngle, double yAxisInterpolation, double turningSplineInterpolation, double passiveSineWaveSpeed, double passiveSineWaveAmplitude, double passiveNoseSineWaveAmplitude, MultipartBalloonModel headModel, MultipartBalloonModel bodyModel, MultipartBalloonModel tailModel) { - this.setId(id); - this.setPermission(permission); - this.setName(name); - this.setLore(lore); - this.setNodeCount(nodeCount); - this.setDistanceBetweenNodes(distanceBetweenNodes); - this.setLeashHeight(leashHeight); - this.setHeadNodeOffset(headNodeOffset); - this.setBodyNodeOffset(bodyNodeOffset); - this.setTailNodeOffset(tailNodeOffset); - this.setMaxNodeJointAngle(maxNodeJointAngle); - this.setYAxisInterpolation(yAxisInterpolation); - this.setTurningSplineInterpolation(turningSplineInterpolation); - this.setPassiveSineWaveSpeed(passiveSineWaveSpeed); - this.setPassiveSineWaveAmplitude(passiveSineWaveAmplitude); - this.setPassiveNoseSineWaveAmplitude(passiveNoseSineWaveAmplitude); - this.setHeadModel(headModel); - this.setBodyModel(bodyModel); - this.setTailModel(tailModel); - } - - /** - * Creates a new multipart balloon type which contains - * the data in the configuration for the balloon - * @param id The ID of the balloon, type java.lang.String - * @param permission The permission required to use the balloon (i.e. blue.jeqo), type java.lang.String - * @param name The name of the balloon, type java.lang.String - * @param lore The lore lines of the balloon in the balloon GUI, type java.lang.String[] - * @param nodeCount The number of nodes, or models, in the balloon, type int - * @param distanceBetweenNodes The distance between each node in the balloon measured as blocks, type double - * @param headNodeOffset The offset of the head node from its 0 position measured as blocks, type double - * @param bodyNodeOffset The offset of the body node from its 0 position measured as blocks, type double - * @param tailNodeOffset The offset of the tail node from its 0 position measured as blocks, type double - * @param maxNodeJointAngle The maximum angle a node can rotate in degrees, type double - * @param yAxisInterpolation The interpolation of the Y-axis, type double - * @param turningSplineInterpolation The interpolation of the turning spline to prevent overturning, type double - * @param passiveSineWaveSpeed The speed of the passive sine wave animation, type double - * @param passiveSineWaveAmplitude The amplitude of the passive sine wave animation, type double - * @param headModel The model used for the head node, type net.jeqo.bloons.balloon.multipart.MultipartBalloonModel - * @param bodyModel The model used for the body node, type net.jeqo.bloons.balloon.multipart.MultipartBalloonModel - * @param tailModel The model used for the tail node, type net.jeqo.bloons.balloon.multipart.MultipartBalloonModel - */ - public MultipartBalloonType(String id, String permission, String name, String[] lore, int nodeCount, double distanceBetweenNodes, double headNodeOffset, double bodyNodeOffset, double tailNodeOffset, double maxNodeJointAngle, double yAxisInterpolation, double turningSplineInterpolation, double passiveSineWaveSpeed, double passiveSineWaveAmplitude, MultipartBalloonModel headModel, MultipartBalloonModel bodyModel, MultipartBalloonModel tailModel) { - this.setId(id); - this.setPermission(permission); - this.setName(name); - this.setLore(lore); - this.setNodeCount(nodeCount); - this.setDistanceBetweenNodes(distanceBetweenNodes); - this.setHeadNodeOffset(headNodeOffset); - this.setBodyNodeOffset(bodyNodeOffset); - this.setTailNodeOffset(tailNodeOffset); - this.setMaxNodeJointAngle(maxNodeJointAngle); - this.setYAxisInterpolation(yAxisInterpolation); - this.setTurningSplineInterpolation(turningSplineInterpolation); - this.setPassiveSineWaveSpeed(passiveSineWaveSpeed); - this.setPassiveSineWaveAmplitude(passiveSineWaveAmplitude); - this.setHeadModel(headModel); - this.setBodyModel(bodyModel); - this.setTailModel(tailModel); - } - - /** - * Creates a new multipart balloon type which contains - * the data in the configuration for the balloon - * @param id The ID of the balloon, type java.lang.String - * @param permission The permission required to use the balloon (i.e. blue.jeqo), type java.lang.String - * @param name The name of the balloon, type java.lang.String - * @param lore The lore lines of the balloon in the balloon GUI, type java.lang.String[] - * @param nodeCount The number of nodes, or models, in the balloon, type int - * @param distanceBetweenNodes The distance between each node in the balloon measured as blocks, type double - * @param headNodeOffset The offset of the head node from its 0 position measured as blocks, type double - * @param bodyNodeOffset The offset of the body node from its 0 position measured as blocks, type double - * @param tailNodeOffset The offset of the tail node from its 0 position measured as blocks, type double - * @param maxNodeJointAngle The maximum angle a node can rotate in degrees, type double - * @param yAxisInterpolation The interpolation of the Y-axis, type double - * @param turningSplineInterpolation The interpolation of the turning spline to prevent overturning, type double - * @param passiveSineWaveSpeed The speed of the passive sine wave animation, type double - * @param headModel The model used for the head node, type net.jeqo.bloons.balloon.multipart.MultipartBalloonModel - * @param bodyModel The model used for the body node, type net.jeqo.bloons.balloon.multipart.MultipartBalloonModel - * @param tailModel The model used for the tail node, type net.jeqo.bloons.balloon.multipart.MultipartBalloonModel - */ - public MultipartBalloonType(String id, String permission, String name, String[] lore, int nodeCount, double distanceBetweenNodes, double headNodeOffset, double bodyNodeOffset, double tailNodeOffset, double maxNodeJointAngle, double yAxisInterpolation, double turningSplineInterpolation, double passiveSineWaveSpeed, MultipartBalloonModel headModel, MultipartBalloonModel bodyModel, MultipartBalloonModel tailModel) { - this.setId(id); - this.setPermission(permission); - this.setName(name); - this.setLore(lore); - this.setNodeCount(nodeCount); - this.setDistanceBetweenNodes(distanceBetweenNodes); - this.setHeadNodeOffset(headNodeOffset); - this.setBodyNodeOffset(bodyNodeOffset); - this.setTailNodeOffset(tailNodeOffset); - this.setMaxNodeJointAngle(maxNodeJointAngle); - this.setYAxisInterpolation(yAxisInterpolation); - this.setTurningSplineInterpolation(turningSplineInterpolation); - this.setPassiveSineWaveSpeed(passiveSineWaveSpeed); - this.setHeadModel(headModel); - this.setBodyModel(bodyModel); - this.setTailModel(tailModel); - } - - /** - * Creates a new multipart balloon type which contains - * the data in the configuration for the balloon - * @param id The ID of the balloon, type java.lang.String - * @param permission The permission required to use the balloon (i.e. blue.jeqo), type java.lang.String - * @param name The name of the balloon, type java.lang.String - * @param lore The lore lines of the balloon in the balloon GUI, type java.lang.String[] - * @param nodeCount The number of nodes, or models, in the balloon, type int - * @param distanceBetweenNodes The distance between each node in the balloon measured as blocks, type double - * @param headNodeOffset The offset of the head node from its 0 position measured as blocks, type double - * @param bodyNodeOffset The offset of the body node from its 0 position measured as blocks, type double - * @param tailNodeOffset The offset of the tail node from its 0 position measured as blocks, type double - * @param maxNodeJointAngle The maximum angle a node can rotate in degrees, type double - * @param yAxisInterpolation The interpolation of the Y-axis, type double - * @param turningSplineInterpolation The interpolation of the turning spline to prevent overturning, type double - * @param headModel The model used for the head node, type net.jeqo.bloons.balloon.multipart.MultipartBalloonModel - * @param bodyModel The model used for the body node, type net.jeqo.bloons.balloon.multipart.MultipartBalloonModel - * @param tailModel The model used for the tail node, type net.jeqo.bloons.balloon.multipart.MultipartBalloonModel - */ - public MultipartBalloonType(String id, String permission, String name, String[] lore, int nodeCount, double distanceBetweenNodes, double headNodeOffset, double bodyNodeOffset, double tailNodeOffset, double maxNodeJointAngle, double yAxisInterpolation, double turningSplineInterpolation, MultipartBalloonModel headModel, MultipartBalloonModel bodyModel, MultipartBalloonModel tailModel) { - this.setId(id); - this.setPermission(permission); - this.setName(name); - this.setLore(lore); - this.setNodeCount(nodeCount); - this.setDistanceBetweenNodes(distanceBetweenNodes); - this.setHeadNodeOffset(headNodeOffset); - this.setBodyNodeOffset(bodyNodeOffset); - this.setTailNodeOffset(tailNodeOffset); - this.setMaxNodeJointAngle(maxNodeJointAngle); - this.setYAxisInterpolation(yAxisInterpolation); - this.setTurningSplineInterpolation(turningSplineInterpolation); - this.setHeadModel(headModel); - this.setBodyModel(bodyModel); - this.setTailModel(tailModel); - } - - /** - * Creates a new multipart balloon type which contains - * the data in the configuration for the balloon - * @param id The ID of the balloon, type java.lang.String - * @param permission The permission required to use the balloon (i.e. blue.jeqo), type java.lang.String - * @param name The name of the balloon, type java.lang.String - * @param lore The lore lines of the balloon in the balloon GUI, type java.lang.String[] - * @param nodeCount The number of nodes, or models, in the balloon, type int - * @param distanceBetweenNodes The distance between each node in the balloon measured as blocks, type double - * @param headModel The model used for the head node, type net.jeqo.bloons.balloon.multipart.MultipartBalloonModel - * @param bodyModel The model used for the body node, type net.jeqo.bloons.balloon.multipart.MultipartBalloonModel - * @param tailModel The model used for the tail node, type net.jeqo.bloons.balloon.multipart.MultipartBalloonModel - */ - public MultipartBalloonType(String id, String permission, String name, String[] lore, int nodeCount, double distanceBetweenNodes, MultipartBalloonModel headModel, MultipartBalloonModel bodyModel, MultipartBalloonModel tailModel) { - this.setId(id); - this.setPermission(permission); - this.setName(name); - this.setLore(lore); - this.setNodeCount(nodeCount); - this.setDistanceBetweenNodes(distanceBetweenNodes); - this.setHeadModel(headModel); - this.setBodyModel(bodyModel); - this.setTailModel(tailModel); - } - - /** - * Creates a new multipart balloon type which contains - * the data in the configuration for the balloon - * @param id The ID of the balloon, type java.lang.String - * @param permission The permission required to use the balloon (i.e. blue.jeqo), type java.lang.String - * @param name The name of the balloon, type java.lang.String - * @param lore The lore lines of the balloon in the balloon GUI, type java.lang.String[] - * @param nodeCount The number of nodes, or models, in the balloon, type int - * @param distanceBetweenNodes The distance between each node in the balloon measured as blocks, type double - * @param headNodeOffset The offset of the head node from its 0 position measured as blocks, type double - * @param bodyNodeOffset The offset of the body node from its 0 position measured as blocks, type double - * @param tailNodeOffset The offset of the tail node from its 0 position measured as blocks, type double - * @param headModel The model used for the head node, type net.jeqo.bloons.balloon.multipart.MultipartBalloonModel - * @param bodyModel The model used for the body node, type net.jeqo.bloons.balloon.multipart.MultipartBalloonModel - * @param tailModel The model used for the tail node, type net.jeqo.bloons.balloon.multipart.MultipartBalloonModel - */ - public MultipartBalloonType(String id, String permission, String name, String[] lore, int nodeCount, double distanceBetweenNodes, double headNodeOffset, double bodyNodeOffset, double tailNodeOffset, MultipartBalloonModel headModel, MultipartBalloonModel bodyModel, MultipartBalloonModel tailModel) { - this.setId(id); - this.setPermission(permission); - this.setName(name); - this.setLore(lore); - this.setNodeCount(nodeCount); - this.setDistanceBetweenNodes(distanceBetweenNodes); - this.setHeadNodeOffset(headNodeOffset); - this.setBodyNodeOffset(bodyNodeOffset); - this.setTailNodeOffset(tailNodeOffset); - this.setHeadModel(headModel); - this.setBodyModel(bodyModel); - this.setTailModel(tailModel); - } - - /** - * Creates a new multipart balloon type which contains - * the data in the configuration for the balloon - * @param id The ID of the balloon, type java.lang.String - * @param permission The permission required to use the balloon (i.e. blue.jeqo), type java.lang.String - * @param name The name of the balloon, type java.lang.String - * @param lore The lore lines of the balloon in the balloon GUI, type java.lang.String[] - * @param nodeCount The number of nodes, or models, in the balloon, type int - * @param distanceBetweenNodes The distance between each node in the balloon measured as blocks, type double - * @param headNodeOffset The offset of the head node from its 0 position measured as blocks, type double - * @param bodyNodeOffset The offset of the body node from its 0 position measured as blocks, type double - * @param tailNodeOffset The offset of the tail node from its 0 position measured as blocks, type double - * @param maxNodeJointAngle The maximum angle a node can rotate in degrees, type double - * @param headModel The model used for the head node, type net.jeqo.bloons.balloon.multipart.MultipartBalloonModel - * @param bodyModel The model used for the body node, type net.jeqo.bloons.balloon.multipart.MultipartBalloonModel - * @param tailModel The model used for the tail node, type net.jeqo.bloons.balloon.multipart.MultipartBalloonModel - */ - public MultipartBalloonType(String id, String permission, String name, String[] lore, int nodeCount, double distanceBetweenNodes, double headNodeOffset, double bodyNodeOffset, double tailNodeOffset, double maxNodeJointAngle, MultipartBalloonModel headModel, MultipartBalloonModel bodyModel, MultipartBalloonModel tailModel) { - this.setId(id); - this.setPermission(permission); - this.setName(name); - this.setLore(lore); - this.setNodeCount(nodeCount); - this.setDistanceBetweenNodes(distanceBetweenNodes); - this.setHeadNodeOffset(headNodeOffset); - this.setBodyNodeOffset(bodyNodeOffset); - this.setTailNodeOffset(tailNodeOffset); - this.setMaxNodeJointAngle(maxNodeJointAngle); - this.setHeadModel(headModel); - this.setBodyModel(bodyModel); - this.setTailModel(tailModel); - } - - /** - * Creates a new multipart balloon type which contains - * the data in the configuration for the balloon - * @param id The ID of the balloon, type java.lang.String - * @param permission The permission required to use the balloon (i.e. blue.jeqo), type java.lang.String - * @param name The name of the balloon, type java.lang.String - * @param lore The lore lines of the balloon in the balloon GUI, type java.lang.String[] - * @param nodeCount The number of nodes, or models, in the balloon, type int - * @param distanceBetweenNodes The distance between each node in the balloon measured as blocks, type double - * @param headNodeOffset The offset of the head node from its 0 position measured as blocks, type double - * @param bodyNodeOffset The offset of the body node from its 0 position measured as blocks, type double - * @param tailNodeOffset The offset of the tail node from its 0 position measured as blocks, type double - * @param maxNodeJointAngle The maximum angle a node can rotate in degrees, type double - * @param yAxisInterpolation The interpolation of the Y-axis, type double - * @param headModel The model used for the head node, type net.jeqo.bloons.balloon.multipart.MultipartBalloonModel - * @param bodyModel The model used for the body node, type net.jeqo.bloons.balloon.multipart.MultipartBalloonModel - * @param tailModel The model used for the tail node, type net.jeqo.bloons.balloon.multipart.MultipartBalloonModel - */ - public MultipartBalloonType(String id, String permission, String name, String[] lore, int nodeCount, double distanceBetweenNodes, double headNodeOffset, double bodyNodeOffset, double tailNodeOffset, double maxNodeJointAngle, double yAxisInterpolation, MultipartBalloonModel headModel, MultipartBalloonModel bodyModel, MultipartBalloonModel tailModel) { - this.setId(id); - this.setPermission(permission); - this.setName(name); - this.setLore(lore); - this.setNodeCount(nodeCount); - this.setDistanceBetweenNodes(distanceBetweenNodes); - this.setHeadNodeOffset(headNodeOffset); - this.setBodyNodeOffset(bodyNodeOffset); - this.setTailNodeOffset(tailNodeOffset); - this.setMaxNodeJointAngle(maxNodeJointAngle); - this.setYAxisInterpolation(yAxisInterpolation); - this.setHeadModel(headModel); - this.setBodyModel(bodyModel); - this.setTailModel(tailModel); + this.setId(id); // required + this.setPermission(permission); // required + this.setName(name); // required + this.setLore(lore); // required + if (nodeCount > 0) this.setNodeCount(nodeCount); // 5 by default, optional + if (distanceBetweenNodes > 0.0D) this.setDistanceBetweenNodes(distanceBetweenNodes); // 2.0 by default, optional + if (leashHeight > 0.0D) this.setLeashHeight(leashHeight); // 1.2 by default, optional + this.setHeadNodeOffset(headNodeOffset); // 0 by default, optional + this.setBodyNodeOffset(bodyNodeOffset); // 0 by default, optional + this.setTailNodeOffset(tailNodeOffset); // 0 by default, optional + if (maxNodeJointAngle > 0.0D) this.setMaxNodeJointAngle(maxNodeJointAngle); // 35.0 by default, optional + if (yAxisInterpolation > 0.0D) this.setYAxisInterpolation(yAxisInterpolation); // 0.35 by default, optional + if (turningSplineInterpolation > 0.0D) this.setTurningSplineInterpolation(turningSplineInterpolation); // 0.35 by default, optional + if (passiveSineWaveSpeed > 0.0D) this.setPassiveSineWaveSpeed(passiveSineWaveSpeed); // 0.05 by default, optional + if (passiveSineWaveAmplitude > 0.0D) this.setPassiveSineWaveAmplitude(passiveSineWaveAmplitude); // 0.5 by default, optional + if (passiveNoseSineWaveAmplitude > 0.0D) this.setPassiveNoseSineWaveAmplitude(passiveNoseSineWaveAmplitude); // 0.5 by default, optional + this.setHeadModel(headModel); // required + this.setBodyModel(bodyModel); // required + this.setTailModel(tailModel); // required } } diff --git a/src/main/java/net/jeqo/bloons/balloon/multipart/balloon/MultipartBalloon.java b/src/main/java/net/jeqo/bloons/balloon/multipart/balloon/MultipartBalloon.java index 9db77875..af4077dc 100644 --- a/src/main/java/net/jeqo/bloons/balloon/multipart/balloon/MultipartBalloon.java +++ b/src/main/java/net/jeqo/bloons/balloon/multipart/balloon/MultipartBalloon.java @@ -4,7 +4,7 @@ import lombok.Setter; import net.jeqo.bloons.Bloons; import net.jeqo.bloons.balloon.multipart.MultipartBalloonType; -import net.jeqo.bloons.balloon.multipart.nodes.ModelNode; +import net.jeqo.bloons.balloon.multipart.nodes.MultipartBalloonNode; import net.jeqo.bloons.configuration.BalloonConfiguration; import net.kyori.adventure.text.Component; import org.bukkit.Location; @@ -22,37 +22,52 @@ */ @Getter public class MultipartBalloon { + /** + * The type of balloon that the multipart balloon is creating + */ @Setter - private MultipartBalloonType balloonType; + private MultipartBalloonType type; + /** + * The owner of the balloon + */ @Setter - private Player balloonOwner; - + private Player owner; + /** + * The chicken that is used to attach the player via a lead to the balloon + */ @Setter - private Chicken balloonChicken; - + private Chicken chicken; + /** + * The tentacle node that is the front of the balloon + */ @Setter - private ModelNode tentacle; + private MultipartBalloonNode tentacle; + /** + * The runnable that is used to constantly update the balloons' position + */ @Setter private BukkitRunnable runnable; - - private final List modelNodes = new ArrayList<>(); + /** + * The list of model nodes that are used to create the balloon + */ + private final List multipartBalloonNodes = new ArrayList<>(); /** * Initializes the balloons functionality */ public void initialize() { // Things that only need to be set up once and not looped over - ModelNode current = new ModelNode((float) this.getBalloonOwner().getLocation().getX(), (float) this.getBalloonOwner().getLocation().getY(), (float) this.getBalloonOwner().getLocation().getZ(), - (float) ((float) this.getBalloonType().getDistanceBetweenNodes() + this.getBalloonType().getTailNodeOffset()), 0, getBalloonType(), this.getBalloonOwner(), - this.getBalloonType().getMaxNodeJointAngle(), this.getBalloonType().getYAxisInterpolation(), this.getBalloonType().getTurningSplineInterpolation()); + MultipartBalloonNode current = new MultipartBalloonNode((float) this.getOwner().getLocation().getX(), (float) this.getOwner().getLocation().getY(), (float) this.getOwner().getLocation().getZ(), + (float) ((float) this.getType().getDistanceBetweenNodes() + this.getType().getTailNodeOffset()), 0, getType(), this.getOwner(), + this.getType().getMaxNodeJointAngle(), this.getType().getYAxisInterpolation(), this.getType().getTurningSplineInterpolation()); // Add the current node to the list of model nodes - this.getModelNodes().add(current); + this.getMultipartBalloonNodes().add(current); // Create a new node for each node in the balloon type - for (int i = 1; i < this.getBalloonType().getNodeCount(); i++) { - ModelNode next = getModelNode(i, current); - this.getModelNodes().add(next); + for (int i = 1; i < this.getType().getNodeCount(); i++) { + MultipartBalloonNode next = getModelNode(i, current); + this.getMultipartBalloonNodes().add(next); current.child = next; current = next; } @@ -69,18 +84,18 @@ public void initialize() { */ public void initializeBalloonLead() { // Location to spawn the lead holder at - Location location = new Location(this.getBalloonOwner().getWorld(), this.getBalloonOwner().getLocation().getX(), this.getBalloonOwner().getLocation().getY() + 2, this.getBalloonOwner().getLocation().getZ()); + Location location = new Location(this.getOwner().getWorld(), this.getOwner().getLocation().getX(), this.getOwner().getLocation().getY() + 2, this.getOwner().getLocation().getZ()); // Configure the chicken entity properties - this.setBalloonChicken(this.getBalloonOwner().getWorld().spawn(location, Chicken.class)); - this.getBalloonChicken().setInvulnerable(true); - this.getBalloonChicken().setInvisible(true); - this.getBalloonChicken().setBaby(); - this.getBalloonChicken().setSilent(true); - this.getBalloonChicken().setAgeLock(true); - this.getBalloonChicken().setAware(false); - this.getBalloonChicken().setCollidable(false); - this.getBalloonChicken().customName(Component.text(BalloonConfiguration.BALLOON_CHICKEN_ID)); + this.setChicken(this.getOwner().getWorld().spawn(location, Chicken.class)); + this.getChicken().setInvulnerable(true); + this.getChicken().setInvisible(true); + this.getChicken().setBaby(); + this.getChicken().setSilent(true); + this.getChicken().setAgeLock(true); + this.getChicken().setAware(false); + this.getChicken().setCollidable(false); + this.getChicken().customName(Component.text(BalloonConfiguration.BALLOON_CHICKEN_ID)); } /** @@ -89,20 +104,20 @@ public void initializeBalloonLead() { * @param current The current node, type net.jeqo.bloons.balloon.multipart.nodes.ModelNode * @return The next model node, type net.jeqo.bloons.balloon.multipart.nodes.ModelNode */ - private @NotNull ModelNode getModelNode(int index, ModelNode current) { - ModelNode next; + private @NotNull MultipartBalloonNode getModelNode(int index, MultipartBalloonNode current) { + MultipartBalloonNode next; // If the index is the last node, create a head node - if (index == this.getBalloonType().getNodeCount() - 1) { - next = new ModelNode(current, (float) ((float) this.getBalloonType().getDistanceBetweenNodes() + this.getBalloonType().getHeadNodeOffset()), - index, getBalloonType(), this.getBalloonOwner(), this.getBalloonType().getMaxNodeJointAngle(), this.getBalloonType().getYAxisInterpolation(), - this.getBalloonType().getTurningSplineInterpolation()); + if (index == this.getType().getNodeCount() - 1) { + next = new MultipartBalloonNode(current, (float) ((float) this.getType().getDistanceBetweenNodes() + this.getType().getHeadNodeOffset()), + index, getType(), this.getOwner(), this.getType().getMaxNodeJointAngle(), this.getType().getYAxisInterpolation(), + this.getType().getTurningSplineInterpolation()); // Otherwise, create a body node } else { - next = new ModelNode(current, (float) ((float) this.getBalloonType().getDistanceBetweenNodes() + this.getBalloonType().getBodyNodeOffset()), - index, getBalloonType(), this.getBalloonOwner(), this.getBalloonType().getMaxNodeJointAngle(), this.getBalloonType().getYAxisInterpolation(), - this.getBalloonType().getTurningSplineInterpolation()); + next = new MultipartBalloonNode(current, (float) ((float) this.getType().getDistanceBetweenNodes() + this.getType().getBodyNodeOffset()), + index, getType(), this.getOwner(), this.getType().getMaxNodeJointAngle(), this.getType().getYAxisInterpolation(), + this.getType().getTurningSplineInterpolation()); } return next; @@ -117,9 +132,9 @@ public void run() { long timeInTicks = 1; // Internally, this stays at one tick to ensure constant updating of positioning - double speed = this.getBalloonType().getPassiveSineWaveSpeed(); // Adjust the speed of the sine wave - double amplitude = this.getBalloonType().getPassiveSineWaveAmplitude(); // Adjust the amplitude of the sine wave - double noseAmplitude = this.getBalloonType().getPassiveNoseSineWaveAmplitude(); // Adjust how much the nose of the first node goes up and down + double speed = this.getType().getPassiveSineWaveSpeed(); // Adjust the speed of the sine wave + double amplitude = this.getType().getPassiveSineWaveAmplitude(); // Adjust the amplitude of the sine wave + double noseAmplitude = this.getType().getPassiveNoseSineWaveAmplitude(); // Adjust how much the nose of the first node goes up and down final boolean[] isInitialized = {false}; @@ -129,7 +144,7 @@ public void run() { @Override public void run() { // Gets the constantly updated owners location - Location balloonOwnerLocation = getBalloonOwner().getLocation(); + Location balloonOwnerLocation = getOwner().getLocation(); // Calculate the Y offset using a sine function with adjusted amplitude double sinValue = Math.sin(yOffset); @@ -147,7 +162,7 @@ public void run() { getTentacle().display(); // Make the other segments follow - ModelNode next = getTentacle().getParent(); + MultipartBalloonNode next = getTentacle().getParent(); while (next != null) { next.follow(); next.display(); @@ -167,9 +182,9 @@ public void run() { // not break the lead if (isInitialized[0]) { // Teleport the chicken holding the leash constantly - Location leadTeleportPoint = new Location(getBalloonOwner().getWorld(), midpointX, getTentacle().getPointA().y + balloonType.getLeashHeight(), midpointZ); - getBalloonChicken().teleport(leadTeleportPoint); - getBalloonChicken().setLeashHolder(getBalloonOwner()); + Location leadTeleportPoint = new Location(getOwner().getWorld(), midpointX, getTentacle().getPointA().y + type.getLeashHeight(), midpointZ); + getChicken().teleport(leadTeleportPoint); + getChicken().setLeashHolder(getOwner()); } } }); @@ -191,15 +206,15 @@ public void destroy() { } // Remove the chicken first to reduce lead dropping on armor stand clears - this.getBalloonChicken().remove(); + this.getChicken().remove(); // Loop through every node and destroy it (remove the armor stand mainly) - for (ModelNode modelNode : this.getModelNodes()) { - modelNode.destroy(); + for (MultipartBalloonNode multipartBalloonNode : this.getMultipartBalloonNodes()) { + multipartBalloonNode.destroy(); } // Clear the model nodes list to prevent memory leaks - this.getModelNodes().clear(); + this.getMultipartBalloonNodes().clear(); } /** @@ -207,7 +222,7 @@ public void destroy() { * @param builder The builder to retrieve the variables from */ MultipartBalloon(MultipartBalloonBuilder builder) { - this.setBalloonType(builder.balloonType); - this.setBalloonOwner(builder.balloonOwner); + this.setType(builder.balloonType); + this.setOwner(builder.balloonOwner); } } diff --git a/src/main/java/net/jeqo/bloons/balloon/multipart/balloon/MultipartBalloonBuilder.java b/src/main/java/net/jeqo/bloons/balloon/multipart/balloon/MultipartBalloonBuilder.java index bf49f1f8..e41ab08c 100644 --- a/src/main/java/net/jeqo/bloons/balloon/multipart/balloon/MultipartBalloonBuilder.java +++ b/src/main/java/net/jeqo/bloons/balloon/multipart/balloon/MultipartBalloonBuilder.java @@ -9,10 +9,13 @@ */ @Setter public class MultipartBalloonBuilder { - - // Both of these have attached lombok setters to - // allow for easy setting of the values in the instance + /** + * The type of balloon to create + */ MultipartBalloonType balloonType; + /** + * The owner of the balloon + */ Player balloonOwner; /** diff --git a/src/main/java/net/jeqo/bloons/balloon/multipart/nodes/ModelNode.java b/src/main/java/net/jeqo/bloons/balloon/multipart/nodes/MultipartBalloonNode.java similarity index 85% rename from src/main/java/net/jeqo/bloons/balloon/multipart/nodes/ModelNode.java rename to src/main/java/net/jeqo/bloons/balloon/multipart/nodes/MultipartBalloonNode.java index 17c204dc..3c331f7a 100644 --- a/src/main/java/net/jeqo/bloons/balloon/multipart/nodes/ModelNode.java +++ b/src/main/java/net/jeqo/bloons/balloon/multipart/nodes/MultipartBalloonNode.java @@ -17,21 +17,59 @@ * Handles the movement and functionality of a single node, model, or armor stand in a multipart balloon */ @Getter @Setter -public class ModelNode { - public ModelNodeVector pointA; - public ModelNodeVector pointB = new ModelNodeVector(); +public class MultipartBalloonNode { + /** + * The front most point of the segment/node + */ + public MultipartBalloonNodeVector pointA; + /** + * The back most point of the segment/node + */ + public MultipartBalloonNodeVector pointB = new MultipartBalloonNodeVector(); - public ModelNode parent = null; - public ModelNode child = null; + /** + * The parent node of the current node + */ + public MultipartBalloonNode parent = null; + /** + * The child node of the current node + */ + public MultipartBalloonNode child = null; + /** + * The armor stand that represents the node + */ ArmorStand balloonArmorStand; - float index; - float length; + /** + * The index position of the node in the balloon chain + */ + private float index; + /** + * The length of the segment in blocks + */ + private float length; + /** + * The type of balloon that the node is a part of that is currently + * registered in the configuration file + */ private MultipartBalloonType balloonType; + /** + * The owner of the balloon + */ private Player balloonOwner; + /** + * The maximum angle that the node can rotate to + */ double maxNodeJointAngle; + /** + * The interpolation factor for the Y-axis + */ double yAxisInterpolation; + /** + * The interpolation factor for the turning spline + * to make the turning of the balloon smoother + */ double turningSplineInterpolation; /** @@ -44,12 +82,12 @@ public class ModelNode { * @param balloonType Type of balloon, type net.jeqo.bloons.balloon.multipart.MultipartBalloonType * @param balloonOwner Owner of the balloon, type org.bukkit.entity.Player */ - public ModelNode(float x, float y, float z, float length, int index, MultipartBalloonType balloonType, Player balloonOwner, double maxNodeJointAngle, double yAxisInterpolation, double turningSplineInterpolation) { + public MultipartBalloonNode(float x, float y, float z, float length, int index, MultipartBalloonType balloonType, Player balloonOwner, double maxNodeJointAngle, double yAxisInterpolation, double turningSplineInterpolation) { this.setLength(length); this.setIndex(index); this.setBalloonType(balloonType); this.setBalloonOwner(balloonOwner); - this.setPointA(new ModelNodeVector(x, y, z)); + this.setPointA(new MultipartBalloonNodeVector(x, y, z)); this.setMaxNodeJointAngle(maxNodeJointAngle); this.setYAxisInterpolation(yAxisInterpolation); this.setTurningSplineInterpolation(turningSplineInterpolation); @@ -70,7 +108,7 @@ public ModelNode(float x, float y, float z, float length, int index, MultipartBa * @param length Length of segment in blocks, type float * @param index Index number in the balloon, type int */ - public ModelNode(ModelNode parent, float length, int index, MultipartBalloonType balloonType, Player balloonOwner, double maxNodeJointAngle, double yAxisInterpolation, double turningSplineInterpolation) { + public MultipartBalloonNode(MultipartBalloonNode parent, float length, int index, MultipartBalloonType balloonType, Player balloonOwner, double maxNodeJointAngle, double yAxisInterpolation, double turningSplineInterpolation) { this.setParent(parent); this.setPointA(parent.getPointB().copy()); this.setLength(length); @@ -124,8 +162,8 @@ public void follow() { * @param targetZ Target Z axis, type float */ public void follow(float targetX, float targetY, float targetZ) { - ModelNodeVector target = new ModelNodeVector(targetX, targetY, targetZ); - ModelNodeVector dir = ModelNodeVector.subtract(target, this.getPointB()); + MultipartBalloonNodeVector target = new MultipartBalloonNodeVector(targetX, targetY, targetZ); + MultipartBalloonNodeVector dir = MultipartBalloonNodeVector.subtract(target, this.getPointB()); double targetAngle = dir.heading(); @@ -208,7 +246,7 @@ private double lerpVal(double startVal, double endVal, double interpolationFacto * @return The heading of the two node vectors, type float */ public float heading(){ - return ModelNodeVector.subtract(this.getPointA(), this.getPointB()).heading(); + return MultipartBalloonNodeVector.subtract(this.getPointA(), this.getPointB()).heading(); } /** diff --git a/src/main/java/net/jeqo/bloons/balloon/multipart/nodes/ModelNodeVector.java b/src/main/java/net/jeqo/bloons/balloon/multipart/nodes/MultipartBalloonNodeVector.java similarity index 71% rename from src/main/java/net/jeqo/bloons/balloon/multipart/nodes/ModelNodeVector.java rename to src/main/java/net/jeqo/bloons/balloon/multipart/nodes/MultipartBalloonNodeVector.java index 36b5a583..80f48212 100644 --- a/src/main/java/net/jeqo/bloons/balloon/multipart/nodes/ModelNodeVector.java +++ b/src/main/java/net/jeqo/bloons/balloon/multipart/nodes/MultipartBalloonNodeVector.java @@ -5,7 +5,7 @@ /** * A custom vector to store the axis of a balloon node */ -public class ModelNodeVector implements Serializable { +public class MultipartBalloonNodeVector implements Serializable { /** * Model node vector axis. */ @@ -16,7 +16,7 @@ public class ModelNodeVector implements Serializable { /** * Creates a blank model node vector. */ - public ModelNodeVector() { + public MultipartBalloonNodeVector() { } /** @@ -25,22 +25,12 @@ public ModelNodeVector() { * @param y Y axis. * @param z Z axis. */ - public ModelNodeVector(float x, float y, float z) { + public MultipartBalloonNodeVector(float x, float y, float z) { this.x = x; this.y = y; this.z = z; } - /** - * Creates a segment vector holding a 2D space. - * @param x X axis. - * @param z Z axis. - */ - public ModelNodeVector(float x, float z) { - this.x = x; - this.z = z; - } - /** * Sets a 3D's vectors axis. * @param x X axis float. @@ -67,8 +57,8 @@ public void set(float x, float z) { * Copies a segment vector. * @return The copy of the vector. */ - public ModelNodeVector copy() { - return new ModelNodeVector(x, y, z); + public MultipartBalloonNodeVector copy() { + return new MultipartBalloonNodeVector(x, y, z); } /** @@ -77,7 +67,7 @@ public ModelNodeVector copy() { * @param v2 Segment vector 2. * @return The combined segment vector. */ - static public ModelNodeVector add(ModelNodeVector v1, ModelNodeVector v2) { + static public MultipartBalloonNodeVector add(MultipartBalloonNodeVector v1, MultipartBalloonNodeVector v2) { return add(v1, v2, null); } @@ -88,9 +78,9 @@ static public ModelNodeVector add(ModelNodeVector v1, ModelNodeVector v2) { * @param target Target vector. * @return The combined vectors. */ - static public ModelNodeVector add(ModelNodeVector v1, ModelNodeVector v2, ModelNodeVector target) { + static public MultipartBalloonNodeVector add(MultipartBalloonNodeVector v1, MultipartBalloonNodeVector v2, MultipartBalloonNodeVector target) { if (target == null) { - target = new ModelNodeVector(v1.x + v2.x,v1.y + v2.y, v1.z + v2.z); + target = new MultipartBalloonNodeVector(v1.x + v2.x,v1.y + v2.y, v1.z + v2.z); } else { target.set(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z); } @@ -103,7 +93,7 @@ static public ModelNodeVector add(ModelNodeVector v1, ModelNodeVector v2, ModelN * @param v2 Segment vector 2. * @return The result of the two subtracted vectors. */ - static public ModelNodeVector subtract(ModelNodeVector v1, ModelNodeVector v2) { + static public MultipartBalloonNodeVector subtract(MultipartBalloonNodeVector v1, MultipartBalloonNodeVector v2) { return subtract(v1, v2, null); } @@ -114,9 +104,9 @@ static public ModelNodeVector subtract(ModelNodeVector v1, ModelNodeVector v2) { * @param target Target vector. * @return The result of the subtraction. */ - static public ModelNodeVector subtract(ModelNodeVector v1, ModelNodeVector v2, ModelNodeVector target) { + static public MultipartBalloonNodeVector subtract(MultipartBalloonNodeVector v1, MultipartBalloonNodeVector v2, MultipartBalloonNodeVector target) { if (target == null) { - target = new ModelNodeVector(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z); + target = new MultipartBalloonNodeVector(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z); } else { target.set(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z); } diff --git a/src/main/java/net/jeqo/bloons/balloon/single/SingleBalloon.java b/src/main/java/net/jeqo/bloons/balloon/single/SingleBalloon.java index 4ea39abd..373ba8ce 100644 --- a/src/main/java/net/jeqo/bloons/balloon/single/SingleBalloon.java +++ b/src/main/java/net/jeqo/bloons/balloon/single/SingleBalloon.java @@ -33,11 +33,16 @@ @Getter @Setter public class SingleBalloon extends BukkitRunnable { - private SingleBalloonType balloonType; + /** Must have variables related to any balloon **/ + private SingleBalloonType type; private Player player; - private ItemStack balloonVisual; - private ArmorStand balloonArmorStand; - public Chicken balloonChicken; + private ArmorStand armorStand; + public Chicken chicken; + + /** + * Only used for non-MEG balloons to configure the visual appearance of the balloon + */ + private ItemStack visual; /** MEG related variables **/ private ModeledEntity modeledEntity; @@ -45,13 +50,15 @@ public class SingleBalloon extends BukkitRunnable { private AnimationHandler animationHandler; private final String defaultIdleAnimationID = "idle"; + /** Variables used for the movement of the balloon **/ private Location playerLocation; private Location moveLocation; private int ticks = 0; private float targetYaw = 0.0F; - private static final String leatherMaterialPrefix = "LEATHER_"; // A constant to define a dyeable material + // A prefix that is needed for dyable materials + private static final String LEATHER_MATERIAL_PREFIX = "LEATHER_"; /** * Constructor for the SingleBalloon class @@ -60,11 +67,83 @@ public class SingleBalloon extends BukkitRunnable { */ public SingleBalloon(Player player, String balloonID) { this.setPlayer(player); - this.setBalloonType(Bloons.getBalloonCore().getSingleBalloonByID(balloonID)); + this.setType(Bloons.getBalloonCore().getSingleBalloonByID(balloonID)); + + if (this.getType().getMegModelID() == null) { + this.setVisual(getConfiguredBalloonVisual(balloonID)); + } + } + + /** + * Initializes the balloon and its subcomponents. + * Sets the current players location, and initializes the armor stand, and chicken entities + */ + private void initializeBalloon() { + this.setPlayerLocation(this.getPlayer().getLocation()); + this.getPlayerLocation().setYaw(0.0F); + + if (this.getType().getMegModelID() == null) { + // Create and set the balloons visual appearance/model + ItemMeta meta = this.getVisual().getItemMeta(); + meta.addItemFlags(ItemFlag.HIDE_UNBREAKABLE); + this.getVisual().setItemMeta(meta); + } + + // Initialize the armor stand and lead to the player + this.initializeBalloonArmorStand(); + this.initializeBalloonLead(); + } - if (this.getBalloonType().getMegModelID() == null) { - this.setBalloonVisual(getConfiguredBalloonVisual(balloonID)); + /** + * Initializes the balloon's armor stand entity with the proper configurations + */ + public void initializeBalloonArmorStand() { + this.setArmorStand(this.getPlayerLocation().getWorld().spawn(this.getPlayerLocation(), ArmorStand.class)); + this.getArmorStand().setBasePlate(false); + this.getArmorStand().setVisible(false); + this.getArmorStand().setInvulnerable(true); + this.getArmorStand().setCanPickupItems(false); + this.getArmorStand().setGravity(false); + this.getArmorStand().setSmall(false); + this.getArmorStand().setMarker(true); + this.getArmorStand().setCollidable(false); + if (this.getType().getMegModelID() == null) { + this.getArmorStand().getEquipment().setHelmet(this.getVisual()); + } else { + try { + // Create the entity and tag it onto the armor stand + ModeledEntity modeledEntity = ModelEngineAPI.createModeledEntity(this.getArmorStand()); + ActiveModel activeModel = ModelEngineAPI.createActiveModel(this.getType().getMegModelID()); + + modeledEntity.addModel(activeModel, true); + + // Set the animation handler to the one of the active model + this.setAnimationHandler(activeModel.getAnimationHandler()); + + // If an idle animation exists, play it initially + this.getAnimationHandler().playAnimation(this.getDefaultIdleAnimationID(), 0.3, 0.3, 1,true); + } catch (Exception e) { + Logger.logError("An error occurred while creating the MEG model for the balloon " + this.getType().getId() + "! This is because a MEG model error occurred."); + e.printStackTrace(); + } } + this.getArmorStand().customName(Component.text(BalloonConfiguration.BALLOON_ARMOR_STAND_ID)); + } + + /** + * Initializes the balloon's lead to the player (chicken entity) + */ + public void initializeBalloonLead() { + this.setChicken(this.getPlayerLocation().getWorld().spawn(this.getPlayerLocation(), Chicken.class)); + this.getChicken().setInvulnerable(true); + this.getChicken().setInvisible(true); + this.getChicken().setSilent(true); + this.getChicken().setBaby(); + this.getChicken().setAgeLock(true); + this.getChicken().setAware(false); + this.getChicken().setCollidable(false); + this.getChicken().setLeashHolder(this.getPlayer()); + this.getChicken().customName(Component.text(BalloonConfiguration.BALLOON_CHICKEN_ID)); } /** @@ -73,7 +152,7 @@ public SingleBalloon(Player player, String balloonID) { */ public void run() { // If the balloon armor stand is null, initialize the balloon - if (this.getBalloonArmorStand() == null) initializeBalloon(); + if (this.getArmorStand() == null) initializeBalloon(); // Every tick, retrieve the updated player location Location playerLocation = this.getPlayerLocation(); @@ -93,7 +172,7 @@ public void run() { } // Set the move location to the armor stand location minus 2 on the Y axis - this.setMoveLocation(this.getBalloonArmorStand().getLocation().subtract(0.0D, 2.0D, 0.0D).clone()); + this.setMoveLocation(this.getArmorStand().getLocation().subtract(0.0D, this.getType().getBalloonHeight(), 0.0D).clone()); // Set the vector to the player location minus the move location Vector vector = playerLocation.toVector().subtract(this.getMoveLocation().toVector()); @@ -105,14 +184,14 @@ public void run() { EulerAngle tiltAngle = new EulerAngle(Math.toRadians(vectorZ), Math.toRadians(playerLocation.getYaw()), Math.toRadians(vectorX)); // Set the pose(s) of the armor stand - ArmorStand armorStand = this.getBalloonArmorStand(); + ArmorStand armorStand = this.getArmorStand(); // Set the pose of only the head regardless of the model type armorStand.setHeadPose(tiltAngle); // Only set the entire pose of the armor stand if it uses MEG, this is to reduce lag across the server // when having 100's of models/armor stands used simultaneously - if (this.getBalloonType().getMegModelID() != null) { + if (this.getType().getMegModelID() != null) { armorStand.setBodyPose(tiltAngle); armorStand.setLeftArmPose(tiltAngle); armorStand.setRightArmPose(tiltAngle); @@ -124,7 +203,7 @@ public void run() { this.teleport(this.getMoveLocation()); // If the balloon armor stand is more than 5 blocks away, teleport to player location - if (this.getBalloonArmorStand().getLocation().distance(playerLocation) > 5.0D) { + if (this.getArmorStand().getLocation().distance(playerLocation) > 5.0D) { this.teleport(playerLocation); } @@ -149,11 +228,11 @@ public void run() { public synchronized void cancel() throws IllegalStateException { if (this.getModeledEntity() != null) { // Remove the MEG model if it exists - ModeledEntity modeledEntity = ModelEngineAPI.getModeledEntity(this.getBalloonArmorStand()); - modeledEntity.removeModel(this.getBalloonType().getMegModelID()); + ModeledEntity modeledEntity = ModelEngineAPI.getModeledEntity(this.getArmorStand()); + modeledEntity.removeModel(this.getType().getMegModelID()); } - this.getBalloonArmorStand().remove(); - this.getBalloonChicken().remove(); + this.getArmorStand().remove(); + this.getChicken().remove(); super.cancel(); } @@ -169,28 +248,8 @@ public void spawnRemoveParticle() { * @param location The location to teleport the balloon to, type org.bukkit.Location */ private void teleport(Location location) { - this.getBalloonArmorStand().teleport(location.add(0.0D, 2.0D, 0.0D)); - this.getBalloonChicken().teleport(location.add(0.0D, 1.2D, 0.0D)); - } - - /** - * Initializes the balloon and its subcomponents. - * Sets the current players location, and initializes the armor stand, and chicken entities - */ - private void initializeBalloon() { - this.setPlayerLocation(this.getPlayer().getLocation()); - this.getPlayerLocation().setYaw(0.0F); - - if (this.getBalloonType().getMegModelID() == null) { - // Create and set the balloons visual appearance/model - ItemMeta meta = this.getBalloonVisual().getItemMeta(); - meta.addItemFlags(ItemFlag.HIDE_UNBREAKABLE); - this.getBalloonVisual().setItemMeta(meta); - } - - // Initialize the armor stand and lead to the player - this.initializeBalloonArmorStand(); - this.initializeBalloonLead(); + this.getArmorStand().teleport(location.add(0.0D, this.getType().getBalloonHeight(), 0.0D)); + this.getChicken().teleport(location.add(0.0D, this.getType().getLeashHeight(), 0.0D)); } /** @@ -227,7 +286,7 @@ public ItemStack getConfiguredBalloonVisual(String balloonID) { meta.setCustomModelData(singleBalloonType.getCustomModelData()); // If the color of the balloon is not set, log an error and return null - if (singleBalloonType.getColor() != null && singleBalloonType.getMaterial().startsWith(leatherMaterialPrefix)) { + if (singleBalloonType.getColor() != null && singleBalloonType.getMaterial().startsWith(LEATHER_MATERIAL_PREFIX)) { // If the color of the balloon is set to potion, log a warning and return null if (singleBalloonType.getColor().equalsIgnoreCase("potion")) { Logger.logWarning(String.format(Languages.getMessage("material-not-dyeable"), material)); @@ -244,58 +303,6 @@ public ItemStack getConfiguredBalloonVisual(String balloonID) { return item; } - /** - * Initializes the balloon's armor stand entity with the proper configurations - */ - public void initializeBalloonArmorStand() { - this.setBalloonArmorStand(this.getPlayerLocation().getWorld().spawn(this.getPlayerLocation(), ArmorStand.class)); - this.getBalloonArmorStand().setBasePlate(false); - this.getBalloonArmorStand().setVisible(false); - this.getBalloonArmorStand().setInvulnerable(true); - this.getBalloonArmorStand().setCanPickupItems(false); - this.getBalloonArmorStand().setGravity(false); - this.getBalloonArmorStand().setSmall(false); - this.getBalloonArmorStand().setMarker(true); - this.getBalloonArmorStand().setCollidable(false); - if (this.getBalloonType().getMegModelID() == null) { - this.getBalloonArmorStand().getEquipment().setHelmet(this.getBalloonVisual()); - } else { - try { - // Create the entity and tag it onto the armor stand - ModeledEntity modeledEntity = ModelEngineAPI.createModeledEntity(this.getBalloonArmorStand()); - ActiveModel activeModel = ModelEngineAPI.createActiveModel(this.getBalloonType().getMegModelID()); - - modeledEntity.addModel(activeModel, true); - - // Set the animation handler to the one of the active model - this.setAnimationHandler(activeModel.getAnimationHandler()); - - // If an idle animation exists, play it initially - this.getAnimationHandler().playAnimation(this.getDefaultIdleAnimationID(), 0.3, 0.3, 1,true); - } catch (Exception e) { - Logger.logError("An error occurred while creating the MEG model for the balloon " + this.getBalloonType().getId() + "! This is because a MEG model error occurred."); - e.printStackTrace(); - } - } - this.getBalloonArmorStand().customName(Component.text(BalloonConfiguration.BALLOON_ARMOR_STAND_ID)); - } - - /** - * Initializes the balloon's lead to the player (chicken entity) - */ - public void initializeBalloonLead() { - this.setBalloonChicken(this.getPlayerLocation().getWorld().spawn(this.getPlayerLocation(), Chicken.class)); - this.getBalloonChicken().setInvulnerable(true); - this.getBalloonChicken().setInvisible(true); - this.getBalloonChicken().setSilent(true); - this.getBalloonChicken().setBaby(); - this.getBalloonChicken().setAgeLock(true); - this.getBalloonChicken().setAware(false); - this.getBalloonChicken().setCollidable(false); - this.getBalloonChicken().setLeashHolder(this.getPlayer()); - this.getBalloonChicken().customName(Component.text(BalloonConfiguration.BALLOON_CHICKEN_ID)); - } - /** * Checks if a balloon needs to be removed or added * @param player The player to check, type org.bukkit.entity.Player diff --git a/src/main/java/net/jeqo/bloons/balloon/single/SingleBalloonType.java b/src/main/java/net/jeqo/bloons/balloon/single/SingleBalloonType.java index 877e00b8..4dd0acbd 100644 --- a/src/main/java/net/jeqo/bloons/balloon/single/SingleBalloonType.java +++ b/src/main/java/net/jeqo/bloons/balloon/single/SingleBalloonType.java @@ -8,18 +8,55 @@ */ @Getter @Setter public class SingleBalloonType { + /** + * The key we are retrieving values from + */ private String key; + /** + * The unique identifier for the balloon type + */ private String id; + /** + * The permission required to use the balloon + */ private String permission; - private String name; - - private String[] lore; + /** + * The height of the leash attached to a player relative from the head of the player in blocks + * Default is 1.2 blocks + */ + private double leashHeight = 1.2D; + /** + * The height of the balloon when attached to a player relative from the head of the player in blocks + * Default is 2.0 blocks + */ + private double balloonHeight = 2.0D; + /** + * The name of the material that makes up the balloons model + */ private String material; - // Not used by MEG balloons + /* + * The color of the model as a hex color code value if the balloon is not a MEG balloon and if + * the material above is dyeable + * Default is #ffffff (white) + */ private String color = "#ffffff"; + /** + * The value of the custom model data stored in the item metadata for the model + */ private int customModelData; + /** + * The name of the balloon that is displayed both in chat and in the Bloons menu + */ + private String name; + /** + * The lore of the item that is displayed in the GUI + */ + private String[] lore; - /** MEG only options **/ + /** + * The ID of the MEG (ModelEngine) model you wish to use as the balloon model + * This is only used if the balloon is a MEG balloon + */ private String megModelID; /** @@ -27,16 +64,20 @@ public class SingleBalloonType { * @param key The key of the balloon type in the configuration, type java.lang.String * @param id The unique identifier for the balloon type, type java.lang.String * @param permission The permission required to use the balloon type, type java.lang.String + * @param leashHeight The height of the leash when the balloon is attached to a player, type double + * @param balloonHeight The height of the balloon when attached to a player, type double * @param material The name of the Bukkit Material used to create the item, type java.lang.String * @param color The color of the model as a hex color code value, type java.lang.String * @param customModelData The custom model data value stored in the item metadata, type int * @param name The name of the balloon, type java.lang.String * @param lore The lore of the balloon, type java.lang.String[] */ - public SingleBalloonType(String key, String id, String permission, String material, String color, int customModelData, String name, String[] lore) { + public SingleBalloonType(String key, String id, String permission, double leashHeight, double balloonHeight, String material, String color, int customModelData, String name, String[] lore) { this.setKey(key); this.setId(id); this.setPermission(permission); + if (leashHeight > 0.0D) this.setLeashHeight(leashHeight); + if (balloonHeight > 0.0D) this.setBalloonHeight(balloonHeight); this.setMaterial(material); this.setColor(color); this.setCustomModelData(customModelData); @@ -51,6 +92,7 @@ public SingleBalloonType(String key, String id, String permission, String materi * @param permission The permission required to use the balloon type, type java.lang.String * @param material The name of the Bukkit Material used to create the item, type java.lang.String * @param customModelData The custom model data value stored in the item metadata, type int + * @param megModelID The ID of the MEG model to use as the balloon model, type java.lang.String * @param name The name of the balloon, type java.lang.String * @param lore The lore of the balloon, type java.lang.String[] */ diff --git a/src/main/java/net/jeqo/bloons/configuration/ConfigConfiguration.java b/src/main/java/net/jeqo/bloons/configuration/ConfigConfiguration.java index 43f452cf..77e2edc9 100644 --- a/src/main/java/net/jeqo/bloons/configuration/ConfigConfiguration.java +++ b/src/main/java/net/jeqo/bloons/configuration/ConfigConfiguration.java @@ -1,7 +1,7 @@ package net.jeqo.bloons.configuration; import net.jeqo.bloons.Bloons; -import net.jeqo.bloons.balloon.model.BalloonModelType; +import net.jeqo.bloons.balloon.model.BalloonSegmentType; import net.jeqo.bloons.balloon.multipart.MultipartBalloonModel; import net.jeqo.bloons.balloon.multipart.MultipartBalloonType; import net.jeqo.bloons.balloon.single.SingleBalloonType; @@ -120,6 +120,8 @@ public static ArrayList getSingleBalloons() { key, config.getString(key + ".id"), config.getString(key + ".permission"), + config.getDouble(key + ".leash-height"), + config.getDouble(key + ".balloon-height"), config.getString(key + ".material"), config.getString(key + ".color"), config.getInt(key + ".custom-model-data"), @@ -207,19 +209,19 @@ public static ArrayList getMultipartBalloons() { config.getDouble(key + ".passive-sine-wave-amplitude"), config.getDouble(key + ".passive-nose-sine-wave-amplitude"), new MultipartBalloonModel( - BalloonModelType.HEAD, + BalloonSegmentType.HEAD, config.getString(key + ".head.material"), config.getString(key + ".head.color"), config.getInt(key + ".head.custom-model-data") ), new MultipartBalloonModel( - BalloonModelType.BODY, + BalloonSegmentType.BODY, config.getString(key + ".body.material"), config.getString(key + ".body.color"), config.getInt(key + ".body.custom-model-data") ), new MultipartBalloonModel( - BalloonModelType.TAIL, + BalloonSegmentType.TAIL, config.getString(key + ".tail.material"), config.getString(key + ".tail.color"), config.getInt(key + ".tail.custom-model-data") diff --git a/src/main/java/net/jeqo/bloons/listeners/multipart/MultipartBalloonPlayerJoinListener.java b/src/main/java/net/jeqo/bloons/listeners/multipart/MultipartBalloonPlayerJoinListener.java index 9861ee0c..311e8f02 100644 --- a/src/main/java/net/jeqo/bloons/listeners/multipart/MultipartBalloonPlayerJoinListener.java +++ b/src/main/java/net/jeqo/bloons/listeners/multipart/MultipartBalloonPlayerJoinListener.java @@ -24,7 +24,7 @@ public void onPlayerJoin(PlayerJoinEvent event) { if (equipEvent.isCancelled()) return; - MultipartBalloonType balloonType = MultipartBalloonManagement.getPlayerBalloon(event.getPlayer().getUniqueId()).getBalloonType(); + MultipartBalloonType balloonType = MultipartBalloonManagement.getPlayerBalloon(event.getPlayer().getUniqueId()).getType(); MultipartBalloonManagement.removePlayerBalloon(event.getPlayer().getUniqueId()); diff --git a/src/main/java/net/jeqo/bloons/listeners/multipart/MultipartBalloonPlayerListener.java b/src/main/java/net/jeqo/bloons/listeners/multipart/MultipartBalloonPlayerListener.java index d193363e..5a69deff 100644 --- a/src/main/java/net/jeqo/bloons/listeners/multipart/MultipartBalloonPlayerListener.java +++ b/src/main/java/net/jeqo/bloons/listeners/multipart/MultipartBalloonPlayerListener.java @@ -42,7 +42,7 @@ public void onDeath(PlayerDeathEvent event) { @EventHandler public void onRespawn(PlayerRespawnEvent event) { MultipartBalloon previousBalloon = Bloons.getPlayerMultipartBalloons().get(event.getPlayer().getPlayer().getUniqueId()); - MultipartBalloonType type = previousBalloon.getBalloonType(); + MultipartBalloonType type = previousBalloon.getType(); if (previousBalloon == null) return; @@ -68,7 +68,7 @@ public void onRespawn(PlayerRespawnEvent event) { public void onWorldChange(PlayerChangedWorldEvent event) { MultipartBalloon balloon = Bloons.getPlayerMultipartBalloons().get(event.getPlayer().getUniqueId()); MultipartBalloon previousBalloon = Bloons.getPlayerMultipartBalloons().get(event.getPlayer().getPlayer().getUniqueId()); - MultipartBalloonType type = previousBalloon.getBalloonType(); + MultipartBalloonType type = previousBalloon.getType(); MultipartBalloonForceUnequipEvent multipartBalloonForceUnequipEvent = new MultipartBalloonForceUnequipEvent(event.getPlayer(), balloon); diff --git a/src/main/resources/balloons/color_pack_example.yml b/src/main/resources/balloons/color_pack_example.yml index faab8f5c..8b4e968e 100644 --- a/src/main/resources/balloons/color_pack_example.yml +++ b/src/main/resources/balloons/color_pack_example.yml @@ -2,7 +2,7 @@ # It can contain all the way from one balloon to technically an infinite # amount of balloons, as long as the server can handle it. blue: - type: single # The type of balloon, this must be single for single balloons + type: single id: blue permission: balloon.blue material: FLINT diff --git a/src/main/resources/balloons/dyeable_example.yml b/src/main/resources/balloons/dyeable_example.yml index 345f45ca..8e84004b 100644 --- a/src/main/resources/balloons/dyeable_example.yml +++ b/src/main/resources/balloons/dyeable_example.yml @@ -5,6 +5,8 @@ dyeable_example: type: single id: dyeable_example permission: balloon.dyeable + leash-height: 1.2 + balloon-height: 2.0 material: LEATHER_HORSE_ARMOR color: '#ffffff' custom-model-data: 1 diff --git a/src/main/resources/balloons/meg_example.yml b/src/main/resources/balloons/meg_example.yml new file mode 100644 index 00000000..4bef83d5 --- /dev/null +++ b/src/main/resources/balloons/meg_example.yml @@ -0,0 +1,14 @@ +# An example of a MEG balloon which utilizes custom models from ModelEngine +meg_example: + type: single + id: meg_example + permission: balloon.meg_example + meg-model-id: meg_example + icon: + material: FLINT + custom-model-data: 7 + name: 'MEG Balloon' + lore: + - '&8Bloons Default Balloon' + - '' + - '&eᴄʟɪᴄᴋ ᴛᴏ ᴇǫᴜɪᴘ' \ No newline at end of file diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 91ab77a6..f2b04852 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -3,7 +3,7 @@ # Bloons 2.0.0 # Made by Jeqo # -# Wiki: https://jeqo.net/wiki/bloons +# Wiki: https://jeqo.net/wiki # Discord: https://jeqo.net/discord # # Default Assets Made by TwistedDreams