Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Map;

@Getter
@Builder
@AllArgsConstructor
Expand All @@ -29,28 +32,5 @@ public class CustomProjectileDefinition implements ProjectilePhysics {
private final @Nullable Key material;
private final @Nullable Integer customModelData;

/*
@Override
public double getGravity() {
return fromKey().getGravity();
}

@Override
public double getDrag() {
return fromKey().getDrag();
}

@Override
public double getWaterDrag() {
return fromKey().getWaterDrag();
}

private @NotNull ProjectilePhysics fromKey() {
DefaultProjectileDefinition value = Registries.DEFAULT_PROJECTILE_DEFINITION_REGISTRY.of(entityKey);
if (value == null) {
return ProjectilePhysics.DEFAULT;
}

return value;
}*/
private final @NotNull Map<String, @NotNull Double> attributes;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
import at.pavlov.cannons.multiversion.EventResolver;
import at.pavlov.cannons.projectile.ProjectileManager;
import at.pavlov.cannons.utils.EventUtils;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Projectile;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.event.entity.EntityExplodeEvent;
Expand Down Expand Up @@ -40,7 +42,7 @@ public void onProjectileHitEntity(ProjectileHitEvent event) {
* @param event
*/
@EventHandler(ignoreCancelled = true)
public void EntityExplode(EntityExplodeEvent event) {
public void onEntityExplode(EntityExplodeEvent event) {
plugin.logDebug("Explode event listener called");

if (!EventResolver.isValidExplosion(event)) {
Expand All @@ -49,4 +51,14 @@ public void EntityExplode(EntityExplodeEvent event) {

EventUtils.handleExplosion(event.blockList());
}

/**
* If living entity projectile gets shot down and killed, make it detonate mid air or wherever it is
* @param event
*/
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
public void onEntityDeath(EntityDeathEvent event) {
LivingEntity entity = event.getEntity();
ProjectileManager.getInstance().detonateProjectile(entity);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,27 @@
import at.pavlov.cannons.CreateExplosion;
import at.pavlov.cannons.Enum.ProjectileCause;
import at.pavlov.cannons.dao.AsyncTaskManager;
import at.pavlov.internal.Key;
import at.pavlov.internal.key.registries.Registries;
import at.pavlov.internal.projectile.definition.CustomProjectileDefinition;
import at.pavlov.internal.projectile.definition.ProjectilePhysics;
import com.google.common.base.Preconditions;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.entity.AbstractArrow;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.ItemDisplay;
import org.bukkit.entity.Player;
import org.bukkit.entity.ThrowableProjectile;
import org.bukkit.entity.WitherSkull;
import org.bukkit.*;
import org.bukkit.attribute.Attributable;
import org.bukkit.attribute.Attribute;
import org.bukkit.attribute.AttributeModifier;
import org.bukkit.entity.*;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataType;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;

import java.nio.charset.StandardCharsets;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

public class ProjectileManager
{
public class ProjectileManager {
private static ProjectileManager instance = null;

private final Cannons plugin;
Expand All @@ -46,6 +43,7 @@ public static ProjectileManager getInstance() {

/**
* ProjectileManager
*
* @param plugin - Cannons instance
*/
private ProjectileManager(Cannons plugin) {
Expand All @@ -58,8 +56,8 @@ public Entity spawnProjectile(Projectile projectile, @NotNull UUID shooter, org.

//set yaw, pitch for fireballs
double v = velocity.length();
spawnLoc.setPitch((float) (Math.acos(velocity.getY()/v)*180.0/Math.PI - 90));
spawnLoc.setYaw((float) (Math.atan2(velocity.getZ(),velocity.getX())*180.0/Math.PI - 90));
spawnLoc.setPitch((float) (Math.acos(velocity.getY() / v) * 180.0 / Math.PI - 90));
spawnLoc.setYaw((float) (Math.atan2(velocity.getZ(), velocity.getX()) * 180.0 / Math.PI - 90));

Entity projectileEntity = spawnProjectile(projectile, spawnLoc, velocity, world);

Expand All @@ -78,17 +76,22 @@ public Entity spawnProjectile(Projectile projectile, @NotNull UUID shooter, org.
return projectileEntity;
}

private static final NamespacedKey MOB_TYPE_KEY = new NamespacedKey(Cannons.getPlugin(), "mob_type");
private @NotNull Entity spawnProjectile(Projectile projectile, Location spawnLoc, Vector velocity, World world) {
Entity entity = world.spawnEntity(spawnLoc, projectile.getProjectileEntity());

//calculate firing vector
entity.setVelocity(velocity);

CustomProjectileDefinition definition = Registries.CUSTOM_PROJECTILE_DEFINITION.of(projectile.getProjectileDefinitionKey());
Key customEntityKey = projectile.getProjectileDefinitionKey();
CustomProjectileDefinition definition = Registries.CUSTOM_PROJECTILE_DEFINITION.of(customEntityKey);
if (definition == null) {
return entity;
}

// allow people to use custom textures for entities
entity.getPersistentDataContainer().set(MOB_TYPE_KEY, PersistentDataType.STRING, customEntityKey.full());

entity.setVisualFire(definition.isOnFire());
entity.setGlowing(definition.isGlowing());

Expand All @@ -101,6 +104,18 @@ public Entity spawnProjectile(Projectile projectile, @NotNull UUID shooter, org.
entity.setGravity(false);
}

if (entity instanceof LivingEntity livingEntity) {
livingEntity.setAI(false);
}

if (entity instanceof Attributable attributable) {
handleAttributable(attributable, definition, entity);
}

if (entity instanceof Display display) {
display.setTeleportDuration(1);
}

if (entity instanceof WitherSkull witherSkull) {
witherSkull.setCharged(definition.isCharged());
} else if (entity instanceof AbstractArrow arrow) {
Expand Down Expand Up @@ -138,9 +153,36 @@ public Entity spawnProjectile(Projectile projectile, @NotNull UUID shooter, org.
return entity;
}

private static void handleAttributable(Attributable attributable, CustomProjectileDefinition definition, Entity entity) {
UUID uuid = UUID.nameUUIDFromBytes("cannon:attribute".getBytes(StandardCharsets.UTF_8));
for (var entry : definition.getAttributes().entrySet()) {
String attrKey = entry.getKey();
Attribute attribute = Registry.ATTRIBUTE.get(NamespacedKey.minecraft(attrKey));

if (attribute == null) {
Cannons.getPlugin().logSevere("Attribute [" + attrKey + "] doesn't exist");
continue;
}

var attributeInstance = attributable.getAttribute(attribute);
if (attributeInstance == null) {
Cannons.getPlugin().logSevere("Attribute [" + attrKey + "] not found for entity " + entity.getType());
continue;
}

// todo: this AttributeModifier constructor is marked for removal, might want to replace with a more robust implementation
attributeInstance.addModifier(
new AttributeModifier(
uuid, "attribute_definition", entry.getValue(), AttributeModifier.Operation.ADD_NUMBER
)
);
}
}


/**
* detonate a timefused projectile mid air
*
* @param cannonball - the cannonball to detonate
*/
private void detonateTimefuse(final FlyingProjectile cannonball) {
Expand All @@ -164,35 +206,32 @@ private void detonateTimefuse(final FlyingProjectile cannonball) {
projectile_entity.remove();
}
flyingProjectilesMap.remove(cannonball.getUID());
}, (long) (cannonball.getProjectile().getTimefuse()*20));
}, (long) (cannonball.getProjectile().getTimefuse() * 20));
}


/**
* detonates the given projectile entity
*
* @param projectile - the projectile with this entity
*/
public void detonateProjectile(Entity projectile)
{
if(projectile == null || !(projectile instanceof org.bukkit.entity.Projectile))
return;

public void detonateProjectile(Entity projectile) {
FlyingProjectile fproj = flyingProjectilesMap.get(projectile.getUniqueId());
if (fproj!=null)
{
CreateExplosion.getInstance().detonate(fproj, (org.bukkit.entity.Projectile) projectile);
if (fproj != null) {
CreateExplosion.getInstance().detonate(fproj, projectile);
projectile.remove();
flyingProjectilesMap.remove(fproj.getUID());
}
}

/**
* detonates the given projectile entity
*
* @param cannonball - the projectile with this entity
* @param target the entity hit by the projectile
* @param target the entity hit by the projectile
*/
public void directHitProjectile(Entity cannonball, Entity target) {
if(cannonball == null || target == null) return;
if (cannonball == null || target == null) return;

FlyingProjectile fproj = flyingProjectilesMap.get(cannonball.getUniqueId());
if (fproj == null) {
Expand All @@ -211,33 +250,33 @@ public void directHitProjectile(Entity cannonball, Entity target) {

/**
* returns true if the given entity is a cannonball projectile
*
* @param projectile flying projectile
* @return true if cannonball projectile
*/
public boolean isFlyingProjectile(Entity projectile)
{
public boolean isFlyingProjectile(Entity projectile) {
FlyingProjectile fproj = flyingProjectilesMap.get(projectile.getUniqueId());
return fproj != null;
}


/**
* returns the list of all flying projectiles
*
* @return - the list of all flying projectiles
*/
public ConcurrentHashMap<UUID, FlyingProjectile> getFlyingProjectiles()
{
public ConcurrentHashMap<UUID, FlyingProjectile> getFlyingProjectiles() {
return flyingProjectilesMap;
}

/**
* returns the projectile of which the player is passenger
* if the player is attached to a projectile he will follow its movement
*
* @param player is the passenger
* @return the projectile or null
*/
public FlyingProjectile getAttachedProjectile(Player player)
{
public FlyingProjectile getAttachedProjectile(Player player) {
if (player == null) {
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@
import at.pavlov.internal.projectile.definition.ProjectilePhysics;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
import org.jetbrains.annotations.NotNull;

import java.io.File;
import java.util.HashMap;

public class ProjectileDefinitionLoader {
public static void reload() {
Expand Down Expand Up @@ -43,7 +45,7 @@ private static void loadEntry(YamlConfiguration cfg, String node) {
dpd = ProjectilePhysics.DEFAULT;
}

CustomProjectileDefinition definition = CustomProjectileDefinition.builder()
CustomProjectileDefinition.CustomProjectileDefinitionBuilder builder = CustomProjectileDefinition.builder()
.key(key)
.entityKey(entityKey)
.constantAcceleration(section.getObject("constantAcceleration", Double.class, dpd.getConstantAcceleration()))
Expand All @@ -55,9 +57,18 @@ private static void loadEntry(YamlConfiguration cfg, String node) {
.charged(section.getBoolean("charged"))
.critical(section.getBoolean("critical"))
.material(Key.from(section.getString("material", "SNOWBALL")))
.customModelData(section.getObject("customModelData", Integer.class, null))
.build();
.customModelData(section.getObject("customModelData", Integer.class, null));

Registries.CUSTOM_PROJECTILE_DEFINITION.register(definition);
var attributeSection = section.getConfigurationSection("attributes");
HashMap<String, @NotNull Double> attributeMap = new HashMap<>();
if (attributeSection != null) {
for (var attrName : attributeSection.getKeys(false)) {
var value = attributeSection.getDouble(attrName);
attributeMap.put(attrName, value);
}
}

builder = builder.attributes(attributeMap);
Registries.CUSTOM_PROJECTILE_DEFINITION.register(builder.build());
}
}
4 changes: 4 additions & 0 deletions cannons-bukkit/src/main/resources/projectile_definitions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
# charged: false # works only for wither skulls, makes it charged
# critical: false # works for arrows and tridents, makes the try visible
#
# # available for all entities that are Attributable, generally all living entities have this
# attributes:
# scale: 2.0
#
# # this stuff is for throwable projectiles, such as snowballs, and item displays
# material: SNOWBALL # you can set any material https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/Material.html
# customModelData: 123 # must be an integer, texturepack magic number goes here
Expand Down