Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
vbmr authored Oct 23, 2022
0 parents commit 9ebe21f
Show file tree
Hide file tree
Showing 14 changed files with 646 additions and 0 deletions.
Empty file added README.md
Empty file.
56 changes: 56 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<name>Boomerang</name>
<description>Bone-y boomerangs.</description>

<groupId>dev.karar.boomerang</groupId>
<artifactId>Boomerang</artifactId>
<version>1.0</version>

<dependencies>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot</artifactId>
<version>1.8.8-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>

<build>
<finalName>${project.name}</finalName>
<resources>
<resource>
<filtering>true</filtering>
<directory>${project.basedir}/src/main/resources</directory>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>

<repositories>
<repository>
<id>spigot-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
</repository>
</repositories>

<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>

</project>
98 changes: 98 additions & 0 deletions src/main/java/dev/karar/boomerang/Boomerang.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package dev.karar.boomerang;

import dev.karar.boomerang.bone.Bone;
import dev.karar.boomerang.commands.GiveCommand;
import dev.karar.boomerang.listeners.InventoryListener;
import dev.karar.boomerang.listeners.PlayerListener;
import dev.karar.boomerang.utils.Utils;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.java.JavaPlugin;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class Boomerang extends JavaPlugin {

private static Boomerang instance;

private static final List<Bone> boomerangs = new ArrayList<>();

private static FileConfiguration config;
private static final HashMap<String, String> messageData = new HashMap<>();

public static Boomerang getInstance() {
return instance;
}

public List<Bone> getBoomerangs() {
return boomerangs;
}

public FileConfiguration getConfig() {
return config;
}

public HashMap<String, String> getMessageData() {
return messageData;
}

@Override
public void onEnable() {
instance = this;

registerCommands();
registerEvents();
createConfig();
createMessages();
}

@Override
public void onDisable() {
for (Bone bone : getBoomerangs()) bone.endReturn();
}

private void registerCommands() {
getCommand("boomerang").setExecutor(new GiveCommand());
}

private void registerEvents() {
getServer().getPluginManager().registerEvents(new PlayerListener(), this);
getServer().getPluginManager().registerEvents(new InventoryListener(), this);
}

private void createConfig() {
// Get (or create) config.yml file.
File configFile = new File(getDataFolder(), "config.yml");
if (!configFile.exists()) {
configFile.getParentFile().mkdirs();
saveResource("config.yml", false);
}

config = new YamlConfiguration();
try {
config.load(configFile);
} catch (IOException | InvalidConfigurationException e) {
e.printStackTrace();
}
}

private void createMessages() {
// Get (or create) messages.yml file.
File messagesFile = new File(getDataFolder(), "messages.yml");
if (!messagesFile.exists()) {
messagesFile.getParentFile().mkdirs();
saveResource("messages.yml", false);
}

// Cache messages.yml file values in hash.
FileConfiguration config = YamlConfiguration.loadConfiguration(messagesFile);
for (String message : config.getConfigurationSection("").getKeys(false)) {
messageData.put(message, Utils.colorize(config.getString(message)));
}
}
}
69 changes: 69 additions & 0 deletions src/main/java/dev/karar/boomerang/bone/Bone.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package dev.karar.boomerang.bone;

import dev.karar.boomerang.Boomerang;
import dev.karar.boomerang.bone.animation.ReturnAnimation;
import dev.karar.boomerang.bone.animation.ThrowAnimation;
import org.bukkit.Bukkit;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.EulerAngle;

public class Bone {

public final Player player;
public final ArmorStand bone;
public ItemStack heldItem;
public int heldSlot;

private int sendID;
private int returnID;

public Bone(Player player, ItemStack item, int slot) {
this.player = player;
this.bone = (ArmorStand) player.getWorld().spawnEntity(player.getLocation().add(0, 0.8f, 0), EntityType.ARMOR_STAND);
this.bone.setVisible(false);
this.bone.setMarker(true);
this.bone.setGravity(false);
this.bone.setRightArmPose(new EulerAngle(270, 0, 0));
this.bone.getEquipment().setItemInHand(ItemType.BOOMERANG.getItem());

this.heldItem = item;
this.heldSlot = slot;
startSend();
}

public void startSend() {
sendID = Bukkit.getScheduler().scheduleSyncRepeatingTask(Boomerang.getInstance(), new ThrowAnimation(this), 0, 1);
// Start return animation when boomerang has exhausted lifespan for ticks-throw set in config.yml file.
Bukkit.getScheduler().runTaskLater(Boomerang.getInstance(), () -> {
Bukkit.getScheduler().cancelTask(sendID);
if (Bukkit.getPlayer(player.getUniqueId()) == null) return;

if (returnID == 0) startReturn();
}, Boomerang.getInstance().getConfig().getLong("animation.throw.duration"));
}

public void startReturn() {
// Cancel any send task in case return task was called by collision earlier than desired.
Bukkit.getScheduler().cancelTask(sendID);

returnID = Bukkit.getScheduler().scheduleSyncRepeatingTask(Boomerang.getInstance(), new ReturnAnimation(this), 0, 1);
Bukkit.getScheduler().runTaskLater(Boomerang.getInstance(), () -> {
if (!bone.isDead()) endReturn();
}, Boomerang.getInstance().getConfig().getLong("animation.return.duration"));
}

public void endReturn() {
Bukkit.getScheduler().cancelTask(returnID);
die();
if (Bukkit.getPlayer(player.getUniqueId()) == null) return;
player.getInventory().setItem(heldSlot, heldItem);
}

public void die() {
bone.remove();
Boomerang.getInstance().getBoomerangs().remove(this);
}
}
48 changes: 48 additions & 0 deletions src/main/java/dev/karar/boomerang/bone/ItemType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package dev.karar.boomerang.bone;

import dev.karar.boomerang.Boomerang;
import dev.karar.boomerang.utils.Utils;
import net.minecraft.server.v1_8_R3.NBTTagCompound;
import org.bukkit.Material;
import org.bukkit.craftbukkit.v1_8_R3.inventory.CraftItemStack;
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;
import java.util.UUID;

public enum ItemType {

BOOMERANG,
SEDENTARY_BOOMERANG;

public ItemStack getItem() {
// Create item and properly attribute based on config.yml file preferences.
ItemStack boomerang = new ItemStack(Material.getMaterial(Boomerang.getInstance().getConfig().getString(name() + ".material")), 1, (short) Boomerang.getInstance().getConfig().getInt(name() + ".type"));
ItemMeta itemMeta = boomerang.getItemMeta().clone();
itemMeta.setDisplayName(Utils.colorize(Boomerang.getInstance().getConfig().getString(name() + ".name")));
List<String> itemLore = new ArrayList<>();
Boomerang.getInstance().getConfig().getStringList(name() + ".lore").forEach((line) -> itemLore.add(Utils.colorize(line)));
itemMeta.setLore(itemLore);
Boomerang.getInstance().getConfig().getStringList(name() + ".enchantments").forEach((enchant) -> {
String type = enchant.split(":")[0];
int level = Integer.parseInt(enchant.split(":")[1]);
itemMeta.addEnchant(Enchantment.getByName(type), level, true);
});
Boomerang.getInstance().getConfig().getStringList(name() + ".flags").forEach((flag) -> itemMeta.addItemFlags(ItemFlag.valueOf(flag)));
boomerang.setItemMeta(itemMeta);

// Fetch NMS and initialize custom metadata.
net.minecraft.server.v1_8_R3.ItemStack nmsItem = CraftItemStack.asNMSCopy(boomerang);
NBTTagCompound tag = nmsItem.getTag();
if (Boomerang.getInstance().getConfig().getBoolean(name() + ".unique")) {
tag.setString("uuid", UUID.randomUUID().toString());
}
tag.setString("id", name());
nmsItem.setTag(tag);
return CraftItemStack.asBukkitCopy(nmsItem);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package dev.karar.boomerang.bone.animation;

import dev.karar.boomerang.Boomerang;
import dev.karar.boomerang.bone.Bone;
import dev.karar.boomerang.utils.Utils;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.*;
import org.bukkit.util.Vector;

public class ReturnAnimation implements Runnable {

private final Bone animation;

private final Player player;
private final ArmorStand bone;

public ReturnAnimation(Bone animation) {
this.animation = animation;
this.player = animation.player;
this.bone = animation.bone;
}

@Override
public void run() {
if (bone.isDead()) return;

if (Bukkit.getPlayer(player.getUniqueId()) == null) {
animation.die();
return;
}

double radius = Boomerang.getInstance().getConfig().getDouble("animation.return.radius");
for (Entity nearby : bone.getNearbyEntities(radius, radius, radius)) {
if (Utils.isEntityIgnored(nearby)) continue;

if (Boomerang.getInstance().getConfig().getDouble("animation.return.damage") > 0) {
LivingEntity mob = (LivingEntity) nearby;
mob.damage(Boomerang.getInstance().getConfig().getDouble("animation.return.damage"));
}
}

Location location = bone.getLocation();
Vector direction = bone.getLocation().toVector().subtract(player.getLocation().toVector()).normalize();

// Rotate and teleport boomerang towards sender.
location.setYaw(bone.getLocation().getYaw() + Boomerang.getInstance().getConfig().getInt("animation.return.rotate-speed"));
location.subtract(direction);
bone.teleport(location);

if (Boomerang.getInstance().getConfig().getBoolean("animation.catch.proximity")) {
double catchRadius = Boomerang.getInstance().getConfig().getDouble("animation.catch.radius");
for (Entity nearby : bone.getNearbyEntities(catchRadius, catchRadius, catchRadius)) {
if (nearby == player) animation.endReturn();
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package dev.karar.boomerang.bone.animation;

import dev.karar.boomerang.Boomerang;
import dev.karar.boomerang.bone.Bone;
import dev.karar.boomerang.utils.Utils;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;

public class ThrowAnimation implements Runnable {

private final Bone animation;

private final Player player;
private final ArmorStand bone;

private final Location startLoc;

public ThrowAnimation(Bone animation) {
this.animation = animation;
this.player = animation.player;
this.bone = animation.bone;

this.startLoc = animation.player.getLocation();
}

@Override
public void run() {
if (bone.isDead()) return;

if (Bukkit.getPlayer(player.getUniqueId()) == null) {
animation.die();
return;
}

double radius = Boomerang.getInstance().getConfig().getDouble("animation.throw.radius");
for (Entity nearby : bone.getNearbyEntities(radius, radius, radius)) {
if (Utils.isEntityIgnored(nearby)) continue;

if (Boomerang.getInstance().getConfig().getDouble("animation.throw.damage") > 0) {
LivingEntity mob = (LivingEntity) nearby;
mob.damage(Boomerang.getInstance().getConfig().getDouble("animation.throw.damage"));
}
}

Location location = bone.getLocation();
Vector direction = startLoc.getDirection();

// On instance boomerang collides with a block, cancel and return to sender.
if (!Utils.getNearbyBlocks(new Location(location.getWorld(), location.getX(), location.getY() + 1, location.getZ()), 0).isEmpty()) {
animation.startReturn();
return;
}

// Rotate and teleport boomerang towards sender-cast direction.
location.setYaw(bone.getLocation().getYaw() + Boomerang.getInstance().getConfig().getInt("animation.throw.rotate-speed"));
location.add(direction);
bone.teleport(location);
}
}
Loading

0 comments on commit 9ebe21f

Please sign in to comment.