diff --git a/api/src/main/java/net/momirealms/customnameplates/api/feature/image/Animation.java b/api/src/main/java/net/momirealms/customnameplates/api/feature/image/Animation.java new file mode 100644 index 0000000..bae0ee0 --- /dev/null +++ b/api/src/main/java/net/momirealms/customnameplates/api/feature/image/Animation.java @@ -0,0 +1,21 @@ +/* + * Copyright (C) <2024> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.momirealms.customnameplates.api.feature.image; + +public record Animation(int speed, int frames) { +} diff --git a/api/src/main/java/net/momirealms/customnameplates/api/feature/image/Image.java b/api/src/main/java/net/momirealms/customnameplates/api/feature/image/Image.java index 16c4751..29cd170 100644 --- a/api/src/main/java/net/momirealms/customnameplates/api/feature/image/Image.java +++ b/api/src/main/java/net/momirealms/customnameplates/api/feature/image/Image.java @@ -18,6 +18,7 @@ package net.momirealms.customnameplates.api.feature.image; import net.momirealms.customnameplates.api.feature.ConfiguredCharacter; +import org.jetbrains.annotations.Nullable; public interface Image { @@ -33,15 +34,15 @@ public interface Image { * * @return true if the image has a shadow, false otherwise */ - boolean hasShadow(); + boolean removeShadow(); /** - * Returns the opacity level of the image. - * The value should typically range from 0 (fully transparent) to 255 (fully opaque). + * Get the animation of the image * - * @return the opacity value of the image + * @return the animated image */ - int opacity(); + @Nullable + Animation animation(); /** * Returns the configured character associated with this image. @@ -73,20 +74,20 @@ public interface Image { Builder id(String id); /** - * Sets whether the image has a shadow effect. + * Sets whether to remove the shadow of the image * - * @param has true if the image should have a shadow, false otherwise + * @param remove true if to remove the shadow * @return the builder instance */ - Builder hasShadow(boolean has); + Builder removeShadow(boolean remove); /** - * Sets the opacity level of the image. + * Sets the animation of the image * - * @param opacity the opacity value, typically from 0 to 255 + * @param animation animation * @return the builder instance */ - Builder opacity(int opacity); + Builder animation(@Nullable Animation animation); /** * Sets the configured character associated with this image. diff --git a/api/src/main/java/net/momirealms/customnameplates/api/feature/image/ImageImpl.java b/api/src/main/java/net/momirealms/customnameplates/api/feature/image/ImageImpl.java index d534430..834a201 100644 --- a/api/src/main/java/net/momirealms/customnameplates/api/feature/image/ImageImpl.java +++ b/api/src/main/java/net/momirealms/customnameplates/api/feature/image/ImageImpl.java @@ -18,21 +18,22 @@ package net.momirealms.customnameplates.api.feature.image; import net.momirealms.customnameplates.api.feature.ConfiguredCharacter; +import org.jetbrains.annotations.Nullable; import java.util.Objects; public class ImageImpl implements Image { private final String id; - private final boolean hasShadow; - private final int opacity; + private final boolean removeShadow; private final ConfiguredCharacter character; + private final Animation animation; - public ImageImpl(String id, boolean hasShadow, int opacity, ConfiguredCharacter character) { + public ImageImpl(String id, boolean removeShadow, Animation animation, ConfiguredCharacter character) { this.id = id; - this.hasShadow = hasShadow; - this.opacity = opacity; + this.removeShadow = removeShadow; this.character = character; + this.animation = animation; } @Override @@ -41,13 +42,13 @@ public class ImageImpl implements Image { } @Override - public boolean hasShadow() { - return hasShadow; + public boolean removeShadow() { + return removeShadow; } @Override - public int opacity() { - return opacity; + public @Nullable Animation animation() { + return animation; } @Override @@ -71,9 +72,9 @@ public class ImageImpl implements Image { public static class BuilderImpl implements Builder { private String id; - private boolean hasShadow; - private int opacity; + private boolean removeShadow; private ConfiguredCharacter character; + private Animation animation; @Override public Builder id(String id) { @@ -82,14 +83,14 @@ public class ImageImpl implements Image { } @Override - public Builder hasShadow(boolean has) { - this.hasShadow = has; + public Builder removeShadow(boolean removeShadow) { + this.removeShadow = removeShadow; return this; } @Override - public Builder opacity(int opacity) { - this.opacity = opacity; + public Builder animation(@Nullable Animation animation) { + this.animation = animation; return this; } @@ -101,7 +102,7 @@ public class ImageImpl implements Image { @Override public Image build() { - return new ImageImpl(id, hasShadow, opacity, character); + return new ImageImpl(id, removeShadow, animation, character); } } } diff --git a/backend/src/main/java/net/momirealms/customnameplates/backend/feature/image/ImageManagerImpl.java b/backend/src/main/java/net/momirealms/customnameplates/backend/feature/image/ImageManagerImpl.java index c98faa6..470068b 100644 --- a/backend/src/main/java/net/momirealms/customnameplates/backend/feature/image/ImageManagerImpl.java +++ b/backend/src/main/java/net/momirealms/customnameplates/backend/feature/image/ImageManagerImpl.java @@ -21,6 +21,7 @@ import dev.dejvokep.boostedyaml.YamlDocument; import net.momirealms.customnameplates.api.ConfigManager; import net.momirealms.customnameplates.api.CustomNameplates; import net.momirealms.customnameplates.api.feature.ConfiguredCharacter; +import net.momirealms.customnameplates.api.feature.image.Animation; import net.momirealms.customnameplates.api.feature.image.Image; import net.momirealms.customnameplates.api.feature.image.ImageManager; import net.momirealms.customnameplates.api.util.ConfigUtils; @@ -73,8 +74,11 @@ public class ImageManagerImpl implements ImageManager { String id = configFile.getName().substring(0, configFile.getName().lastIndexOf(".")); Image image = Image.builder() .id(id) - .hasShadow(!config.getBoolean("shadow.remove", false)) - .opacity(config.getInt("shadow.opacity", 254)) + .animation(config.contains("animation") ? new Animation( + config.getInt("animation.speed", 64), + config.getInt("animation.frames", 1) + ) : null) + .removeShadow(!config.getBoolean("shadow", true)) .character(ConfiguredCharacter.create( ConfigUtils.getFileInTheSameFolder(configFile, config.getString("image") + ".png"), config.getInt("ascent", 8), diff --git a/backend/src/main/java/net/momirealms/customnameplates/backend/feature/pack/ResourcePackManagerImpl.java b/backend/src/main/java/net/momirealms/customnameplates/backend/feature/pack/ResourcePackManagerImpl.java index 1bb2c95..6a6d852 100644 --- a/backend/src/main/java/net/momirealms/customnameplates/backend/feature/pack/ResourcePackManagerImpl.java +++ b/backend/src/main/java/net/momirealms/customnameplates/backend/feature/pack/ResourcePackManagerImpl.java @@ -29,6 +29,7 @@ import net.momirealms.customnameplates.api.feature.OffsetFont; import net.momirealms.customnameplates.api.feature.advance.CharacterFontAdvanceData; import net.momirealms.customnameplates.api.feature.background.Background; import net.momirealms.customnameplates.api.feature.bubble.Bubble; +import net.momirealms.customnameplates.api.feature.image.Animation; import net.momirealms.customnameplates.api.feature.image.Image; import net.momirealms.customnameplates.api.feature.nameplate.Nameplate; import net.momirealms.customnameplates.api.feature.pack.ResourcePackManager; @@ -321,11 +322,53 @@ public class ResourcePackManagerImpl implements ResourcePackManager { jo.add("chars", ja); list.add(jo); try { + File targetFile = new File(texturesFolder, + ConfigManager.imagePath().replace("\\", File.separator) + character.imageFile().getName()); FileUtils.copyFile( new File(plugin.getDataFolder(), - "contents" + File.separator + "images" + File.separator + character.imageFile().getName()), - new File(texturesFolder, - ConfigManager.imagePath().replace("\\", File.separator) + character.imageFile().getName())); + "contents" + File.separator + "images" + File.separator + character.imageFile().getName()), targetFile); + if (image.removeShadow() || image.animation() != null) { + BufferedImage bufferedImage = ImageIO.read(targetFile); + if (image.removeShadow()) { + for (int y = 0; y < bufferedImage.getHeight(); y++) { + for (int x = 0; x < bufferedImage.getWidth(); x++) { + int argb = bufferedImage.getRGB(x, y); + int alpha = (argb >> 24) & 0xff; + if (alpha != 0) { + int rgb = argb & 0x00ffffff; + int newArgb = (254 << 24) | rgb; + bufferedImage.setRGB(x, y, newArgb); + } + } + } + } + + Animation animation = image.animation(); + if (animation != null) { + int height = bufferedImage.getHeight(); + int extra = height % animation.frames(); + if (extra > 0) { + plugin.getPluginLogger().warn("Image height is not a multiple of frame rate: " + image.id()); + continue; + } + int eachFrameHeight = height / animation.frames(); + int width = bufferedImage.getWidth(); + int speed = Math.min(Math.max(animation.speed(), 1), 255); + + int alpha = 1; + int red = speed; + int green = width; + int blue = eachFrameHeight; + int argb = (alpha << 24) | (red << 16) | (green << 8) | blue; + + for (int i = 0; i < animation.frames(); i++) { + int y = i * eachFrameHeight; + bufferedImage.setRGB(0, y, argb); + } + } + + ImageIO.write(bufferedImage, "png", targetFile); + } } catch (IOException e) { throw new RuntimeException(e); } @@ -583,6 +626,7 @@ public class ResourcePackManagerImpl implements ResourcePackManager { " vertexColor = ((.6 + .6 * cos(6. * (gl_Position.x + GameTime * 1000.) + vec4(0, 23, 21, 1))) + vec4(0., 0., 0., 1.)) * texelFetch(Sampler2, UV2 / 16, 0);\n" + " gl_Position = ProjMat * ModelViewMat * vertex;\n" + " } else "; + public static final String Hide_ScoreBoard_Numbers = "\n" + " if (Position.z == 0.0\n" + diff --git a/backend/src/main/resources/contents/images/bell.yml b/backend/src/main/resources/contents/images/bell.yml index bdf645e..ffe7172 100644 --- a/backend/src/main/resources/contents/images/bell.yml +++ b/backend/src/main/resources/contents/images/bell.yml @@ -1,3 +1,4 @@ image: bell height: 10 -ascent: 4 \ No newline at end of file +ascent: 4 +shadow: false \ No newline at end of file diff --git a/backend/src/main/resources/contents/images/bubble.yml b/backend/src/main/resources/contents/images/bubble.yml index fd9f8f3..6883278 100644 --- a/backend/src/main/resources/contents/images/bubble.yml +++ b/backend/src/main/resources/contents/images/bubble.yml @@ -1,3 +1,4 @@ image: bubble height: 10 -ascent: 4 \ No newline at end of file +ascent: 4 +shadow: false \ No newline at end of file diff --git a/backend/src/main/resources/contents/images/clock.yml b/backend/src/main/resources/contents/images/clock.yml index 89d0e28..2382766 100644 --- a/backend/src/main/resources/contents/images/clock.yml +++ b/backend/src/main/resources/contents/images/clock.yml @@ -1,3 +1,4 @@ image: clock height: 10 -ascent: 4 \ No newline at end of file +ascent: 4 +shadow: false \ No newline at end of file diff --git a/backend/src/main/resources/contents/images/coin.yml b/backend/src/main/resources/contents/images/coin.yml index 7ab3460..3e91a4c 100644 --- a/backend/src/main/resources/contents/images/coin.yml +++ b/backend/src/main/resources/contents/images/coin.yml @@ -1,3 +1,4 @@ image: coin height: 10 -ascent: -14 \ No newline at end of file +ascent: -14 +shadow: false \ No newline at end of file diff --git a/backend/src/main/resources/contents/images/compass.yml b/backend/src/main/resources/contents/images/compass.yml index 9acdf75..5ede4b9 100644 --- a/backend/src/main/resources/contents/images/compass.yml +++ b/backend/src/main/resources/contents/images/compass.yml @@ -1,3 +1,4 @@ image: compass height: 10 -ascent: 4 \ No newline at end of file +ascent: 4 +shadow: false \ No newline at end of file diff --git a/backend/src/main/resources/contents/images/stamina_0.yml b/backend/src/main/resources/contents/images/stamina_0.yml index b698ede..278d569 100644 --- a/backend/src/main/resources/contents/images/stamina_0.yml +++ b/backend/src/main/resources/contents/images/stamina_0.yml @@ -1,3 +1,4 @@ image: stamina_0 height: 9 -ascent: -16 \ No newline at end of file +ascent: -16 +shadow: false \ No newline at end of file diff --git a/backend/src/main/resources/contents/images/stamina_1.yml b/backend/src/main/resources/contents/images/stamina_1.yml index 3248246..2438885 100644 --- a/backend/src/main/resources/contents/images/stamina_1.yml +++ b/backend/src/main/resources/contents/images/stamina_1.yml @@ -1,3 +1,4 @@ image: stamina_1 height: 9 -ascent: -16 \ No newline at end of file +ascent: -16 +shadow: false \ No newline at end of file diff --git a/backend/src/main/resources/contents/images/stamina_2.yml b/backend/src/main/resources/contents/images/stamina_2.yml index 9a0545d..4f8bea0 100644 --- a/backend/src/main/resources/contents/images/stamina_2.yml +++ b/backend/src/main/resources/contents/images/stamina_2.yml @@ -1,3 +1,4 @@ image: stamina_2 height: 9 -ascent: -16 \ No newline at end of file +ascent: -16 +shadow: false \ No newline at end of file diff --git a/backend/src/main/resources/contents/images/weather.yml b/backend/src/main/resources/contents/images/weather.yml index b25b0d0..1691581 100644 --- a/backend/src/main/resources/contents/images/weather.yml +++ b/backend/src/main/resources/contents/images/weather.yml @@ -1,3 +1,4 @@ image: weather height: 10 -ascent: 4 \ No newline at end of file +ascent: 4 +shadow: false \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index f05427f..a72087f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ # Project settings # Rule: [major update].[feature update].[bug fix] -project_version=3.0.7.1 +project_version=3.0.8 config_version=32 project_group=net.momirealms