diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/MBR.mcpack b/MBR.mcpack new file mode 100644 index 0000000..3f3f8f4 Binary files /dev/null and b/MBR.mcpack differ diff --git a/pom.xml b/pom.xml index 56dee25..6b995f1 100644 --- a/pom.xml +++ b/pom.xml @@ -4,8 +4,8 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - cn.powernukkitx - ExamplePlugin-Maven + me.zimzaza4 + MoreBows 1.0.0-SNAPSHOT diff --git a/src/main/java/cn/powernukkitx/exampleplugin/BroadcastPluginTask.java b/src/main/java/cn/powernukkitx/exampleplugin/BroadcastPluginTask.java deleted file mode 100644 index 40953c9..0000000 --- a/src/main/java/cn/powernukkitx/exampleplugin/BroadcastPluginTask.java +++ /dev/null @@ -1,19 +0,0 @@ -package cn.powernukkitx.exampleplugin; - -import cn.nukkit.scheduler.PluginTask; - -/** - * author: MagicDroidX - * ExamplePlugin Project - */ -public class BroadcastPluginTask extends PluginTask { - - public BroadcastPluginTask(ExamplePlugin owner) { - super(owner); - } - - @Override - public void onRun(int currentTick) { - this.getOwner().getLogger().info("I've run on tick " + currentTick); - } -} diff --git a/src/main/java/cn/powernukkitx/exampleplugin/EventListener.java b/src/main/java/cn/powernukkitx/exampleplugin/EventListener.java deleted file mode 100644 index a987c56..0000000 --- a/src/main/java/cn/powernukkitx/exampleplugin/EventListener.java +++ /dev/null @@ -1,24 +0,0 @@ -package cn.powernukkitx.exampleplugin; - -import cn.nukkit.event.EventHandler; -import cn.nukkit.event.EventPriority; -import cn.nukkit.event.Listener; -import cn.nukkit.event.server.ServerCommandEvent; - -/** - * author: MagicDroidX - * NukkitExamplePlugin Project - */ -public class EventListener implements Listener { - private final ExamplePlugin plugin; - - public EventListener(ExamplePlugin plugin) { - this.plugin = plugin; - } - - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = false) //DON'T FORGET THE ANNOTATION @EventHandler - public void onServerCommand(ServerCommandEvent event) { - this.plugin.getLogger().info("ServerCommandEvent is called!"); - //you can do more here! - } -} diff --git a/src/main/java/cn/powernukkitx/exampleplugin/ExamplePlugin.java b/src/main/java/cn/powernukkitx/exampleplugin/ExamplePlugin.java deleted file mode 100644 index 39177ad..0000000 --- a/src/main/java/cn/powernukkitx/exampleplugin/ExamplePlugin.java +++ /dev/null @@ -1,77 +0,0 @@ -package cn.powernukkitx.exampleplugin; - -import cn.nukkit.command.Command; -import cn.nukkit.command.CommandSender; -import cn.nukkit.plugin.PluginBase; -import cn.nukkit.utils.Config; -import cn.nukkit.utils.ConfigSection; -import cn.nukkit.utils.TextFormat; -import cn.nukkit.utils.Utils; - -import java.io.File; -import java.io.IOException; -import java.util.LinkedHashMap; - -/** - * author: MagicDroidX - * NukkitExamplePlugin Project - */ -public class ExamplePlugin extends PluginBase { - - @Override - public void onLoad() { - this.getLogger().info(TextFormat.WHITE + "I've been loaded!"); - } - - @Override - public void onEnable() { - this.getLogger().info(TextFormat.DARK_GREEN + "I've been enabled!"); - - this.getLogger().info(String.valueOf(this.getDataFolder().mkdirs())); - - //Register the EventListener - this.getServer().getPluginManager().registerEvents(new EventListener(this), this); - - //PluginTask - this.getServer().getScheduler().scheduleRepeatingTask(new BroadcastPluginTask(this), 200); - - //Save resources - this.saveResource("string.txt"); - - //Config reading and writing - Config config = new Config( - new File(this.getDataFolder(), "config.yml"), - Config.YAML, - //Default values (not necessary) - new ConfigSection(new LinkedHashMap<>() { - { - put("this-is-a-key", "Hello! Config!"); - put("another-key", true); //you can also put other standard objects! - } - })); - //Now try to get the value, the default value will be given if the key isn't exist! - this.getLogger().info(String.valueOf(config.get("this-is-a-key", "this-is-default-value"))); - //Don't forget to save it! - config.save(); - } - - @Override - public void onDisable() { - this.getLogger().info(TextFormat.DARK_RED + "I've been disabled!"); - } - - @Override - public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { - switch (command.getName().toLowerCase()) { - case "example": - try { - this.getLogger().info(Utils.readFile(new File(this.getDataFolder(), "string.txt")) + " " + sender.getName()); - } catch (IOException e) { - throw new RuntimeException(e); - } - break; - } - return true; - } - -} diff --git a/src/main/java/me/zimzaza4/morebows/MoreBows.java b/src/main/java/me/zimzaza4/morebows/MoreBows.java new file mode 100644 index 0000000..0f5e3c0 --- /dev/null +++ b/src/main/java/me/zimzaza4/morebows/MoreBows.java @@ -0,0 +1,67 @@ +package me.zimzaza4.morebows; + +import cn.nukkit.Nukkit; +import cn.nukkit.Server; +import cn.nukkit.inventory.CraftingManager; +import cn.nukkit.inventory.ShapedRecipe; +import cn.nukkit.item.Item; +import cn.nukkit.item.customitem.ItemCustom; +import cn.nukkit.plugin.PluginBase; +import cn.nukkit.utils.TextFormat; +import me.zimzaza4.morebows.item.bows.IcyBow; +import me.zimzaza4.morebows.item.bows.TNTBow; +import me.zimzaza4.morebows.item.bows.TeleportBow; +import me.zimzaza4.morebows.listeners.ProjectileListener; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class MoreBows extends PluginBase { + private static MoreBows instance; + + private static final String[] RECIPE = new String[] { + "mmm", + "mbm", + "mmm" + }; + @Override + public void onEnable() { + instance = this; + Server.getInstance().getPluginManager().registerEvents(new ProjectileListener(), this); + + try { + Item.registerCustomItem(List.of(IcyBow.class, TeleportBow.class, TNTBow.class)); + } catch (Exception e) { + e.printStackTrace(); + } + + CraftingManager craftingManager = Server.getInstance().getCraftingManager(); + + + craftingManager.registerShapedRecipe(new ShapedRecipe(new IcyBow(), RECIPE, getBowRecipeMap(Item.get(Item.ICE)), new ArrayList<>())); + craftingManager.registerShapedRecipe(new ShapedRecipe(new TNTBow(), RECIPE, getBowRecipeMap(Item.get(Item.TNT)), new ArrayList<>())); + craftingManager.registerShapedRecipe(new ShapedRecipe(new TeleportBow(), RECIPE, getBowRecipeMap(Item.get(Item.ENDER_PEARL)), new ArrayList<>())); + + craftingManager.rebuildPacket(); + } + + + + public Map getBowRecipeMap(Item material) { + Map map = new HashMap<>(); + map.put('b', Item.get(Item.BOW)); + map.put('m', material); + return map; + } + + @Override + public void onDisable() { + + } + + public static MoreBows getInstance() { + return instance; + } +} diff --git a/src/main/java/me/zimzaza4/morebows/item/CustomBowBase.java b/src/main/java/me/zimzaza4/morebows/item/CustomBowBase.java new file mode 100644 index 0000000..89d6e65 --- /dev/null +++ b/src/main/java/me/zimzaza4/morebows/item/CustomBowBase.java @@ -0,0 +1,186 @@ + +package me.zimzaza4.morebows.item; + +import cn.nukkit.Player; +import cn.nukkit.Server; +import cn.nukkit.api.PowerNukkitDifference; +import cn.nukkit.entity.Entity; +import cn.nukkit.entity.projectile.EntityArrow; +import cn.nukkit.entity.projectile.EntityProjectile; +import cn.nukkit.event.entity.EntityShootBowEvent; +import cn.nukkit.event.entity.ProjectileHitEvent; +import cn.nukkit.event.entity.ProjectileLaunchEvent; +import cn.nukkit.inventory.Inventory; +import cn.nukkit.item.Item; +import cn.nukkit.item.ItemTool; +import cn.nukkit.item.customitem.CustomItemDefinition; +import cn.nukkit.item.customitem.ItemCustomTool; +import cn.nukkit.item.customitem.data.ItemCreativeCategory; +import cn.nukkit.item.enchantment.Enchantment; +import cn.nukkit.level.Sound; +import cn.nukkit.math.Vector3; +import cn.nukkit.nbt.tag.CompoundTag; +import cn.nukkit.nbt.tag.DoubleTag; +import cn.nukkit.nbt.tag.FloatTag; +import cn.nukkit.nbt.tag.ListTag; +import me.zimzaza4.morebows.item.data.ArrowMetadata; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Random; +import java.util.stream.Stream; + +public class CustomBowBase extends ItemCustomTool { + + + public CustomBowBase(@NotNull String id, @Nullable String name, @NotNull String textureName) { + super(id, name, textureName); + } + + @Override + public CustomItemDefinition getDefinition() { + return CustomItemDefinition + .toolBuilder(this, ItemCreativeCategory.EQUIPMENT) + .allowOffHand(false) + .handEquipped(true) + .foil(false) + .customBuild(nbt -> { + nbt.getCompound("components") + .putCompound("minecraft:food", new CompoundTag().putBoolean("can_always_eat", true)) + .getCompound("item_properties") + .putInt("use_duration", Integer.MAX_VALUE) + .putCompound("minecraft:chargeable", new CompoundTag().putFloat("movement_modifier", 0.35F)); + + }); + } + + @Override + public int getMaxDurability() { + return ItemTool.DURABILITY_BOW; + } + + @Override + public int getEnchantAbility() { + return 1; + } + + @Override + public boolean onClickAir(Player player, Vector3 directionVector) { + return player.isCreative() || + Stream.of(player.getInventory(), player.getOffhandInventory()) + .anyMatch(inv -> inv.contains(getArrowType())); + } + + @PowerNukkitDifference(info = "Using new method to play sounds", since = "1.4.0.0-PN") + @Override + public boolean onRelease(Player player, int ticksUsed) { + Item itemArrow = Item.get(Item.ARROW, 0, 1); + + Inventory inventory = player.getOffhandInventory(); + + if (!inventory.contains(itemArrow) && !(inventory = player.getInventory()).contains(itemArrow) && (player.isAdventure() || player.isSurvival())) { + player.getOffhandInventory().sendContents(player); + inventory.sendContents(player); + return false; + } + + double damage = 2; + + Enchantment bowDamage = this.getEnchantment(Enchantment.ID_BOW_POWER); + if (bowDamage != null && bowDamage.getLevel() > 0) { + damage += (double) bowDamage.getLevel() * 0.5 + 0.5; + } + + Enchantment flameEnchant = this.getEnchantment(Enchantment.ID_BOW_FLAME); + boolean flame = flameEnchant != null && flameEnchant.getLevel() > 0; + + CompoundTag nbt = new CompoundTag() + .putList(new ListTag("Pos") + .add(new DoubleTag("", player.x)) + .add(new DoubleTag("", player.y + player.getEyeHeight())) + .add(new DoubleTag("", player.z))) + .putList(new ListTag("Motion") + .add(new DoubleTag("", -Math.sin(player.yaw / 180 * Math.PI) * Math.cos(player.pitch / 180 * Math.PI))) + .add(new DoubleTag("", -Math.sin(player.pitch / 180 * Math.PI))) + .add(new DoubleTag("", Math.cos(player.yaw / 180 * Math.PI) * Math.cos(player.pitch / 180 * Math.PI)))) + .putList(new ListTag("Rotation") + .add(new FloatTag("", (player.yaw > 180 ? 360 : 0) - (float) player.yaw)) + .add(new FloatTag("", (float) -player.pitch))) + .putShort("Fire", flame ? 45 * 60 : 0) + .putDouble("damage", damage); + + double p = (double) ticksUsed / 20; + double f = Math.min((p * p + p * 2) / 3, 1) * 3; + + EntityArrow arrow = (EntityArrow) Entity.createEntity("Arrow", player.chunk, nbt, player, f == 2); + + if (arrow == null) { + return false; + } + + EntityShootBowEvent entityShootBowEvent = new EntityShootBowEvent(player, this, arrow, f); + + if (f < 0.1 || ticksUsed < 3) { + entityShootBowEvent.setCancelled(); + } + + Server.getInstance().getPluginManager().callEvent(entityShootBowEvent); + if (entityShootBowEvent.isCancelled()) { + entityShootBowEvent.getProjectile().kill(); + player.getInventory().sendContents(player); + player.getOffhandInventory().sendContents(player); + } else { + entityShootBowEvent.getProjectile().setMotion(entityShootBowEvent.getProjectile().getMotion().multiply(entityShootBowEvent.getForce())); + Enchantment infinityEnchant = this.getEnchantment(Enchantment.ID_BOW_INFINITY); + boolean infinity = infinityEnchant != null && infinityEnchant.getLevel() > 0; + EntityProjectile projectile; + if (infinity && (projectile = entityShootBowEvent.getProjectile()) instanceof EntityArrow) { + ((EntityArrow) projectile).setPickupMode(EntityProjectile.PICKUP_CREATIVE); + } + if (player.isAdventure() || player.isSurvival()) { + if (!infinity) { + inventory.removeItem(itemArrow); + } + if (!this.isUnbreakable()) { + Enchantment durability = this.getEnchantment(Enchantment.ID_DURABILITY); + if (!(durability != null && durability.getLevel() > 0 && (100 / (durability.getLevel() + 1)) <= new Random().nextInt(100))) { + this.setDamage(this.getDamage() + 1); + if (this.getDamage() >= getMaxDurability()) { + player.getLevel().addSound(player, Sound.RANDOM_BREAK); + this.count--; + } + player.getInventory().setItemInHand(this); + } + } + } + if (entityShootBowEvent.getProjectile() != null) { + ProjectileLaunchEvent projectev = new ProjectileLaunchEvent(entityShootBowEvent.getProjectile(), player); + Server.getInstance().getPluginManager().callEvent(projectev); + if (projectev.isCancelled()) { + entityShootBowEvent.getProjectile().kill(); + } else { + entityShootBowEvent.getProjectile().spawnToAll(); + entityShootBowEvent.getProjectile().setMetadata("morebows:custom_arrow_data", new ArrowMetadata(this)); + onShoot(entityShootBowEvent.getProjectile()); + player.getLevel().addSound(player, Sound.RANDOM_BOW); + } + } + } + + return true; + } + + public Item getArrowType() { + return Item.get(Item.ARROW); + } + + + protected void onShoot(EntityProjectile projectile) { + + } + + public void onHit(ProjectileHitEvent event) { + + } + +} diff --git a/src/main/java/me/zimzaza4/morebows/item/bows/IcyBow.java b/src/main/java/me/zimzaza4/morebows/item/bows/IcyBow.java new file mode 100644 index 0000000..69cf3c1 --- /dev/null +++ b/src/main/java/me/zimzaza4/morebows/item/bows/IcyBow.java @@ -0,0 +1,26 @@ +package me.zimzaza4.morebows.item.bows; + +import cn.nukkit.entity.Entity; +import cn.nukkit.entity.EntityLiving; +import cn.nukkit.event.entity.ProjectileHitEvent; +import cn.nukkit.potion.Effect; +import me.zimzaza4.morebows.item.CustomBowBase; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class IcyBow extends CustomBowBase { + public IcyBow() { + super("morebows:icy_bow", "§b冰弓", "icy_bow"); + } + + @Override + public void onHit(ProjectileHitEvent event) { + if (event.getMovingObjectPosition().entityHit instanceof EntityLiving living) { + Effect effect = Effect.getEffect(Effect.SLOWNESS); + effect.setDuration(100); + effect.setAmplifier(3); + living.addEffect(effect); + + } + } +} diff --git a/src/main/java/me/zimzaza4/morebows/item/bows/TNTBow.java b/src/main/java/me/zimzaza4/morebows/item/bows/TNTBow.java new file mode 100644 index 0000000..feab004 --- /dev/null +++ b/src/main/java/me/zimzaza4/morebows/item/bows/TNTBow.java @@ -0,0 +1,16 @@ +package me.zimzaza4.morebows.item.bows; + +import cn.nukkit.event.entity.ProjectileHitEvent; +import cn.nukkit.level.Explosion; +import me.zimzaza4.morebows.item.CustomBowBase; + +public class TNTBow extends CustomBowBase { + public TNTBow() { + super("morebows:tnt_bow", "TNT弓", "tnt_bow"); + } + + @Override + public void onHit(ProjectileHitEvent event) { + new Explosion(event.getEntity(), 2.0f, event.getEntity()).explodeB(); + } +} diff --git a/src/main/java/me/zimzaza4/morebows/item/bows/TeleportBow.java b/src/main/java/me/zimzaza4/morebows/item/bows/TeleportBow.java new file mode 100644 index 0000000..c0750d1 --- /dev/null +++ b/src/main/java/me/zimzaza4/morebows/item/bows/TeleportBow.java @@ -0,0 +1,28 @@ +package me.zimzaza4.morebows.item.bows; + +import cn.nukkit.entity.projectile.EntityArrow; +import cn.nukkit.event.entity.EntityDamageByBlockEvent; +import cn.nukkit.event.entity.EntityDamageByEntityEvent; +import cn.nukkit.event.entity.EntityDamageEvent; +import cn.nukkit.event.entity.ProjectileHitEvent; +import cn.nukkit.level.Sound; +import me.zimzaza4.morebows.item.CustomBowBase; + +public class TeleportBow extends CustomBowBase { + public TeleportBow() { + super("morebows:teleport_bow", "传送弓", "teleport_bow"); + } + + + @Override + public void onHit(ProjectileHitEvent event) { + if (event.getEntity() instanceof EntityArrow arrow) { + if (arrow.shootingEntity != null) { + arrow.shootingEntity.teleport(event.getMovingObjectPosition().hitVector.add(0, 1, 0)); + + arrow.shootingEntity.attack(new EntityDamageByEntityEvent(arrow, arrow.shootingEntity, EntityDamageEvent.DamageCause.PROJECTILE, 5)); + arrow.level.addSound(arrow, Sound.MOB_ENDERMEN_PORTAL); + } + } + } +} diff --git a/src/main/java/me/zimzaza4/morebows/item/data/ArrowMetadata.java b/src/main/java/me/zimzaza4/morebows/item/data/ArrowMetadata.java new file mode 100644 index 0000000..43e29b1 --- /dev/null +++ b/src/main/java/me/zimzaza4/morebows/item/data/ArrowMetadata.java @@ -0,0 +1,30 @@ +package me.zimzaza4.morebows.item.data; + +import cn.nukkit.metadata.MetadataValue; +import cn.nukkit.plugin.Plugin; +import me.zimzaza4.morebows.MoreBows; +import me.zimzaza4.morebows.item.CustomBowBase; + +public class ArrowMetadata extends MetadataValue { + + private final CustomBowBase bow; + + public ArrowMetadata(CustomBowBase bow) { + super(MoreBows.getInstance()); + this.bow = bow; + } + + @Override + public Object value() { + return this; + } + + public CustomBowBase getBow() { + return bow; + } + + @Override + public void invalidate() { + + } +} diff --git a/src/main/java/me/zimzaza4/morebows/listeners/ProjectileListener.java b/src/main/java/me/zimzaza4/morebows/listeners/ProjectileListener.java new file mode 100644 index 0000000..77d83ab --- /dev/null +++ b/src/main/java/me/zimzaza4/morebows/listeners/ProjectileListener.java @@ -0,0 +1,20 @@ +package me.zimzaza4.morebows.listeners; + +import cn.nukkit.event.EventHandler; +import cn.nukkit.event.Listener; +import cn.nukkit.event.entity.ProjectileHitEvent; +import me.zimzaza4.morebows.item.data.ArrowMetadata; + +public class ProjectileListener implements Listener { + + @EventHandler + public void onProjectileHit(ProjectileHitEvent e) { + if (e.getEntity().hasMetadata("morebows:custom_arrow_data")) { + e.getEntity().getMetadata("morebows:custom_arrow_data").forEach(data -> { + if (data instanceof ArrowMetadata ad) { + ad.getBow().onHit(e); + } + }); + } + } +} diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 9485fc2..b6548d4 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,37 +1,8 @@ -#name, main, version and api are required -name: ExamplePlugin -main: cn.powernukkitx.exampleplugin.ExamplePlugin -#remember version and api is string, don't write it like this: 1.0.0, or there will be an exception +name: MoreBows +main: me.zimzaza4.morebows.MoreBows version: "1.0.0" api: ["1.0.0"] load: POSTWORLD -author: Nukkit Project -# Authors and author will be added together in one list. -authors: ["Example", "Another"] -description: Example plugin showing the API -website: https://github.com/PowerNukkitX/ExamplePlugin-Maven -# These dependencies are required for the plugin to start. -#depend: ["OtherPlugin", "ThisPlugin"] -# These dependencies are not required. -softdepend: ["PluginA", "PluginB"] -# Log prefix in console -prefix: "Example" -# Plugin will be loaded before these. Any cyclic loadbefore's or dependencies's will throw errors! -loadbefore: ["ImportantPlugin"] - -commands: - example: - description: Example command - usage: "/example" - aliases: ["xample", "nukkitexample"] - permission: exampleplugin.command.example - permission-message: "You do not have the required permission to run /example" -permissions: - exampleplugin.command.example: - description: "Allows the user to run the example command" - default: true -# children: -# exampleplugin.command.example.test: -# description: "Use the test feature in the example command" -# default: true \ No newline at end of file +author: zimzaza4 +description: Bow Plugin \ No newline at end of file