@@ -1,3 +1,8 @@ | |||
VERSION 1.1 | |||
1. Update to GWMLibrary 2.2 | |||
2. Add 'PER_PARTICLE_COLOR' parameter to 'HELIX', 'GLOBE', 'CIRCLE' and 'BLOCK-HIGHLIGHT' Cosmetic Effects | |||
3. Add 'COLOR' parameter to 'GLOBE', 'CIRCLE' and 'BLOCK-HIGHLIGHT' Cosmetic Effects | |||
VERSION 1.0.1 | |||
* Fix 'CIRCLE' Cosmetic Effect | |||
@@ -6,7 +6,7 @@ | |||
<groupId>dev.gwm.spongeplugin</groupId> | |||
<artifactId>cosmetics</artifactId> | |||
<version>1.0.1</version> | |||
<version>1.1</version> | |||
<name>Cosmetics</name> | |||
<packaging>jar</packaging> | |||
@@ -35,7 +35,7 @@ import java.util.concurrent.atomic.AtomicInteger; | |||
@Plugin(id = "cosmetics", | |||
name = "Cosmetics", | |||
version = "1.0.1", | |||
version = "1.1", | |||
description = "Fancy cosmetic effects", | |||
authors = {"GWM"/* My contacts: | |||
* E-Mail(nazark@tutanota.com), | |||
@@ -46,7 +46,7 @@ import java.util.concurrent.atomic.AtomicInteger; | |||
}) | |||
public class Cosmetics extends SpongePlugin { | |||
public static final Version VERSION = new Version(null, 1, 0, 1); | |||
public static final Version VERSION = new Version(null, 1, 1); | |||
private static Cosmetics instance = null; | |||
@@ -1,11 +1,16 @@ | |||
package dev.gwm.spongeplugin.cosmetics.superobject.effect; | |||
import com.flowpowered.math.vector.Vector3d; | |||
import com.google.common.reflect.TypeToken; | |||
import dev.gwm.spongeplugin.cosmetics.superobject.effect.base.AbstractCosmeticEffect; | |||
import dev.gwm.spongeplugin.cosmetics.utils.CosmeticsUtils; | |||
import dev.gwm.spongeplugin.library.exception.SuperObjectConstructionException; | |||
import ninja.leaping.configurate.ConfigurationNode; | |||
import org.spongepowered.api.effect.Viewer; | |||
import org.spongepowered.api.effect.particle.ParticleEffect; | |||
import org.spongepowered.api.effect.particle.ParticleOptions; | |||
import org.spongepowered.api.effect.particle.ParticleTypes; | |||
import org.spongepowered.api.util.Color; | |||
import org.spongepowered.api.world.Locatable; | |||
import java.util.Optional; | |||
@@ -14,13 +19,31 @@ public class BlockHighlightCosmeticEffect extends AbstractCosmeticEffect { | |||
public static final String TYPE = "BLOCK-HIGHLIGHT"; | |||
private final Optional<Color> color; | |||
private final boolean perParticleColor; | |||
public BlockHighlightCosmeticEffect(ConfigurationNode node) { | |||
super(node); | |||
try { | |||
ConfigurationNode colorNode = node.getNode("COLOR"); | |||
ConfigurationNode perParticleColorNode = node.getNode("PER_PARTICLE_COLOR"); | |||
if (colorNode.isVirtual()) { | |||
color = Optional.empty(); | |||
} else { | |||
color = Optional.of(colorNode.getValue(TypeToken.of(Color.class))); | |||
} | |||
perParticleColor = perParticleColorNode.getBoolean(false); | |||
} catch (Exception e) { | |||
throw new SuperObjectConstructionException(category(), type(), e); | |||
} | |||
} | |||
public BlockHighlightCosmeticEffect(Optional<String> id, | |||
Optional<Long> delay, Optional<Vector3d> defaultOffset) { | |||
public BlockHighlightCosmeticEffect(String id, | |||
Optional<Long> delay, Optional<Vector3d> defaultOffset, | |||
Optional<Color> color, boolean perParticleColor) { | |||
super(id, delay, defaultOffset); | |||
this.color = color; | |||
this.perParticleColor = perParticleColor; | |||
} | |||
@Override | |||
@@ -35,19 +58,26 @@ public class BlockHighlightCosmeticEffect extends AbstractCosmeticEffect { | |||
private final class EffectRunnable extends AbstractEffectRunnable { | |||
private ParticleEffect effect = ParticleEffect.builder().type(ParticleTypes.REDSTONE_DUST).build(); | |||
private EffectRunnable(Viewer viewer, Locatable locatable, Vector3d offset) { | |||
super(viewer, locatable, offset); | |||
} | |||
@Override | |||
public void run() { | |||
Vector3d position = getPosition(); | |||
Color particleColor = color.orElse(CosmeticsUtils.getRandomColor()); | |||
for (double x = 0; x <= 1; x += 0.2) { | |||
for (double z = 0; z <= 1; z += 0.2) { | |||
for (double y = 1; y >= 0; y -= 0.2) { | |||
if (x == 0 || x == 1 || z == 0 || z == 1 || y == 1 || y == 0) { //Only borders, not insides | |||
getViewer().spawnParticles(effect, getPosition().add(x, y, z)); | |||
if (perParticleColor) { | |||
particleColor = CosmeticsUtils.getRandomColor(); | |||
} | |||
getViewer().spawnParticles( | |||
ParticleEffect.builder().type(ParticleTypes.REDSTONE_DUST). | |||
option(ParticleOptions.COLOR, particleColor). | |||
build(), | |||
position.add(x, y, z)); | |||
} | |||
} | |||
} | |||
@@ -1,12 +1,16 @@ | |||
package dev.gwm.spongeplugin.cosmetics.superobject.effect; | |||
import com.flowpowered.math.vector.Vector3d; | |||
import com.google.common.reflect.TypeToken; | |||
import dev.gwm.spongeplugin.cosmetics.superobject.effect.base.AbstractCosmeticEffect; | |||
import dev.gwm.spongeplugin.cosmetics.utils.CosmeticsUtils; | |||
import dev.gwm.spongeplugin.library.exception.SuperObjectConstructionException; | |||
import ninja.leaping.configurate.ConfigurationNode; | |||
import org.spongepowered.api.effect.Viewer; | |||
import org.spongepowered.api.effect.particle.ParticleEffect; | |||
import org.spongepowered.api.effect.particle.ParticleOptions; | |||
import org.spongepowered.api.effect.particle.ParticleTypes; | |||
import org.spongepowered.api.util.Color; | |||
import org.spongepowered.api.world.Locatable; | |||
import java.util.Optional; | |||
@@ -15,6 +19,8 @@ public class CircleCosmeticEffect extends AbstractCosmeticEffect { | |||
public static final String TYPE = "CIRCLE"; | |||
private final Optional<Color> color; | |||
private final boolean perParticleColor; | |||
private final double radius; | |||
private final double step; | |||
private final int stepsPerAnimation; | |||
@@ -22,9 +28,17 @@ public class CircleCosmeticEffect extends AbstractCosmeticEffect { | |||
public CircleCosmeticEffect(ConfigurationNode node) { | |||
super(node); | |||
try { | |||
ConfigurationNode colorNode = node.getNode("COLOR"); | |||
ConfigurationNode perParticleColorNode = node.getNode("PER_PARTICLE_COLOR"); | |||
ConfigurationNode radiusNode = node.getNode("RADIUS"); | |||
ConfigurationNode stepNode = node.getNode("STEP"); | |||
ConfigurationNode stepsPerAnimationNode = node.getNode("STEPS_PER_ANIMATION"); | |||
if (colorNode.isVirtual()) { | |||
color = Optional.empty(); | |||
} else { | |||
color = Optional.of(colorNode.getValue(TypeToken.of(Color.class))); | |||
} | |||
perParticleColor = perParticleColorNode.getBoolean(false); | |||
if (!radiusNode.isVirtual()) { | |||
radius = radiusNode.getDouble(); | |||
} else { | |||
@@ -54,10 +68,13 @@ public class CircleCosmeticEffect extends AbstractCosmeticEffect { | |||
} | |||
} | |||
public CircleCosmeticEffect(Optional<String> id, | |||
public CircleCosmeticEffect(String id, | |||
Optional<Long> delay, Optional<Vector3d> defaultOffset, | |||
Optional<Color> color, boolean perParticleColor, | |||
double radius, double step, int stepsPerAnimation) { | |||
super(id, delay, defaultOffset); | |||
this.color = color; | |||
this.perParticleColor = perParticleColor; | |||
if (radius <= 0) { | |||
throw new IllegalArgumentException("Radius is equal to or less than 0!"); | |||
} | |||
@@ -82,9 +99,27 @@ public class CircleCosmeticEffect extends AbstractCosmeticEffect { | |||
return new EffectRunnable(viewer, locatable, offset); | |||
} | |||
private final class EffectRunnable extends AbstractEffectRunnable { | |||
public Optional<Color> getColor() { | |||
return color; | |||
} | |||
public boolean isPerParticleColor() { | |||
return perParticleColor; | |||
} | |||
public double getRadius() { | |||
return radius; | |||
} | |||
public double getStep() { | |||
return step; | |||
} | |||
private final ParticleEffect effect = ParticleEffect.builder().type(ParticleTypes.REDSTONE_DUST).build(); | |||
public int getStepsPerAnimation() { | |||
return stepsPerAnimation; | |||
} | |||
private final class EffectRunnable extends AbstractEffectRunnable { | |||
private final double d = Math.PI - 2 * Math.acos(step / (2 * radius)); | |||
private final double l = (2 * Math.PI) / d; | |||
@@ -96,15 +131,24 @@ public class CircleCosmeticEffect extends AbstractCosmeticEffect { | |||
@Override | |||
public void run() { | |||
Vector3d position = getPosition(); | |||
Color particleColor = color.orElse(CosmeticsUtils.getRandomColor()); | |||
for (int j = 0; j < stepsPerAnimation; j++) { | |||
if (perParticleColor) { | |||
particleColor = CosmeticsUtils.getRandomColor(); | |||
} | |||
if (i > l) { | |||
i = 0; | |||
} | |||
final double x = getPosition().getX(); | |||
final double z = getPosition().getZ(); | |||
final double x = position.getX(); | |||
final double z = position.getZ(); | |||
double xOffset = radius * Math.cos(i * d); | |||
double zOffset = radius * Math.sin(i * d); | |||
getViewer().spawnParticles(effect, getPosition().add(new Vector3d(xOffset, 0, zOffset))); | |||
getViewer().spawnParticles( | |||
ParticleEffect.builder().type(ParticleTypes.REDSTONE_DUST). | |||
option(ParticleOptions.COLOR, particleColor). | |||
build(), | |||
position.add(new Vector3d(xOffset, 0, zOffset))); | |||
i++; | |||
} | |||
} | |||
@@ -1,11 +1,16 @@ | |||
package dev.gwm.spongeplugin.cosmetics.superobject.effect; | |||
import com.flowpowered.math.vector.Vector3d; | |||
import com.google.common.reflect.TypeToken; | |||
import dev.gwm.spongeplugin.cosmetics.superobject.effect.base.AbstractCosmeticEffect; | |||
import dev.gwm.spongeplugin.cosmetics.utils.CosmeticsUtils; | |||
import dev.gwm.spongeplugin.library.exception.SuperObjectConstructionException; | |||
import ninja.leaping.configurate.ConfigurationNode; | |||
import org.spongepowered.api.effect.Viewer; | |||
import org.spongepowered.api.effect.particle.ParticleEffect; | |||
import org.spongepowered.api.effect.particle.ParticleOptions; | |||
import org.spongepowered.api.effect.particle.ParticleTypes; | |||
import org.spongepowered.api.util.Color; | |||
import org.spongepowered.api.world.Locatable; | |||
import java.util.Optional; | |||
@@ -14,13 +19,31 @@ public final class GlobeCosmeticEffect extends AbstractCosmeticEffect { | |||
public static final String TYPE = "GLOBE"; | |||
private final Optional<Color> color; | |||
private final boolean perParticleColor; | |||
public GlobeCosmeticEffect(ConfigurationNode node) { | |||
super(node); | |||
try { | |||
ConfigurationNode colorNode = node.getNode("COLOR"); | |||
ConfigurationNode perParticleColorNode = node.getNode("PER_PARTICLE_COLOR"); | |||
if (colorNode.isVirtual()) { | |||
color = Optional.empty(); | |||
} else { | |||
color = Optional.of(colorNode.getValue(TypeToken.of(Color.class))); | |||
} | |||
perParticleColor = perParticleColorNode.getBoolean(false); | |||
} catch (Exception e) { | |||
throw new SuperObjectConstructionException(category(), type(), e); | |||
} | |||
} | |||
public GlobeCosmeticEffect(Optional<String> id, | |||
Optional<Long> delay, Optional<Vector3d> defaultOffset) { | |||
public GlobeCosmeticEffect(String id, | |||
Optional<Long> delay, Optional<Vector3d> defaultOffset, | |||
Optional<Color> color, boolean perParticleColor) { | |||
super(id, delay, defaultOffset); | |||
this.color = color; | |||
this.perParticleColor = perParticleColor; | |||
} | |||
@Override | |||
@@ -33,9 +56,15 @@ public final class GlobeCosmeticEffect extends AbstractCosmeticEffect { | |||
return new EffectRunnable(viewer, locatable, offset); | |||
} | |||
private final class EffectRunnable extends AbstractEffectRunnable { | |||
public Optional<Color> getColor() { | |||
return color; | |||
} | |||
public boolean isPerParticleColor() { | |||
return perParticleColor; | |||
} | |||
private final ParticleEffect effect = ParticleEffect.builder().type(ParticleTypes.REDSTONE_DUST).build(); | |||
private final class EffectRunnable extends AbstractEffectRunnable { | |||
private double phi = 0; | |||
@@ -51,12 +80,20 @@ public final class GlobeCosmeticEffect extends AbstractCosmeticEffect { | |||
phi = 0; | |||
} | |||
Vector3d position = getPosition(); | |||
Color particleColor = color.orElse(CosmeticsUtils.getRandomColor()); | |||
for (double theta = 0; theta <= 2 * Math.PI; theta += Math.PI / 40) { | |||
if (perParticleColor) { | |||
particleColor = CosmeticsUtils.getRandomColor(); | |||
} | |||
double r = 1.5; | |||
double x = r * Math.cos(theta) * Math.sin(phi); | |||
double y = r * Math.cos(phi) + 1.5; | |||
double z = r * Math.sin(theta) * Math.sin(phi); | |||
getViewer().spawnParticles(effect, position.add(x, y, z)); | |||
getViewer().spawnParticles( | |||
ParticleEffect.builder().type(ParticleTypes.REDSTONE_DUST). | |||
option(ParticleOptions.COLOR, particleColor). | |||
build(), | |||
position.add(x, y, z)); | |||
} | |||
} | |||
} | |||
@@ -3,6 +3,7 @@ package dev.gwm.spongeplugin.cosmetics.superobject.effect; | |||
import com.flowpowered.math.vector.Vector3d; | |||
import com.google.common.reflect.TypeToken; | |||
import dev.gwm.spongeplugin.cosmetics.superobject.effect.base.AbstractCosmeticEffect; | |||
import dev.gwm.spongeplugin.cosmetics.utils.CosmeticsUtils; | |||
import dev.gwm.spongeplugin.library.exception.SuperObjectConstructionException; | |||
import ninja.leaping.configurate.ConfigurationNode; | |||
import org.spongepowered.api.effect.Viewer; | |||
@@ -13,33 +14,36 @@ import org.spongepowered.api.util.Color; | |||
import org.spongepowered.api.world.Locatable; | |||
import java.util.Optional; | |||
import java.util.concurrent.ThreadLocalRandom; | |||
public class HelixCosmeticEffect extends AbstractCosmeticEffect { | |||
public static final String TYPE = "HELIX"; | |||
private final Optional<Color> color; | |||
private final boolean perParticleColor; | |||
public HelixCosmeticEffect(ConfigurationNode node) { | |||
super(node); | |||
try { | |||
ConfigurationNode colorNode = node.getNode("COLOR"); | |||
ConfigurationNode perParticleColorNode = node.getNode("PER_PARTICLE_COLOR"); | |||
if (colorNode.isVirtual()) { | |||
color = Optional.empty(); | |||
} else { | |||
color = Optional.of(colorNode.getValue(TypeToken.of(Color.class))); | |||
} | |||
perParticleColor = perParticleColorNode.getBoolean(false); | |||
} catch (Exception e) { | |||
throw new SuperObjectConstructionException(category(), type(), e); | |||
} | |||
} | |||
public HelixCosmeticEffect(Optional<String> id, | |||
public HelixCosmeticEffect(String id, | |||
Optional<Long> delay, Optional<Vector3d> defaultOffset, | |||
Optional<Color> color) { | |||
Optional<Color> color, boolean perParticleColor) { | |||
super(id, delay, defaultOffset); | |||
this.color = color; | |||
this.perParticleColor = perParticleColor; | |||
} | |||
@Override | |||
@@ -56,6 +60,10 @@ public class HelixCosmeticEffect extends AbstractCosmeticEffect { | |||
return color; | |||
} | |||
public boolean isPerParticleColor() { | |||
return perParticleColor; | |||
} | |||
private final class EffectRunnable extends AbstractEffectRunnable { | |||
private double phi = 0; | |||
@@ -72,17 +80,19 @@ public class HelixCosmeticEffect extends AbstractCosmeticEffect { | |||
} | |||
Vector3d position = getPosition(); | |||
double x, y, z; | |||
ThreadLocalRandom random = ThreadLocalRandom.current(); | |||
Color particleColor = getColor(). | |||
orElse(Color.ofRgb(random.nextInt(256), random.nextInt(256), random.nextInt(256))); | |||
Color particleColor = color.orElse(CosmeticsUtils.getRandomColor()); | |||
for (double t = 0; t <= 2 * Math.PI; t = t + Math.PI / 16) { | |||
for (double i = 0; i <= 1; i = i + 1) { | |||
if (perParticleColor) { | |||
particleColor = CosmeticsUtils.getRandomColor(); | |||
} | |||
x = 0.15 * (2 * Math.PI - t) * Math.cos(t + phi + i * Math.PI); | |||
y = 0.5 * t; | |||
z = 0.15 * (2 * Math.PI - t) * Math.sin(t + phi + i * Math.PI); | |||
getViewer().spawnParticles( | |||
ParticleEffect.builder().type(ParticleTypes.REDSTONE_DUST) | |||
.option(ParticleOptions.COLOR, particleColor).build(), | |||
ParticleEffect.builder().type(ParticleTypes.REDSTONE_DUST). | |||
option(ParticleOptions.COLOR, particleColor). | |||
build(), | |||
position.add(x, y, z)); | |||
} | |||
} | |||
@@ -20,9 +20,6 @@ public abstract class AbstractCosmeticEffect extends AbstractSuperObject impleme | |||
public AbstractCosmeticEffect(ConfigurationNode node) { | |||
super(node); | |||
try { | |||
if (!id().isPresent()) { | |||
throw new RuntimeException("The Cosmetic Particle Effect does not have an ID!"); | |||
} | |||
ConfigurationNode delayNode = node.getNode("DELAY"); | |||
ConfigurationNode offsetNode = node.getNode("OFFSET"); | |||
if (delayNode.isVirtual()) { | |||
@@ -43,12 +40,9 @@ public abstract class AbstractCosmeticEffect extends AbstractSuperObject impleme | |||
} | |||
} | |||
public AbstractCosmeticEffect(Optional<String> id, | |||
public AbstractCosmeticEffect(String id, | |||
Optional<Long> delay, Optional<Vector3d> offset) { | |||
super(id); | |||
if (!id().isPresent()) { | |||
throw new RuntimeException("The Cosmetic Particle Effect does not have an ID!"); | |||
} | |||
if (delay.isPresent() && delay.get() <= 0) { | |||
throw new IllegalArgumentException("Delay is equal to or less than 0!"); | |||
} | |||
@@ -57,10 +57,6 @@ public interface CosmeticEffect extends SuperObject { | |||
Runnable createTask(Viewer viewer, Locatable locatable, Vector3d offset); | |||
default String getId() { | |||
return id().get(); | |||
} | |||
default long getDelay() { | |||
return defaultDelay(); | |||
} | |||
@@ -6,22 +6,24 @@ import dev.gwm.spongeplugin.library.utils.Config; | |||
import dev.gwm.spongeplugin.library.utils.SuperObjectsService; | |||
import ninja.leaping.configurate.ConfigurationNode; | |||
import org.spongepowered.api.Sponge; | |||
import org.spongepowered.api.util.Color; | |||
import java.io.File; | |||
import java.nio.file.Path; | |||
import java.util.concurrent.ThreadLocalRandom; | |||
public class CosmeticsUtils { | |||
public static boolean loadCosmeticEffect(File file, boolean force) { | |||
try { | |||
Config cpeConfig = new Config(Cosmetics.getInstance(), file); | |||
ConfigurationNode loadNode = cpeConfig.getNode("LOAD"); | |||
Config cosmeticEffectConfig = new Config(Cosmetics.getInstance(), file); | |||
ConfigurationNode loadNode = cosmeticEffectConfig.getNode("LOAD"); | |||
if (force || loadNode.getBoolean(true)) { | |||
CosmeticEffect cpe = Sponge.getServiceManager().provide(SuperObjectsService.class).get(). | |||
create(CosmeticsSuperObjectCategories.COSMETIC_EFFECT, cpeConfig.getNode()); | |||
CosmeticEffect cosmeticEffect = Sponge.getServiceManager().provide(SuperObjectsService.class).get(). | |||
create(CosmeticsSuperObjectCategories.COSMETIC_EFFECT, cosmeticEffectConfig.getNode()); | |||
if (Cosmetics.getInstance().isLogLoadedEffects()) { | |||
Cosmetics.getInstance().getLogger(). | |||
info("Loaded the Cosmetic Effect from the file \"" + getCosmeticEffectRelativePath(file) + "\" with id \"" + cpe.getId() + "\"!"); | |||
info("Loaded the Cosmetic Effect from the file \"" + getCosmeticEffectRelativePath(file) + "\" with id \"" + cosmeticEffect.id() + "\"!"); | |||
} | |||
return true; | |||
} else { | |||
@@ -37,4 +39,9 @@ public class CosmeticsUtils { | |||
public static Path getCosmeticEffectRelativePath(File cosmeticEffectFile) { | |||
return Cosmetics.getInstance().getEffectsDirectory().toPath().relativize(cosmeticEffectFile.toPath()); | |||
} | |||
public static Color getRandomColor() { | |||
ThreadLocalRandom random = ThreadLocalRandom.current(); | |||
return Color.ofRgb(random.nextInt(256), random.nextInt(256), random.nextInt(256)); | |||
} | |||
} |