|
14 | 14 | import org.bukkit.entity.EntityType; |
15 | 15 | import org.bukkit.entity.LivingEntity; |
16 | 16 | import org.bukkit.entity.Player; |
| 17 | +import org.bukkit.entity.Projectile; |
| 18 | +import org.bukkit.entity.Tameable; |
| 19 | +import org.bukkit.entity.AnimalTamer; |
17 | 20 | import org.bukkit.event.Event; |
18 | 21 | import org.bukkit.event.EventPriority; |
19 | 22 | import org.bukkit.event.HandlerList; |
|
24 | 27 | import org.bukkit.block.BlockState; |
25 | 28 | import org.bukkit.event.inventory.InventoryClickEvent; |
26 | 29 | import org.bukkit.event.entity.CreatureSpawnEvent; |
| 30 | +import org.bukkit.event.entity.EntityDamageEvent; |
27 | 31 | import org.bukkit.plugin.EventExecutor; |
28 | 32 | import org.bukkit.plugin.java.JavaPlugin; |
29 | 33 | import org.bukkit.scheduler.BukkitTask; |
30 | 34 | import org.bukkit.command.CommandMap; |
31 | 35 | import org.bukkit.util.RayTraceResult; |
32 | 36 | import org.bukkit.util.Vector; |
33 | 37 | import org.bukkit.permissions.PermissionAttachment; |
| 38 | +import org.bukkit.projectiles.BlockProjectileSource; |
| 39 | +import org.bukkit.projectiles.ProjectileSource; |
34 | 40 | import org.bukkit.attribute.Attribute; |
35 | 41 | import org.bukkit.attribute.AttributeModifier; |
36 | 42 | import org.bukkit.inventory.InventoryHolder; |
@@ -825,7 +831,20 @@ private void handleEventResult(JsonObject message) { |
825 | 831 | return; |
826 | 832 | } |
827 | 833 |
|
828 | | - if (message.has("result") && !message.get("result").isJsonNull()) { |
| 834 | + if (!message.has("result") || message.get("result").isJsonNull()) { |
| 835 | + return; |
| 836 | + } |
| 837 | + |
| 838 | + String resultType = message.has("result_type") ? message.get("result_type").getAsString() : null; |
| 839 | + if ("damage".equalsIgnoreCase(resultType)) { |
| 840 | + JsonElement result = message.get("result"); |
| 841 | + if (result.isJsonPrimitive() && result.getAsJsonPrimitive().isNumber()) { |
| 842 | + pending.damageOverride = result.getAsDouble(); |
| 843 | + } |
| 844 | + return; |
| 845 | + } |
| 846 | + |
| 847 | + if (resultType == null || "chat".equalsIgnoreCase(resultType)) { |
829 | 848 | pending.chatOverride = message.get("result").getAsString(); |
830 | 849 | } |
831 | 850 | } |
@@ -2142,6 +2161,8 @@ private JsonElement serialize(Object value, Set<Object> seen) { |
2142 | 2161 | fields.add("type", serialize(entity.getType(), seen)); |
2143 | 2162 | fields.add("location", serialize(entity.getLocation(), seen)); |
2144 | 2163 | fields.add("world", serialize(entity.getWorld(), seen)); |
| 2164 | + fields.addProperty("is_projectile", entity instanceof Projectile); |
| 2165 | + addAttributionFields(entity, fields, seen); |
2145 | 2166 | } |
2146 | 2167 |
|
2147 | 2168 | if (value instanceof org.bukkit.World world) { |
@@ -2545,6 +2566,12 @@ private JsonObject baseEventPayload(Event event, String eventName) { |
2545 | 2566 | tryAddPayload(payload, event, "player", "getPlayer", "getWhoClicked"); |
2546 | 2567 | tryAddPayload(payload, event, "block", "getBlock", "getClickedBlock"); |
2547 | 2568 | tryAddPayload(payload, event, "entity", "getEntity"); |
| 2569 | + tryAddPayload(payload, event, "damager", "getDamager"); |
| 2570 | + if (event instanceof EntityDamageEvent damageEvent) { |
| 2571 | + payload.addProperty("damage", damageEvent.getDamage()); |
| 2572 | + payload.addProperty("final_damage", damageEvent.getFinalDamage()); |
| 2573 | + payload.add("damage_cause", serialize(damageEvent.getCause())); |
| 2574 | + } |
2548 | 2575 | tryAddPayload(payload, event, "location", "getLocation"); |
2549 | 2576 | tryAddPayload(payload, event, "world", "getWorld"); |
2550 | 2577 | tryAddPayload(payload, event, "item", "getItem"); |
@@ -2601,6 +2628,9 @@ private boolean dispatchCancellableEvent(Event event, String eventName, JsonObje |
2601 | 2628 | Bukkit.getScheduler().runTask(plugin, |
2602 | 2629 | () -> Bukkit.getServer().broadcast(net.kyori.adventure.text.Component.text(message))); |
2603 | 2630 | } |
| 2631 | + if (pending.damageOverride != null && pending.event instanceof EntityDamageEvent damageEvent) { |
| 2632 | + damageEvent.setDamage(pending.damageOverride); |
| 2633 | + } |
2604 | 2634 | if (cancelRequested && cancelMode == CancelMode.EVENT) { |
2605 | 2635 | pending.cancellable.setCancelled(true); |
2606 | 2636 | } |
@@ -2695,6 +2725,115 @@ private void tryAddPayload(JsonObject payload, Event event, String key, String.. |
2695 | 2725 | } |
2696 | 2726 | } |
2697 | 2727 |
|
| 2728 | + private void addAttributionFields(org.bukkit.entity.Entity entity, JsonObject fields, Set<Object> seen) { |
| 2729 | + Object shooter = null; |
| 2730 | + if (entity instanceof Projectile projectile) { |
| 2731 | + shooter = projectile.getShooter(); |
| 2732 | + } else { |
| 2733 | + shooter = tryInvokeNoArg(entity, "getShooter"); |
| 2734 | + } |
| 2735 | + addAttribution("shooter", shooter, fields, seen); |
| 2736 | + |
| 2737 | + Object source = tryInvokeNoArg(entity, "getSource"); |
| 2738 | + addAttribution("source", source, fields, seen); |
| 2739 | + |
| 2740 | + Object owner = null; |
| 2741 | + if (entity instanceof Tameable tameable) { |
| 2742 | + fields.addProperty("is_tamed", tameable.isTamed()); |
| 2743 | + owner = tameable.getOwner(); |
| 2744 | + } |
| 2745 | + if (owner == null) { |
| 2746 | + owner = tryInvokeNoArg(entity, "getOwner"); |
| 2747 | + } |
| 2748 | + if (owner == null) { |
| 2749 | + owner = tryInvokeNoArg(entity, "getOwningPlayer"); |
| 2750 | + } |
| 2751 | + if (owner == null) { |
| 2752 | + owner = tryInvokeNoArg(entity, "getOwningEntity"); |
| 2753 | + } |
| 2754 | + if (owner == null) { |
| 2755 | + owner = tryInvokeNoArg(entity, "getSummoner"); |
| 2756 | + } |
| 2757 | + addAttribution("owner", owner, fields, seen); |
| 2758 | + |
| 2759 | + } |
| 2760 | + |
| 2761 | + private Object tryInvokeNoArg(Object target, String methodName) { |
| 2762 | + try { |
| 2763 | + Method method = target.getClass().getMethod(methodName); |
| 2764 | + if (method.getParameterCount() != 0) { |
| 2765 | + return null; |
| 2766 | + } |
| 2767 | + return method.invoke(target); |
| 2768 | + } catch (Exception ignored) { |
| 2769 | + return null; |
| 2770 | + } |
| 2771 | + } |
| 2772 | + |
| 2773 | + private void addAttribution(String key, Object source, JsonObject fields, Set<Object> seen) { |
| 2774 | + if (source == null) { |
| 2775 | + return; |
| 2776 | + } |
| 2777 | + if (fields.has(key)) { |
| 2778 | + return; |
| 2779 | + } |
| 2780 | + |
| 2781 | + Object resolved = source; |
| 2782 | + if (source instanceof ProjectileSource projectileSource && !(source instanceof Entity)) { |
| 2783 | + if (projectileSource instanceof BlockProjectileSource blockSource) { |
| 2784 | + resolved = blockSource.getBlock(); |
| 2785 | + } |
| 2786 | + } |
| 2787 | + |
| 2788 | + if ("source".equals(key) || "shooter".equals(key)) { |
| 2789 | + if (resolved instanceof Entity sourceEntity) { |
| 2790 | + fields.add(key, serialize(sourceEntity, seen)); |
| 2791 | + } else if (resolved instanceof org.bukkit.block.Block block) { |
| 2792 | + fields.add(key, serialize(block, seen)); |
| 2793 | + } |
| 2794 | + return; |
| 2795 | + } |
| 2796 | + |
| 2797 | + if (resolved instanceof Entity sourceEntity) { |
| 2798 | + fields.add(key, serialize(sourceEntity, seen)); |
| 2799 | + fields.addProperty(key + "_uuid", sourceEntity.getUniqueId().toString()); |
| 2800 | + if (sourceEntity instanceof Player player) { |
| 2801 | + fields.addProperty(key + "_name", player.getName()); |
| 2802 | + } else { |
| 2803 | + Object name = tryInvokeNoArg(sourceEntity, "getName"); |
| 2804 | + if (name instanceof String nameText && !nameText.isBlank()) { |
| 2805 | + fields.addProperty(key + "_name", nameText); |
| 2806 | + } |
| 2807 | + } |
| 2808 | + return; |
| 2809 | + } |
| 2810 | + |
| 2811 | + if (resolved instanceof org.bukkit.block.Block block) { |
| 2812 | + fields.add(key, serialize(block, seen)); |
| 2813 | + return; |
| 2814 | + } |
| 2815 | + |
| 2816 | + if (resolved instanceof AnimalTamer tamer) { |
| 2817 | + fields.addProperty(key + "_uuid", tamer.getUniqueId().toString()); |
| 2818 | + if (tamer.getName() != null) { |
| 2819 | + fields.addProperty(key + "_name", tamer.getName()); |
| 2820 | + } |
| 2821 | + if (tamer instanceof Player player) { |
| 2822 | + fields.add(key, serialize(player, seen)); |
| 2823 | + } |
| 2824 | + return; |
| 2825 | + } |
| 2826 | + |
| 2827 | + if (resolved instanceof UUID uuid) { |
| 2828 | + fields.addProperty(key + "_uuid", uuid.toString()); |
| 2829 | + return; |
| 2830 | + } |
| 2831 | + |
| 2832 | + if (resolved instanceof String nameText) { |
| 2833 | + fields.addProperty(key + "_name", nameText); |
| 2834 | + } |
| 2835 | + } |
| 2836 | + |
2698 | 2837 | private void send(JsonObject response) { |
2699 | 2838 | if (writer == null) { |
2700 | 2839 | return; |
@@ -3332,6 +3471,7 @@ static class PendingEvent { |
3332 | 3471 | Event event; |
3333 | 3472 | int id; |
3334 | 3473 | String chatOverride; |
| 3474 | + Double damageOverride; |
3335 | 3475 | } |
3336 | 3476 |
|
3337 | 3477 | private Class<? extends Event> resolveEventClass(String eventName) throws ClassNotFoundException { |
|
0 commit comments