commit c1243cf83a7bfb8a70828b7685520228cbac47e2
parent ef1e781adb24532cd8d89e8c9a065a81e52c997f
Author: night0721 <[email protected]>
Date: Thu, 14 Jul 2022 00:04:52 +0100
spawn command like dungeons i hope, custom item manager
custom item manager can now convert config.yml items into files in files in ItemData folder, no idea why i did that but it seems better
Diffstat:
8 files changed, 482 insertions(+), 14 deletions(-)
diff --git a/src/main/java/com/night/nullvalkyrie/Events/CustomItemEvents.java b/src/main/java/com/night/nullvalkyrie/Events/CustomItemEvents.java
@@ -27,7 +27,7 @@ public class CustomItemEvents implements Listener {
if (pl.getInventory().getItemInMainHand().getItemMeta() != null) {
String name = pl.getInventory().getItemInMainHand().getItemMeta().getDisplayName();
if (name.equalsIgnoreCase(Rarity.ULTRA.getColor() + "Snow Gun")) {
- e.setDamage(10000);
+ e.setDamage(2000);
} else if (name.equalsIgnoreCase("AA-12")) {
e.setDamage(7);
} else {
diff --git a/src/main/java/com/night/nullvalkyrie/Items/CustomItemManager.java b/src/main/java/com/night/nullvalkyrie/Items/CustomItemManager.java
@@ -1,19 +1,18 @@
package com.night.nullvalkyrie.Items;
import com.night.nullvalkyrie.Main;
-import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.attribute.Attribute;
import org.bukkit.attribute.AttributeModifier;
+import org.bukkit.configuration.MemorySection;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemFlag;
import org.bukkit.inventory.ItemStack;
-import org.bukkit.inventory.ShapedRecipe;
import org.bukkit.inventory.meta.ItemMeta;
import java.io.File;
@@ -30,6 +29,7 @@ public class CustomItemManager {
main.getDataFolder().mkdir();
}
createItemDataDirectory("ItemData");
+ createFilesFromConfig(main.getConfig());
register();
}
public void register() {
@@ -175,6 +175,30 @@ public class CustomItemManager {
}
return ns;
}
+ public void createFilesFromConfig(FileConfiguration config) {
+ for(String a : config.getKeys(false)) {
+ FileConfiguration c = loadConfig("ItemData\\" + a + ".yml");
+ for(String b : config.getKeys(true)) {
+ if(b.startsWith(a)) {
+ List<String> d = new ArrayList<>(Arrays.asList(b.split("\\.")));
+ if(d.size() != 1) {
+ d.remove(0);
+ if(d.size() == 1) {
+ c.set(d.get(0), config.get(b));
+ } else {
+ c.set(String.join(".", d), config.get(b));
+ }
+ try {
+ c.save(loadFile("ItemData\\" + a + ".yml"));
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ }
+ }
+ }
+ }
public static ItemStack getItem(String name){
return a.get(name);
}
diff --git a/src/main/java/com/night/nullvalkyrie/Main.java b/src/main/java/com/night/nullvalkyrie/Main.java
@@ -50,6 +50,8 @@ public final class Main extends JavaPlugin implements Listener {
@Override
public void onEnable() {
+ getConfig().options().copyDefaults();
+ saveDefaultConfig();
new VanishCommand();
new TestCommand();
new AnvilCommand();
diff --git a/src/main/java/com/night/nullvalkyrie/Util/Utils.java b/src/main/java/com/night/nullvalkyrie/Util/Utils.java
@@ -0,0 +1,49 @@
+package com.night.nullvalkyrie.Util;
+
+import org.bukkit.ChatColor;
+import org.bukkit.Material;
+import org.bukkit.enchantments.Enchantment;
+import org.bukkit.inventory.ItemFlag;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.ItemMeta;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Utils {
+ public static String color(String string) {
+ return ChatColor.translateAlternateColorCodes('&', string);
+ }
+
+ public static ItemStack createItem(Material type, int amount, String name, String... lines) {
+ ItemStack item = new ItemStack(type, amount);
+ ItemMeta meta = item.getItemMeta();
+ meta.setUnbreakable(true);
+ meta.addItemFlags(ItemFlag.HIDE_UNBREAKABLE, ItemFlag.HIDE_ENCHANTS);
+ if (name != null) meta.setDisplayName(color(name));
+ if (lines != null) {
+ List<String> lore = new ArrayList<>();
+ for (String line : lines) {
+ lore.add(color(line));
+ }
+ meta.setLore(lore);
+ }
+ item.setItemMeta(meta);
+ return item;
+ }
+
+ public static ItemStack enchantItem(ItemStack item, Enchantment enchant, int level) {
+ item.addUnsafeEnchantment(enchant, level);
+ return item;
+ }
+
+ public static ItemStack[] makeArmorSet(ItemStack helmet, ItemStack chestplate, ItemStack leggings, ItemStack boots) {
+ ItemStack[] armor = new ItemStack[4];
+ armor[3] = helmet;
+ armor[2] = chestplate;
+ armor[1] = leggings;
+ armor[0] = boots;
+ return armor;
+ }
+
+}
diff --git a/src/main/java/com/night/nullvalkyrie/Util/components/CustomMob.java b/src/main/java/com/night/nullvalkyrie/Util/components/CustomMob.java
@@ -0,0 +1,111 @@
+package com.night.nullvalkyrie.Util.components;
+
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.attribute.Attribute;
+import org.bukkit.enchantments.Enchantment;
+import org.bukkit.entity.EntityType;
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.inventory.EntityEquipment;
+import org.bukkit.inventory.ItemStack;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static com.night.nullvalkyrie.Util.Utils.color;
+import static com.night.nullvalkyrie.Util.Utils.*;
+
+public enum CustomMob {
+
+ DESERT_RISEN(
+ "&6Desert Risen",
+ 2048,
+ 60,
+ EntityType.HUSK,
+ null,
+ null,
+ new LootItem(createItem(Material.ROTTEN_FLESH, 1, "&fPreserved Flesh", "&7A preserved flesh from a rotting corpse", "&7Not sure what you'd want this for, though", "&7", "&9Foodstuff"), 1, 3, 100)),
+
+ SKELETAL_MAGE(
+ "&dSkeletal Mage",
+ 2048,
+ 15,
+ EntityType.SKELETON,
+ createItem(Material.BONE, 1, null), makeArmorSet(new ItemStack(Material.IRON_HELMET),
+ null,
+ null,
+ null),
+ new LootItem(createItem(Material.BONE, 1, "&dBone Wand", "&7A wand made from skeletal bones"), 30),
+ new LootItem(new ItemStack(Material.BONE), 1, 3, 100)),
+
+ ZOMBIE_SQUIRE(
+ "&bZombie Squire",
+ 2048,
+ 12,
+ EntityType.ZOMBIE,
+ new ItemStack(Material.IRON_SWORD),
+ makeArmorSet(new ItemStack(Material.CHAINMAIL_HELMET), new ItemStack(Material.CHAINMAIL_CHESTPLATE), new ItemStack(Material.CHAINMAIL_LEGGINGS), new ItemStack(Material.IRON_BOOTS)), new LootItem(new ItemStack(Material.CHAINMAIL_CHESTPLATE), 35), new LootItem(new ItemStack(Material.CHAINMAIL_LEGGINGS), 35), new LootItem(new ItemStack(Material.CHAINMAIL_HELMET), 35), new LootItem(new ItemStack(Material.IRON_BOOTS), 25), new LootItem(new ItemStack(Material.IRON_SWORD), 40)),
+
+ CHARRED_ARCHER(
+ "&8Charred Archer",
+ 2048,
+ 3,
+ EntityType.WITHER_SKELETON,
+ enchantItem(new ItemStack(Material.BOW), Enchantment.ARROW_KNOCKBACK, 2),
+ null, new LootItem(enchantItem(enchantItem(createItem(Material.BOW, 1, "&cBurnt Bow", "&7This bow is burnt to a crisp but remains intact", "&8due to special enchantments"), Enchantment.ARROW_FIRE, 1), Enchantment.ARROW_KNOCKBACK, 2), 100),
+ new LootItem(new ItemStack(Material.BONE), 1, 5, 100)),
+ ;
+
+ private String name;
+ private double maxHealth, spawnChance;
+ private EntityType type;
+ private ItemStack mainItem;
+ private ItemStack[] armor;
+ private List<LootItem> lootTable;
+
+ CustomMob(String name, double maxHealth, double spawnChance, EntityType type, ItemStack mainItem, ItemStack[] armor, LootItem... lootItems) {
+ this.name = name;
+ this.maxHealth = maxHealth;
+ this.spawnChance = spawnChance;
+ this.type = type;
+ this.mainItem = mainItem;
+ this.armor = armor;
+ lootTable = Arrays.asList(lootItems);
+ }
+
+ public LivingEntity spawn(Location location) {
+ LivingEntity entity = (LivingEntity) location.getWorld().spawnEntity(location, type);
+ entity.setCustomNameVisible(true);
+ entity.setCustomName(color(name + " &r&c" + (int) maxHealth + "/" + (int) maxHealth + "❤"));
+ entity.getAttribute(Attribute.GENERIC_MAX_HEALTH).setBaseValue(maxHealth);
+ entity.setHealth(maxHealth);
+ EntityEquipment inv = entity.getEquipment();
+ if (armor != null) inv.setArmorContents(armor);
+ inv.setHelmetDropChance(0f);
+ inv.setChestplateDropChance(0f);
+ inv.setLeggingsDropChance(0f);
+ inv.setBootsDropChance(0f);
+ inv.setItemInMainHand(mainItem);
+ inv.setItemInMainHandDropChance(0f);
+ return entity;
+ }
+
+ public void tryDropLoot(Location location) {
+ for (LootItem item : lootTable) {
+ item.tryDropItem(location);
+ }
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public double getMaxHealth() {
+ return maxHealth;
+ }
+
+ public double getSpawnChance() {
+ return spawnChance;
+ }
+
+}
diff --git a/src/main/java/com/night/nullvalkyrie/Util/components/LootItem.java b/src/main/java/com/night/nullvalkyrie/Util/components/LootItem.java
@@ -0,0 +1,36 @@
+package com.night.nullvalkyrie.Util.components;
+
+import org.bukkit.Location;
+import org.bukkit.inventory.ItemStack;
+
+import java.util.Random;
+
+public class LootItem {
+
+ private ItemStack item;
+ private int min = 1, max = 1;
+ private double dropRate;
+ private static Random randomiser = new Random();
+
+ public LootItem(ItemStack item, double dropRate) {
+ this.item = item;
+ this.dropRate = dropRate;
+ }
+
+ public LootItem(ItemStack item, int min, int max, double dropRate) {
+ this.item = item;
+ this.min = min;
+ this.max = max;
+ this.dropRate = dropRate;
+ }
+
+ public void tryDropItem(Location loc) {
+ if (Math.random() * 101 > dropRate) return;
+ int amount = randomiser.nextInt(max - min + 1) + min;
+ if (amount == 0) return;
+ ItemStack item = this.item.clone();
+ item.setAmount(amount);
+ loc.getWorld().dropItemNaturally(loc, item);
+ }
+
+}
diff --git a/src/main/java/com/night/nullvalkyrie/commands/SpawnCommand.java b/src/main/java/com/night/nullvalkyrie/commands/SpawnCommand.java
@@ -1,33 +1,151 @@
package com.night.nullvalkyrie.commands;
+import com.night.nullvalkyrie.Main;
+import com.night.nullvalkyrie.Util.components.CustomMob;
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.World;
+import org.bukkit.block.Block;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.*;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.entity.EntityDamageEvent;
+import org.bukkit.event.entity.EntityDeathEvent;
+import org.bukkit.scheduler.BukkitRunnable;
-import java.util.List;
+import java.text.DecimalFormat;
+import java.util.*;
-public class SpawnCommand extends Command {
- public SpawnCommand() {
+import static com.night.nullvalkyrie.Util.Utils.color;
+
+public class SpawnCommand extends Command implements Listener {
+ private final Main main;
+ public World world;
+ public final Map<Entity, Integer> indicators = new HashMap<>();
+ public final Map<Entity, CustomMob> entities = new HashMap<>();
+ private final DecimalFormat formatter = new DecimalFormat("#");
+ public SpawnCommand(Main main) {
super(
"spawn",
new String[]{},
"Spawn a custom mob",
""
);
+ this.main = main;
}
@Override
public void onCommand(CommandSender sender, String[] args) {
- Player player = (Player) sender;
- Entity ent = player.getWorld().spawnEntity((player.getLocation().add(0, 2, 0)), EntityType.ZOMBIE);
- ent.setCustomName("Gay");
- ent.setCustomNameVisible(true);
- double ourHealth = 20 * 5;
- Damageable ente = (Damageable) ent;
- ente.setMaxHealth(ourHealth);
- ente.setHealth(ourHealth);
+ world = Bukkit.getWorld("world");
+
+ spawnMobs(9, 10, 5 * 20);
+ new BukkitRunnable() {
+ final Set<Entity> stands = indicators.keySet();
+ final List<Entity> removal = new ArrayList<>();
+ @Override
+ public void run() {
+ for (Entity stand : stands) {
+ int ticksLeft = indicators.get(stand);
+ if (ticksLeft == 0) {
+ stand.remove();
+ removal.add(stand);
+ continue;
+ }
+ ticksLeft--;
+ indicators.put(stand, ticksLeft);
+ }
+ stands.removeAll(removal);
+ }
+ }.runTaskTimer(main, 0L, 1L);
+
+ }
+ public void spawnMobs(int size, int mobCap, int spawnTime) {
+ CustomMob[] mobTypes = CustomMob.values();
+ new BukkitRunnable() {
+ final Set<Entity> spawned = entities.keySet();
+ final List<Entity> removal = new ArrayList<>();
+ @Override
+ public void run() {
+ for (Entity entity : spawned) {
+ if (!entity.isValid() || entity.isDead()) removal.add(entity);
+ }
+ spawned.removeAll(removal);
+ // Spawning Algorithm
+ int diff = mobCap - entities.size();
+ if (diff <= 0) return;
+ int spawnAmount = (int) (Math.random() * (diff + 1)), count = 0;
+ while (count <= spawnAmount) {
+ count++;
+ int ranX = getRandomWithNeg(size), ranZ = getRandomWithNeg(size);
+ Block block = world.getHighestBlockAt(ranX, ranZ);
+ double xOffset = getRandomOffset(), zOffset = getRandomOffset();
+ Location loc = block.getLocation().clone().add(xOffset, 1, zOffset);
+ if (!isSpawnable(loc)) continue;
+ double random = Math.random() * 101, previous = 0;
+ CustomMob typeToSpawn = mobTypes[0];
+ for (CustomMob type : mobTypes) {
+ previous += type.getSpawnChance();
+ if (random <= previous) {
+ typeToSpawn = type;
+ break;
+ }
+ }
+ entities.put(typeToSpawn.spawn(loc), typeToSpawn);
+ }
+ }
+ }.runTaskTimer(main, 0L, spawnTime);
}
+ private static boolean isSpawnable(Location loc) {
+ Block feetBlock = loc.getBlock(), headBlock = loc.clone().add(0, 1, 0).getBlock(), upperBlock = loc.clone().add(0, 2, 0).getBlock();
+ return feetBlock.isPassable() && !feetBlock.isLiquid() && headBlock.isPassable() && !headBlock.isLiquid() && upperBlock.isPassable() && !upperBlock.isLiquid();
+ }
+
+ private static double getRandomOffset() {
+ double random = Math.random();
+ if (Math.random() > 0.5) random *= -1;
+ return random;
+ }
+
+ private static int getRandomWithNeg(int size) {
+ int random = (int) (Math.random() * (size + 1));
+ if (Math.random() > 0.5) random *= -1;
+ return random;
+ }
+
+ @EventHandler
+ public void onEntityDamage(EntityDamageEvent event) {
+ Entity rawEntity = event.getEntity();
+ if (!entities.containsKey(rawEntity)) return;
+ CustomMob mob = entities.get(rawEntity);
+ LivingEntity entity = (LivingEntity) rawEntity;
+ double damage = event.getFinalDamage(), health = entity.getHealth() + entity.getAbsorptionAmount();
+ if (health > damage) {
+ // If the entity survived the hit
+ health -= damage;
+ entity.setCustomName(color(mob.getName() + " &r&c" + (int) health + "/" + (int) mob.getMaxHealth() + "❤"));
+ }
+ Location loc = entity.getLocation().clone().add(getRandomOffset(), 1, getRandomOffset());
+ world.spawn(loc, ArmorStand.class, armorStand -> {
+ armorStand.setMarker(true);
+ armorStand.setVisible(false);
+ armorStand.setGravity(false);
+ armorStand.setSmall(true);
+ armorStand.setCustomNameVisible(true);
+ armorStand.setCustomName(color("&c" + formatter.format(damage)));
+ indicators.put(armorStand, 30);
+ });
+ }
+
+ @EventHandler
+ public void onEntityDeath(EntityDeathEvent event) {
+ if (!entities.containsKey(event.getEntity())) return;
+ event.setDroppedExp(0);
+ event.getDrops().clear();
+ entities.remove(event.getEntity()).tryDropLoot(event.getEntity().getLocation());
+ }
@Override
public List<String> onTabComplete(CommandSender sender, String[] args) {
return null;
diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml
@@ -0,0 +1,128 @@
+ExplosiveBow:
+ name: "Explosive Bow"
+ material: "BOW"
+ type: "Weapon"
+ rarity: LEGENDARY
+ lore:
+ properties:
+ damage: 50
+ ability:
+ name: Explosive Shot
+ details:
+ - Shoot a explosive arrow that causes lots of damage
+ - Arrow won't destroy blocks
+ enchants:
+ thunderbolt: 5
+ attributes:
+ damage: 50.0
+FragGrenade:
+ name: "Frag Grenade"
+ material: "EGG"
+ type: "Weapon"
+ rarity: LEGENDARY
+ lore:
+ properties:
+ damage: 50
+ ability:
+ name: TNT Party
+ details:
+ - Throw a *large* TNT explode with tons of damage
+ enchants:
+ thunderbolt: 5
+ attributes:
+ damage: 50.0
+GrapplingHook:
+ name: "Grappling Hook"
+ material: "FISHING_ROD"
+ type: "Weapon"
+ rarity: RARE
+ lore:
+ ability:
+ name: Hook
+ details:
+ - Using it will make you fly
+ enchants:
+ thunderbolt: 5
+SnowGun:
+ name: "Snow Gun"
+ material: "DIAMOND_HOE"
+ type: "Weapon"
+ rarity: ULTRA
+ lore:
+ properties:
+ damage: 25
+ speed: 20
+ ability:
+ name: Let it go
+ details:
+ - Shoot Snowball that cause lots of damage
+ enchants:
+ thunderbolt: 5
+ attributes:
+ damage: 25.0
+ moveSpeed: 0.2
+TeleportDoor:
+ name: "Teleport Door"
+ material: "DIAMOND_SHOVEL"
+ type: "Weapon"
+ rarity: GRAND
+ lore:
+ properties:
+ damage: 75
+ speed: 20
+ ability:
+ name: Instant Teleport
+ details:
+ - Teleport to 12 blocks away from you
+ enchants:
+ thunderbolt: 5
+ attributes:
+ damage: 75.0
+ moveSpeed: 0.2
+Terminator:
+ name: "Terminator"
+ material: "BOW"
+ type: "Weapon"
+ rarity: MYTHIC
+ lore:
+ properties:
+ damage: 50
+ speed: 10
+ ability:
+ name: Triple Shot
+ details:
+ - Shoot three arrow at one time
+ - Arrow deals 50% more damage
+ enchants:
+ sharpness: 20
+ looting: 10
+ thunderbolt: 5
+ attributes:
+ damage: 50.0
+ moveSpeed: 0.1
+WidowSword:
+ name: "Widow Sword"
+ material: "STICK"
+ type: "Weapon"
+ rarity: MYTHIC
+ lore:
+ properties:
+ damage: 100
+ speed: 20
+ ability:
+ name: Damage Multiplier
+ details:
+ - Damage dealt to mobs will be multiplied
+ - Zombie + 100%
+ - Skeleton + 100%
+ - Spider + 100%
+ enchants:
+ sharpness: 20
+ looting: 10
+ thunderbolt: 5
+ attributes:
+ damage: 100.0
+ moveSpeed: 0.2
+ zombie: 100
+ skeleton: 100
+ spider: 100