Skip to content

Instantly share code, notes, and snippets.

@aikar
Created November 8, 2016 18:23
Show Gist options
  • Save aikar/903589f3843e82c2444cddd690d18b96 to your computer and use it in GitHub Desktop.
Save aikar/903589f3843e82c2444cddd690d18b96 to your computer and use it in GitHub Desktop.
/*
* Copyright (c) 2016. Starlis LLC / dba Empire Minecraft
*
* This source code is proprietary software and must not be redistributed without Starlis LLC's approval
*
*/
package com.empireminecraft.features.specialevents;
import co.aikar.timings.Timing;
import com.destroystokyo.paper.event.entity.EntityPathfindEvent;
import com.empireminecraft.Empire;
import com.empireminecraft.Identifier;
import com.empireminecraft.Worlds;
import com.empireminecraft.commands.EmpireCommand;
import com.empireminecraft.commands.annotation.CommandAlias;
import com.empireminecraft.commands.annotation.Default;
import com.empireminecraft.commands.annotation.Subcommand;
import com.empireminecraft.config.EmpireServer;
import com.empireminecraft.config.meta.EmpireMetaKey;
import com.empireminecraft.config.meta.PersistentMetaKey;
import com.empireminecraft.config.typemap.RupeeTransType;
import com.empireminecraft.entityai.EntityAIApi;
import com.empireminecraft.features.items.CustomItems;
import com.empireminecraft.features.items.UsableItem;
import com.empireminecraft.features.survival.LootPool;
import com.empireminecraft.features.survival.SurvivalItemDrops;
import com.empireminecraft.items.PromoItems;
import com.empireminecraft.metaapi.MetaApi;
import com.empireminecraft.systems.EmpireChat;
import com.empireminecraft.systems.Formatting;
import com.empireminecraft.systems.chat.Chat;
import com.empireminecraft.systems.chat.ChatChannel;
import com.empireminecraft.systems.currency.Rupees;
import com.empireminecraft.systems.db.DbRow;
import com.empireminecraft.systems.db.EmpireDb;
import com.empireminecraft.systems.residence.protection.CuboidArea;
import com.empireminecraft.systems.residence.protection.Residence;
import com.empireminecraft.systems.residence.protection.ResidenceManager;
import com.empireminecraft.user.EmpireGroup;
import com.empireminecraft.user.EmpireUser;
import com.empireminecraft.user.meta.EmpireCustomMeta;
import com.empireminecraft.user.meta.EmpireCustomMetaKey;
import com.empireminecraft.user.meta.EmpireMetaNumberSerializer;
import com.empireminecraft.user.meta.LongSetMetaSerializer;
import com.empireminecraft.util.BlockUtil;
import com.empireminecraft.util.BukkitUtil;
import com.empireminecraft.util.BukkitUtil.Listener;
import com.empireminecraft.util.NumUtil;
import com.empireminecraft.util.TimeUtil;
import com.empireminecraft.util.UserUtil;
import com.empireminecraft.util.Util;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.Color;
import org.bukkit.FireworkEffect;
import org.bukkit.FireworkEffect.Type;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.entity.Bat;
import org.bukkit.entity.Creature;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Fireball;
import org.bukkit.entity.Firework;
import org.bukkit.entity.Ghast;
import org.bukkit.entity.Item;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.entity.Villager;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.event.entity.ItemMergeEvent;
import org.bukkit.event.entity.ProjectileLaunchEvent;
import org.bukkit.event.player.PlayerDropItemEvent;
import org.bukkit.event.player.PlayerPickupItemEvent;
import org.bukkit.event.weather.WeatherChangeEvent;
import org.bukkit.event.world.ChunkLoadEvent;
import org.bukkit.event.world.ChunkUnloadEvent;
import org.bukkit.event.world.WorldLoadEvent;
import org.bukkit.event.world.WorldUnloadEvent;
import org.bukkit.inventory.EntityEquipment;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.FireworkMeta;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import static com.empireminecraft.features.survival.LootPool.LootItem;
final class Halloween extends Listener {
private static World world;
private static final ListMultimap<Identifier, Location> jackCache = ArrayListMultimap.create();
private static final EmpireCustomMetaKey<Integer> SMP_SCORE_KEY;
private static final EmpireCustomMetaKey<Integer> GLOBAL_SCORE_KEY;
private static final EmpireCustomMetaKey<Set<Long>> PICKUP_LOG_KEY;
private static final UsableItem[] CANDIES = {
PromoItems.CREEPER_CANDY,
PromoItems.ZOMBIE_CANDY,
PromoItems.SPIDER_CANDY,
PromoItems.SKELETON_CANDY,
PromoItems.ENDER_CANDY
};
private static final Timing jackTiming = Util.timings("Jack block update");
static {
final String server = EmpireServer.getServer().label;
PICKUP_LOG_KEY = new EmpireCustomMetaKey("htown.pickups", LongSetMetaSerializer.SERIALIZER);
GLOBAL_SCORE_KEY = new EmpireCustomMetaKey("htown.score", EmpireMetaNumberSerializer.INTEGER);
SMP_SCORE_KEY = new EmpireCustomMetaKey("htown." + server+ ".score", EmpireMetaNumberSerializer.INTEGER);
final List<EmpireMetaKey> auto = EmpireMetaKey.getAutoloadKeys();
auto.add(PICKUP_LOG_KEY);
auto.add(GLOBAL_SCORE_KEY);
auto.add(SMP_SCORE_KEY);
}
private Halloween() {}
public static void initialize() {
world = Bukkit.getWorld("event");
if (world != null) {
for (Chunk chunk : world.getLoadedChunks()) {
cacheChunk(chunk);
}
}
final LootPool.LootTable loot = SurvivalItemDrops.mobDrops;
loot.put(EntityType.CREEPER, LootPool.LootPool(LootItem(25, PromoItems.CREEPER_CANDY)));
loot.put(EntityType.ZOMBIE, LootPool.LootPool(LootItem(25, PromoItems.ZOMBIE_CANDY)));
loot.put(EntityType.SPIDER, LootPool.LootPool(LootItem(25, PromoItems.SPIDER_CANDY)));
loot.put(EntityType.SKELETON, LootPool.LootPool(LootItem(25, PromoItems.SKELETON_CANDY)));
loot.put(EntityType.ENDERMAN, LootPool.LootPool(LootItem(25, PromoItems.ENDER_CANDY)));
new Halloween();
new HalloweenCommand();
BukkitUtil.runTaskTimer(Halloween::worldEvent, TimeUtil.SECOND.inTicks(30));
BukkitUtil.runTaskTimer(Halloween::cycleMobs, TimeUtil.SECOND.inTicks(15));
BukkitUtil.runTaskTimer(Halloween::toggleJacks, TimeUtil.SECOND.inTicks(10));
BukkitUtil.runTaskTimer(Halloween::scoreBroadcast, TimeUtil.MINUTE.inTicks(15));
}
public static void initializeCommand() {
new HalloweenCommand();
}
@CommandAlias("halloween|hallo|htown")
private static class HalloweenCommand extends EmpireCommand {
@Default
public void onEnter(Player player) {
if (world != null) {
SpecialEvents.teleportToEventWorld(player, p -> {
EmpireChat.setActiveChannel(p, ChatChannel.RESIDENCE);
Util.sendMsg(p, "&aChat focus set to channel " + ChatChannel.RESIDENCE);
});
} else {
Util.sendMsg(player, "&cSorry, it appears Halloween Town is closed!");
}
}
@Subcommand("score|s|p|points")
@CommandAlias("hscore|hpoints|gscore")
public void onScore(Player player) {
sendScore(player, "Global Score", GLOBAL_SCORE_KEY);
}
@Subcommand("smpscore|smp|smppoints")
@CommandAlias("smpscore|smppoints")
public void onSMPScore(Player player) {
sendScore(player, EmpireServer.getServer().label.toUpperCase() + " Score", SMP_SCORE_KEY);
}
private void sendScore(Player player, String header, EmpireCustomMetaKey<Integer> key) {
Empire.newChain()
.async(() -> {
try {
EmpireUser user = player.getUser();
List<DbRow> results = getTopPlayers(key, 10);
Util.sendMsg(player, Formatting.heading("Halloween Score - " + header));
int globalPoints = user.getMeta(GLOBAL_SCORE_KEY).getOrDefault();
int smpPoints = user.getMeta(SMP_SCORE_KEY).getOrDefault();
final String server = EmpireServer.getServer().label.toUpperCase();
user.sendMsg("&a - Your scores: &b" + smpPoints + " &a/&b " + globalPoints + " &e(" + server + "/GLOBAL)");
for (int i = 0; i < results.size(); i++) {
DbRow res = results.get(i);
Util.sendMsg(player, " &b" + (i+1) + ": " + EmpireGroup.colorUserName(res.get("name"), (Integer) res.get("user_group_id"))
+ "&f (" + res.get("score") + ")");
}
Util.sendMsg(player, " &bUse &f/smpscore&b for per-SMP score, &f/hscore &bfor global");
} catch (SQLException e) {
Util.sendMsg(player, "&cSomething went wrong. Hopefully Aikar can fix it.");
Util.printException(e);
}
}).execute();
}
}
private static List<DbRow> getTopPlayers(EmpireCustomMetaKey<Integer> key, int number) throws SQLException {
return EmpireDb.getResults(
"SELECT m.value as score, u.name, u.user_group_id " +
" FROM user u JOIN user_meta m ON m.user_id = u.user_id " +
" WHERE m.meta_key = ? " +
" ORDER BY CAST(value as UNSIGNED) DESC LIMIT " + number,
key.key
);
}
@EventHandler
public static void onChunkLoad(ChunkLoadEvent event) {
if (event.getWorld().equals(world)) {
cacheChunk(event.getChunk());
}
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
public static void onChunkUnload(ChunkUnloadEvent event) {
if (event.getWorld().equals(world)) {
final Identifier chunkId = event.getChunk().getIdentifier();
final List<Location> list = jackCache.get(chunkId);
if (list != null) {
list.clear();
}
}
}
@EventHandler
public static void onWorldLoad(WorldLoadEvent event) {
if ("event".equals(event.getWorld().getName())) {
world = event.getWorld();
}
}
@EventHandler
public static void onWorldUnload(WorldUnloadEvent event) {
if (event.getWorld().equals(world)) {
world.getPlayers().forEach(p -> {
Util.sendMsg(p, "&cSorry, Halloween town has been closed!");
p.teleport(Worlds.getSpawnLocation(Worlds.TOWN));
});
world = null;
}
}
@EventHandler(ignoreCancelled = true)
public static void onMerge(ItemMergeEvent event) {
if (event.getEntity().getWorld().equals(world)) {
event.setCancelled(true);
}
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
public static void onDamage(EntityDamageEvent event) {
final Entity entity = event.getEntity();
if (entity.getWorld().equals(world) && entity instanceof Villager) {
event.setCancelled(true);
}
}
@EventHandler
public static void onProjLaunch(ProjectileLaunchEvent event) {
if (event.getEntity().getWorld().equals(world) && event.getEntity() instanceof Fireball) {
event.setCancelled(true);
}
}
@EventHandler
public static void onDeath(EntityDeathEvent event) {
final LivingEntity entity = event.getEntity();
if (entity instanceof Player) {
return;
}
if (entity.getWorld().equals(world)) {
if (entity instanceof Ghast) {
event.getDrops().clear();
}
if (NumUtil.rand(1,2) == 1) {
spawnFirework(entity.getLocation(), 1, 1, 1);
spawnCandy(entity.getLocation());
if (NumUtil.rand(1, 4) != 1) {
spawnCandy(entity.getLocation());
if (Util.randBool()) {
spawnCandy(entity.getLocation());
}
}
}
}
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
public static void onMove(EntityPathfindEvent event) {
final Entity entity = event.getEntity();
if (entity.getWorld().equals(world)) {
Residence residence = Residence.getResidence(event.getLoc());
if (residence == null) {
event.setCancelled(true);
}
}
}
@EventHandler(ignoreCancelled = true)
public static void onWeather(WeatherChangeEvent event) {
if (event.getWorld().equals(world) && event.toWeatherState()) {
event.setCancelled(true);
}
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public static void onPickup(PlayerPickupItemEvent event) {
final Player player = event.getPlayer();
if (!player.getWorld().equals(world)) {
return;
}
final ItemStack itemStack = event.getItem().getItemStack();
if (!isCandy(itemStack)) {
return;
}
final String ownerName = MetaApi.getEntityMeta(event.getItem(), PersistentMetaKey.ITEM_OWNER);
if (ownerName == null || player.getName().equals(ownerName)) {
return;
}
Player throwerPlayer = Bukkit.getPlayerExact(ownerName);
if (throwerPlayer == null) {
return;
}
if (Chat.isAway(throwerPlayer)) {
event.setCancelled(true);
return;
}
EmpireUser picker = player.getUser();
EmpireUser thrower = throwerPlayer.getUser();
if (!processPickup(picker, thrower)) {
event.setCancelled(true);
}
}
@EventHandler(ignoreCancelled = true)
public void onDropItem(PlayerDropItemEvent event) {
final Player player = event.getPlayer();
if (!player.getWorld().equals(world)) {
return;
}
if (Chat.isAway(player)) {
event.setCancelled(true);
return;
}
final Location location = event.getItemDrop().getLocation();
location.setY(location.getWorld().getHighestBlockYAt(location));
if (world.getNearbyEntitiesByType(Item.class, location, 6, 6, 6).size() > 2) {
event.setCancelled(true);
Util.sendMsg(player, "&cToo many items are already nearby! Throw somewhere else.");
}
}
private static void scoreBroadcast() {
if (world != null) {
Empire.newChain()
.asyncFirst( () -> {
try {
final String server = EmpireServer.getServer().label.toUpperCase();
final List<DbRow> top3SMP = getTopPlayers(SMP_SCORE_KEY, 3);
final List<DbRow> top3Global = getTopPlayers(GLOBAL_SCORE_KEY, 3);
final Function<DbRow, String> buildNameString = row -> {
final Integer groupId = row.get("user_group_id");
final String score = row.get("score");
final String name = row.get("name");
return EmpireGroup.colorUserName(name, groupId) + " &b(" + score + ")";
};
String smpScore = top3SMP.stream().map(buildNameString).collect(Collectors.joining("&b, "));
String globalScore = top3Global.stream().map(buildNameString).collect(Collectors.joining("&b, "));
return Lists.newArrayList(
Util.color(" &b" + server + ": " + smpScore),
Util.color(" &bGlobal: " + globalScore)
);
} catch (SQLException e) {
Util.printException(e);
}
return null;
})
.abortIfNull()
.syncLast((result) -> {
final String heading = Formatting.heading("Current Top Scores");
world.getPlayers().forEach(player -> {
Util.sendMsg(player, heading);
Util.sendMsg(player, result.get(0));
Util.sendMsg(player, result.get(1));
Util.sendMsg(player, " &bSee TOP 10 with &f/smpscore&b for per-SMP, &f/hscore &bfor global");
});
})
.execute();
}
}
private static boolean processPickup(EmpireUser picker, EmpireUser thrower) {
final EmpireCustomMeta<Set<Long>> meta = picker.getMeta(PICKUP_LOG_KEY);
Set<Long> pickups = meta.getOrDefault();
if (pickups == null) {
return true; // shouldnt happen on this API but make IDE happy
}
final Residence residence = Residence.getResidence(thrower.player);
if (residence == null || !"event".equals(residence.getName())) {
return false;
}
CuboidArea area = residence.getArea("entrance");
if (area.containsLoc(picker.player.getLocation())) {
return false;
}
if (pickups.contains(thrower.userId)) {
return false;
}
pickups.add(thrower.userId);
meta.save();
String server = EmpireServer.getServer().label.toUpperCase();
int pickerPoints = picker.incrementMeta(GLOBAL_SCORE_KEY, 1);
int pickerSMPPoints = picker.incrementMeta(SMP_SCORE_KEY, 1);
picker.sendMsg( "&aYou received candy from " + thrower.colorName + "&a!");
picker.sendMsg( "&a - Your scores: &b" + pickerSMPPoints + " &a/&b " + pickerPoints + " &e(" + server + "/GLOBAL)");
processRewards(picker, pickerPoints);
int giverPoints = thrower.incrementMeta(GLOBAL_SCORE_KEY, 1);
int giverSMPPoints = thrower.incrementMeta(SMP_SCORE_KEY, 1);
thrower.sendMsg("&aYou gave candy to " + picker.colorName + "&a, you get bonus candy!");
thrower.sendMsg("&a - Your scores: &b" + giverSMPPoints + " &a/&b " + giverPoints + " &e(" + server + "/GLOBAL)");
processRewards(thrower, giverPoints);
UserUtil.givePlayerItems(thrower.player, Util.random(CANDIES));
return true;
}
private static void processRewards(EmpireUser user, int score) {
if (score == 50) {
user.sendMsg(" &a» &bCongratulations! You have earned a &aHaunted Head&a!");
UserUtil.givePlayerItems(user.player, PromoItems.HAUNTED_HEAD);
} else if (score == 150) {
user.sendMsg(" &a» &bCongratulations! You have earned a &6&oHeadless Horseman Mask&a!");
UserUtil.givePlayerItems(user.player, PromoItems.HEADLESS_HORSEMAN_MASK);
}
if (score % 25 == 0) {
user.sendMsg(" &a» &bCongratulations! You have earned &a500&b rupees!");
Empire.newChain().async(() -> {
Rupees.credit(user.getUserId(), 500, RupeeTransType.PROMOTIONAL_CREDIT.id(), "Halloween 2016 Bonus: " + score);
}).execute();
}
}
private static boolean isCandy(ItemStack item) {
for (UsableItem candy : CANDIES) {
if (UsableItem.isSame(candy, item)) {
return true;
}
}
return false;
}
private static void cacheChunk(Chunk chunk) {
int cX = chunk.getX() << 4;
int cZ = chunk.getZ() << 4;
final Identifier chunkId = chunk.getIdentifier();
jackCache.get(chunkId).clear();
Residence residence = ResidenceManager.getByName("event");
if (residence == null) {
return;
}
Residence pumpkin = residence.getSubzone("pumpkin");
for (int x = 0; x < 16; x++) {
for (int z = 0; z < 16; z++) {
for (int y = 0; y < 20; y++) {
final Block block = world.getBlockAt(cX + x, y, cZ + z);
final Location blockLoc = block.getLocation();
if (!residence.containsLoc(blockLoc) || (pumpkin != null && pumpkin.containsLoc(blockLoc))) {
continue;
}
final Material type = block.getType();
if (type == Material.JACK_O_LANTERN || type == Material.PUMPKIN) {
jackCache.put(chunkId, blockLoc);
}
}
}
}
}
@SuppressWarnings("deprecation")
private static void toggleJacks() {
if (world == null) {
return;
}
for (Chunk chunk : world.getLoadedChunks()) {
final List<Location> list = jackCache.get(chunk.getIdentifier());
if (list == null || list.isEmpty()) {
continue;
}
for (Iterator<Location> iterator = list.iterator(); iterator.hasNext(); ) {
try (Timing ignored = jackTiming.startTiming()) {
Location loc = iterator.next();
final Block block = loc.getBlock();
final Material type = block.getType();
if (type != Material.JACK_O_LANTERN && type != Material.PUMPKIN) {
iterator.remove();
continue;
}
if (NumUtil.rand(1,3) != 1) {
continue;
}
byte data = block.getData();
if (type == Material.PUMPKIN) {
block.setTypeIdAndData(Material.JACK_O_LANTERN.getId(), data, false);
} else {
block.setTypeIdAndData(Material.PUMPKIN.getId(), data, false);
}
}
}
}
}
private static void cycleMobs() {
if (world == null) {
return;
}
int limit = TimeUtil.MINUTE.inTicks(1);
int batLimit = TimeUtil.MINUTE.inTicks(3);
world.getEntities().forEach(entity -> {
final int ticksLived = entity.getTicksLived();
if ((Util.isMonster(entity) && ticksLived > limit) || (entity instanceof Bat && ticksLived > batLimit)) {
entity.remove();
}
});
}
private static void spawnCandy(Location location) {
world.dropItemNaturally(location, Util.random(CANDIES));
}
private static void worldEvent() {
if (world == null) {
return;
}
final Residence res = Residence.getResidenceByName("event");
if (res == null) {
return;
}
final CuboidArea main = res.getArea("main");
if (main == null) {
return;
}
final Location highLoc = main.getHighLoc();
final Location lowLoc = main.getLowLoc();
for (int i = 0, count = 0; i < 150 && count < 4; i++) {
int randX = NumUtil.rand(lowLoc.getBlockX(), highLoc.getBlockX());
int randZ = NumUtil.rand(lowLoc.getBlockZ(), highLoc.getBlockZ());
Location loc = new Location(world, randX, NumUtil.rand(20,60), randZ);
if (BlockUtil.isAreaAir(loc, 3)) {
count++;
spawnFirework(loc.clone(), NumUtil.rand(2, 6), NumUtil.rand(1,3), NumUtil.rand(1,3));
spawnMob(loc.clone());
}
}
}
private static void spawnMob(Location loc) {
loc.setY(world.getHighestBlockYAt(loc)+1);
Entity entity;
int type = NumUtil.rand(1, 6);
if (type == 1) {
entity = world.spawnEntity(loc, EntityType.SKELETON, SpawnReason.FORCE);
} else if (type == 2) {
entity = world.spawnEntity(loc, EntityType.ZOMBIE, SpawnReason.FORCE);
} else if (type == 3) {
entity = world.spawnEntity(loc, EntityType.PIG_ZOMBIE, SpawnReason.FORCE);
} else if (type == 4 && NumUtil.rand(1, 3) == 1) {
entity = world.spawnEntity(loc, EntityType.GHAST, SpawnReason.FORCE);
} else {
entity = world.spawnEntity(loc, EntityType.BAT, SpawnReason.FORCE);
}
if (entity instanceof Creature) {
Creature creature = (Creature) entity;
prepareMonster(creature);
}
}
private static void prepareMonster(Creature creature) {
ItemStack head = new ItemStack(Material.LEATHER_HELMET);
ItemStack body = new ItemStack(Material.LEATHER_CHESTPLATE);
ItemStack legs = new ItemStack(Material.LEATHER_LEGGINGS);
ItemStack boots = new ItemStack(Material.LEATHER_BOOTS);
CustomItems.colorLeatherItem(head, Util.randBool() ? 0x000000 : 0xffa500);
CustomItems.colorLeatherItem(body, Util.randBool() ? 0x000000 : 0xffa500);
CustomItems.colorLeatherItem(legs, Util.randBool() ? 0x000000 : 0xffa500);
CustomItems.colorLeatherItem(boots, Util.randBool() ? 0x000000 : 0xffa500);
final EntityEquipment equipment = creature.getEquipment();
equipment.setHelmet(head);
equipment.setChestplate(body);
equipment.setLeggings(legs);
equipment.setBoots(boots);
EntityAIApi.makePeaceful(creature);
EntityAIApi.setTargetRange(creature, 0);
}
private static void spawnFirework(Location loc, int power, int oranges, int blacks) {
world.spawnEntity(loc, EntityType.FIREWORK, input -> {
if (input == null) {
return false;
}
Firework firework = (Firework) input;
FireworkMeta meta = firework.getFireworkMeta();
meta.setPower(power);
final Type type = randType();
final Color black = Color.fromRGB(0, 0, 0);
for (int i = 0; i < blacks; i++) {
meta.addEffects(
createEffect(type, black, randOrange(), true, false),
createEffect(type, black, randOrange(), false, true)
);
}
for (int i = 0; i < oranges; i++) {
meta.addEffects(
createEffect(type, randOrange(), black, true, false),
createEffect(type, randOrange(), black, false, true)
);
}
firework.setFireworkMeta(meta);
firework.detonate();
return false;
});
}
private static FireworkEffect createEffect(Type type, Color color, Color fade, boolean trail, boolean flicker) {
return FireworkEffect.builder().with(type).withColor(color).withFade(fade).trail(trail).flicker(flicker).build();
}
private static Type randType() {
return Util.random(Type.values());
}
private static Color randOrange() {
return Color.fromRGB(NumUtil.rand(255-5, 255), NumUtil.rand(165-10, 170), 0);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment