summaryrefslogtreewikicommitdiff
path: root/bukkit/src/event/PacketListener.kt
blob: d49af6093229a0b1bfca9fdb4c4c1b4b93dc9d50 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
package cat.freya.khs.bukkit.event

import cat.freya.khs.bukkit.BukkitKhsPlayer
import cat.freya.khs.bukkit.KhsPlugin
import cat.freya.khs.bukkit.disguise.Disguise
import cat.freya.khs.event.DamageEvent
import cat.freya.khs.event.onDamage
import com.github.retrooper.packetevents.PacketEvents
import com.github.retrooper.packetevents.event.PacketListener as PacketListenerPE
import com.github.retrooper.packetevents.event.PacketListenerPriority
import com.github.retrooper.packetevents.event.PacketReceiveEvent
import com.github.retrooper.packetevents.event.PacketSendEvent
import com.github.retrooper.packetevents.protocol.packettype.PacketType.Play.Client.INTERACT_ENTITY
import com.github.retrooper.packetevents.protocol.packettype.PacketType.Play.Server.*
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity
import com.github.retrooper.packetevents.wrapper.play.server.*
import java.util.UUID
import org.bukkit.GameMode
import org.bukkit.attribute.Attribute
import org.bukkit.entity.Player as BukkitPlayer

class PacketListener(val plugin: KhsPlugin) : PacketListenerPE {
    private val debounce = mutableSetOf<UUID>()

    init {
        PacketEvents.getAPI().eventManager.registerListener(this, PacketListenerPriority.NORMAL)
    }

    // intercept entity-related packets of entities that
    // are supposed to be hidden
    override fun onPacketSend(event: PacketSendEvent) {
        val player = event.getPlayer() as? BukkitPlayer ?: return
        val entityId =
            when (event.packetType) {
                ENTITY_EQUIPMENT -> WrapperPlayServerEntityEquipment(event).entityId
                ENTITY_ANIMATION -> WrapperPlayServerEntityAnimation(event).entityId
                SPAWN_ENTITY -> WrapperPlayServerSpawnEntity(event).entityId
                ENTITY_VELOCITY -> WrapperPlayServerEntityVelocity(event).entityId
                ENTITY_HEAD_LOOK -> WrapperPlayServerEntityHeadLook(event).entityId
                ENTITY_TELEPORT -> WrapperPlayServerEntityTeleport(event).entityId
                ENTITY_STATUS -> WrapperPlayServerEntityStatus(event).entityId
                ENTITY_METADATA -> WrapperPlayServerEntityMetadata(event).entityId
                ENTITY_EFFECT -> WrapperPlayServerEntityEffect(event).entityId
                REMOVE_ENTITY_EFFECT -> WrapperPlayServerRemoveEntityEffect(event).entityId
                else -> return
            }

        if (!plugin.entityHider.isVisible(player, entityId)) {
            event.setCancelled(true)
        }
    }

    // check when a player is trying to attack a disguise
    override fun onPacketReceive(event: PacketReceiveEvent) {
        val player = event.getPlayer() as? BukkitPlayer ?: return

        // we want interact event
        if (event.packetType != INTERACT_ENTITY) return

        val packet = WrapperPlayClientInteractEntity(event)

        // attacking only
        val action = packet.action ?: return
        if (action != WrapperPlayClientInteractEntity.InteractAction.ATTACK) return

        val disguise =
            plugin.disguiser.getByEntityId(packet.entityId)
                ?: plugin.disguiser.getByHitboxId(packet.entityId)
                ?: return

        if (disguise.player.gameMode == GameMode.CREATIVE) return

        event.setCancelled(true)
        handleAttack(disguise, player)
    }

    private fun handleAttack(disguise: Disguise, seeker: BukkitPlayer) {
        if (disguise.player.uniqueId == seeker.uniqueId) return

        val fallbackAmount = 7.0
        val amount =
            if (plugin.shim.supports(9)) {
                val attribName =
                    if (plugin.shim.supports(21)) "ATTACK_DAMAGE" else "GENERIC_ATTACK_DAMAGE"
                val attrib = Attribute.valueOf(attribName)
                seeker.getAttribute(attrib)?.value ?: fallbackAmount
            } else {
                fallbackAmount // uhhh i dunno how to do this for 1.8
            }

        val debounceUUID = disguise.player.uniqueId

        disguise.shouldBeSolid = false
        if (debounce.contains(debounceUUID)) return

        // trigger an attack event
        val khsPlayer = BukkitKhsPlayer(plugin.shim, disguise.player)
        val khsSeeker = BukkitKhsPlayer(plugin.shim, seeker)
        val khsEvent = DamageEvent(plugin.khs, khsPlayer, khsSeeker, amount)
        onDamage(khsEvent)

        // set and soon turn off debounce
        debounce.add(debounceUUID)
        plugin.server.scheduler.scheduleSyncDelayedTask(
            plugin,
            { debounce.remove(debounceUUID) },
            10,
        )
    }
}