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