Color fading for Cauldron Particles

This commit is contained in:
Sn0wStorm 2020-11-07 22:37:32 +01:00
parent 29830e0405
commit db1a425215
4 changed files with 193 additions and 17 deletions

View File

@ -6,6 +6,8 @@ import com.dre.brewery.recipe.BCauldronRecipe;
import com.dre.brewery.recipe.RecipeItem;
import com.dre.brewery.utility.BUtil;
import com.dre.brewery.utility.LegacyUtil;
import com.dre.brewery.utility.Tuple;
import org.bukkit.Color;
import org.bukkit.Effect;
import org.bukkit.Location;
import org.bukkit.Material;
@ -19,6 +21,7 @@ import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
@ -32,17 +35,17 @@ public class BCauldron {
private static Set<UUID> plInteracted = new HashSet<>(); // Interact Event helper
public static Map<Block, BCauldron> bcauldrons = new HashMap<>(); // All active cauldrons. Mapped to their block for fast retrieve
public static Particle particle = Particle.CLOUD;
private BIngredients ingredients = new BIngredients();
private final Block block;
private int state = 0;
private boolean changed = false;
private Optional<BCauldronRecipe> particleRecipe; // null if we haven't checked, empty if there is none
private Color particleColor;
private Location particleLocation;
public BCauldron(Block block) {
this.block = block;
particleLocation = block.getLocation().add(0.5, 0.8, 0.5);
particleLocation = block.getLocation().add(0.5, 0.9, 0.5);
}
// loading from file
@ -50,7 +53,7 @@ public class BCauldron {
this.block = block;
this.state = state;
this.ingredients = ingredients;
particleLocation = block.getLocation().add(0.5, 0.8, 0.5);
particleLocation = block.getLocation().add(0.5, 0.9, 0.5);
}
/**
@ -84,6 +87,7 @@ public class BCauldron {
ingredients = ingredients.copy();
changed = false;
}
particleColor = null;
}
// add an ingredient to the cauldron
@ -94,6 +98,8 @@ public class BCauldron {
changed = false;
}
particleRecipe = null;
particleColor = null;
ingredients.add(ingredient, rItem);
block.getWorld().playEffect(block.getLocation(), Effect.EXTINGUISH, 0);
if (state > 0) {
@ -233,18 +239,28 @@ public class BCauldron {
public void cookEffect() {
if (BUtil.isChunkLoaded(block) && LegacyUtil.isCauldronHeatsource(block.getRelative(BlockFace.DOWN))) {
if (particleRandom.nextFloat() > 0.75) {
// Pixely cloud at 0.4 random in x and z
// 0 count enables direction, send to y = 1 with speed 0.07
block.getWorld().spawnParticle(Particle.CLOUD, getRandParticleLoc(), 0, 0, 1, 0, 0.07);
if (particleRandom.nextFloat() > 0.85) {
// Dark pixely smoke cloud at 0.4 random in x and z
// 0 count enables direction, send to y = 1 with speed 0.09
block.getWorld().spawnParticle(Particle.SMOKE_LARGE, getRandParticleLoc(), 0, 0, 1, 0, 0.09);
}
if (particleRandom.nextFloat() > 0.2) {
// A Water Splash with 0.2 offset in x and z
block.getWorld().spawnParticle(Particle.WATER_SPLASH, particleLocation, 1, 0.2, 0, 0.2);
}
Color color = getParticleColor();
// Colorable spirally spell, 0 count enables color instead of the offset variables
// Configurable RGB color. 1025 seems to be the best for color brightness and upwards motion
block.getWorld().spawnParticle(Particle.SPELL_MOB, getRandParticleLoc(), 0, 180.0/255.0, 40.0/255.0, 1.0/255.0, 1025.0);
block.getWorld().spawnParticle(Particle.SPELL_MOB, getRandParticleLoc(), 0,
((double) color.getRed()) / 255.0,
((double) color.getGreen()) / 255.0,
((double) color.getBlue()) / 255.0,
1025.0);
if (particleRandom.nextFloat() > 0.4) {
// Two hovering pixely dust clouds, a bit offset with DustOptions to give some color and size
block.getWorld().spawnParticle(Particle.REDSTONE, particleLocation, 2, 0.15, 0.2, 0.15, new Particle.DustOptions(color, 1.5f));
}
}
}
@ -255,7 +271,82 @@ public class BCauldron {
particleLocation.getZ() + (particleRandom.nextDouble() * 0.8) - 0.4);
}
public static void cookEffects() {
/**
* Get or calculate the particle color from the current best Cauldron Recipe
* Also calculates the best Cauldron Recipe if not yet done
*
* @return the Particle Color, after potentially calculating it
*/
@NotNull
public Color getParticleColor() {
if (state < 1) {
return Color.fromRGB(153, 221, 255); // Bright Blue
}
if (particleColor != null) {
return particleColor;
}
if (particleRecipe == null) {
// Check for Cauldron Recipe
particleRecipe = Optional.ofNullable(ingredients.getCauldronRecipe());
}
List<Tuple<Integer, Color>> colorList = null;
if (particleRecipe.isPresent()) {
colorList = particleRecipe.get().getParticleColor();
}
if (colorList == null || colorList.isEmpty()) {
// No color List configured, or no recipe found
colorList = new ArrayList<>(1);
colorList.add(new Tuple<>(10, Color.fromRGB(77, 166, 255))); // Dark Aqua kind of Blue
}
int index = 0;
while (index < colorList.size() - 1 && colorList.get(index).a() < state) {
// Find the first index where the colorList Minute is higher than the state
index++;
}
int minute = colorList.get(index).a();
if (minute > state) {
// going towards the minute
int prevPos;
Color prevColor;
if (index > 0) {
// has previous colours
prevPos = colorList.get(index - 1).a();
prevColor = colorList.get(index - 1).b();
} else {
prevPos = 0;
prevColor = Color.fromRGB(153, 221, 255); // Bright Blue
}
particleColor = BUtil.weightedMixColor(prevColor, prevPos, state, colorList.get(index).b(), minute);
} else if (minute == state) {
// reached the minute
particleColor = colorList.get(index).b();
} else {
// passed the last minute configured
if (index > 0) {
// We have more than one color, just use the last one
particleColor = colorList.get(index).b();
} else {
// Only have one color, go towards a Gray
Color nextColor = Color.fromRGB(138, 153, 168); // Dark Teal, Gray
int nextPos = (int) (minute * 2.6f);
if (nextPos <= state) {
// We are past the next color (Gray) as well, keep using it
particleColor = nextColor;
} else {
particleColor = BUtil.weightedMixColor(colorList.get(index).b(), minute, state, nextColor, nextPos);
}
}
}
//P.p.log("RGB: " + particleColor.getRed() + "|" + particleColor.getGreen() + "|" + particleColor.getBlue());
return particleColor;
}
public static void processNextCookEffects() {
if (!BConfig.enableCauldronParticles) return;
int size = bcauldrons.size();
if (size <= 0) {
@ -422,6 +513,21 @@ public class BCauldron {
}
}
/**
* Recalculate the Cauldron Particle Recipe
*/
public static void reload() {
for (BCauldron cauldron : BCauldron.bcauldrons.values()) {
cauldron.particleRecipe = null;
cauldron.particleColor = null;
if (BConfig.enableCauldronParticles) {
if (BUtil.isChunkLoaded(cauldron.block) && LegacyUtil.isCauldronHeatsource(cauldron.block.getRelative(BlockFace.DOWN))) {
cauldron.getParticleColor();
}
}
}
}
/**
* reset to normal cauldron
*/

View File

@ -198,6 +198,9 @@ public class P extends JavaPlugin {
return;
}
// Reload Cauldron Particle Recipes
BCauldron.reload();
// Reload Recipes
boolean successful = true;
for (Brew brew : Brew.legacyPotions.values()) {
@ -485,7 +488,7 @@ public class P extends JavaPlugin {
public class CauldronParticles implements Runnable {
@Override
public void run() {
BCauldron.cookEffects();
BCauldron.processNextCookEffects();
}
}

View File

@ -9,11 +9,7 @@ import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
import java.util.*;
import java.util.stream.Collectors;
/**
@ -28,8 +24,8 @@ public class BCauldronRecipe {
private String name;
private List<RecipeItem> ingredients;
//private List<String> particles
private PotionColor color;
private List<Tuple<Integer, Color>> particleColor = new ArrayList<>();
private List<String> lore;
private int cmData; // Custom Model Data
private boolean saveInData; // If this recipe should be saved in data and loaded again when the server restarts. Applicable to non-config recipes
@ -78,6 +74,33 @@ public class BCauldronRecipe {
//return null;
}
for (String entry : cfg.getStringList(id + ".cookParticles")) {
String[] split = entry.split("/");
int minute;
if (split.length == 1) {
minute = 10;
} else if (split.length == 2) {
minute = P.p.parseInt(split[1]);
} else {
P.p.errorLog("cookParticle: '" + entry + "' in: " + recipe.name);
return null;
}
if (minute < 1) {
P.p.errorLog("cookParticle: '" + entry + "' in: " + recipe.name);
return null;
}
PotionColor partCol = PotionColor.fromString(split[0]);
if (partCol == PotionColor.WATER && !split[0].equals("WATER")) {
P.p.errorLog("Color of cookParticle: '" + entry + "' in: " + recipe.name);
return null;
}
recipe.particleColor.add(new Tuple<>(minute, partCol.getColor()));
}
if (!recipe.particleColor.isEmpty()) {
// Sort by minute
recipe.particleColor.sort(Comparator.comparing(Tuple::first));
}
List<Tuple<Integer,String>> lore = BRecipe.loadLore(cfg, id + ".lore");
if (lore != null && !lore.isEmpty()) {
@ -107,6 +130,11 @@ public class BCauldronRecipe {
return color;
}
@NotNull
public List<Tuple<Integer, Color>> getParticleColor() {
return particleColor;
}
@Nullable
public List<String> getLore() {
return lore;
@ -337,6 +365,11 @@ public class BCauldronRecipe {
return this;
}
public Builder addParticleColor(int atMinute, Color color) {
recipe.particleColor.add(new Tuple<>(atMinute, color));
return this;
}
public Builder addLore(String line) {
if (recipe.lore == null) {
recipe.lore = new ArrayList<>();
@ -358,6 +391,10 @@ public class BCauldronRecipe {
if (recipe.ingredients == null || recipe.ingredients.isEmpty()) {
throw new IllegalArgumentException("CauldronRecipe has no ingredients");
}
if (!recipe.particleColor.isEmpty()) {
// Sort particleColor by minute
recipe.particleColor.sort(Comparator.comparing(Tuple::first));
}
return recipe;
}
}

View File

@ -6,6 +6,7 @@ import com.dre.brewery.P;
import com.dre.brewery.api.events.barrel.BarrelDestroyEvent;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Color;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
@ -48,6 +49,35 @@ public class BUtil {
return msg;
}
/**
* Creates a weighted mix between the two given colours
* <p>where the weight is calculated from the distance of the currentPos to the prev and next
*
* @param prevColor Previous Color
* @param prevPos Position of the Previous Color
* @param currentPos Current Position
* @param nextColor Next Color
* @param nextPos Position of the Next Color
* @return
*/
public static Color weightedMixColor(Color prevColor, int prevPos, int currentPos, Color nextColor, int nextPos) {
float diffPrev = currentPos - prevPos;
float diffNext = nextPos - currentPos;
float total = diffNext + diffPrev;
float percentNext = diffPrev / total;
float percentPrev = diffNext / total;
/*5 #8# 15
8-5 = 3 -> 3/10
15-8 = 7 -> 7/10*/
return Color.fromRGB(
Math.min(255, (int) ((nextColor.getRed() * percentNext) + (prevColor.getRed() * percentPrev))),
Math.min(255, (int) ((nextColor.getGreen() * percentNext) + (prevColor.getGreen() * percentPrev))),
Math.min(255, (int) ((nextColor.getBlue() * percentNext) + (prevColor.getBlue() * percentPrev)))
);
}
/**
* Returns either uuid or Name of player, depending on bukkit version
*/