Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EntityDamageByPsychicEvent의 getEntity에서 문제가 생겼습니다. #109

Open
bucket1582 opened this issue Dec 31, 2020 · 3 comments
Open

Comments

@bucket1582
Copy link

bucket1582 commented Dec 31, 2020

개요

플레이어가 공격을 받았을 때 카운터 공격을 하는 능력을 개발하는 중에, 초능력에 의해 공격을 당했는지 확인하는 코드를 체크하기 위해 다음과 같은 코드를 작성했습니다.

현재 코드
package proj.science.bucket1572.mathematics.function.inversefunction

import com.github.noonmaru.psychics.Ability
import com.github.noonmaru.psychics.AbilityConcept
import com.github.noonmaru.psychics.AbilityType
import com.github.noonmaru.psychics.attribute.EsperAttribute
import com.github.noonmaru.psychics.attribute.EsperStatistic
import com.github.noonmaru.psychics.damage.Damage
import com.github.noonmaru.psychics.damage.DamageType
import com.github.noonmaru.psychics.event.EntityDamageByPsychicEvent
import com.github.noonmaru.psychics.item.isPsychicbound
import com.github.noonmaru.tap.config.Config
import com.github.noonmaru.tap.config.Name
import net.md_5.bungee.api.ChatColor
import org.bukkit.Material
import org.bukkit.enchantments.Enchantment
import org.bukkit.entity.Player
import org.bukkit.event.EventHandler
import org.bukkit.event.Listener
import org.bukkit.inventory.ItemStack
import java.lang.ClassCastException

@Name("concept")
class InverseFunctionConcept : AbilityConcept(){
    @Config
    var coefficient : Double = 1.0

    init {
        type = AbilityType.PASSIVE
        displayName = "역함수"
        levelRequirement = 0
        cooldownTicks = 0
        cost = 0.0
        castingTicks = 0

        val invFunction = ItemStack(Material.BARRIER, 1)
        invFunction.apply {
            val meta = itemMeta
            meta.setDisplayName("${ChatColor.GREEN}${ChatColor.BOLD}역함수 카운터")
            meta.addEnchant(Enchantment.DAMAGE_UNDEAD, 1, false)
            meta.lore = listOf(
                "받은 만큼 되갚아주는 함수의 카운터"
            )
            meta.isPsychicbound = true
            itemMeta = meta
        }
        wand = invFunction
        supplyItems = listOf(
            invFunction
        )
        description = listOf(
            "자신이 다른 사람의 ${ChatColor.BOLD}${ChatColor.RED}원거리 초능력 공격${ChatColor.WHITE}에 의해",
            "피해를 입을 경우, 즉시 초능력을 사용한 대상에게",
            "(받은 피해) × (${coefficient})만큼의 피해를 입힙니다.",
            "",
            "${ChatColor.ITALIC}어떤 함수가 가역함수일 필요충분조건은",
            "${ChatColor.ITALIC}그 함수가 일대일대응인 것이다."
        )
    }
}

class InverseFunction : Ability<InverseFunctionConcept>(), Listener {

    override fun onEnable() {
        psychic.registerEvents(this)
        psychic.runTaskTimer(Debug(), 20L, 80L)
    }

    private inner class Debug : Runnable {
        override fun run() {
            if (esper.player.inventory.contains(concept.wand)) {
                esper.player.psychicDamage(
                    Damage(DamageType.MELEE, EsperStatistic.of(EsperAttribute.ATTACK_DAMAGE to 2.0))
                )
            }
        }
    }

    @EventHandler
    fun onAttackedByPsychic(event: EntityDamageByPsychicEvent) {
        try {
            esper.player.sendActionBar("공격당했습니다.")
        } catch (error: ClassCastException) {
            esper.player.sendActionBar("사람이 아닙니다.")
        }
    }
}

yml 파일도 적절히 작성하여, 서버를 구동하고, 능력을 불러오는 것까지는 문제가 없었습니다.

yml 파일
abilities:
  exp-function:
    ability: proj.science.bucket1572.exponentialfunction
    common:
      display-name: 지수함수
      type: ACTIVE
      interruptible: false
      range: 40.0
      wand:
        v: 2580
        type: NETHER_STAR
        meta:
          ==: ItemMeta
          meta-type: UNSPECIFIC
          display-name: §4§l지수함수 런쳐
          lore:
          - 멀어질수록 강해지는 함수의 공격기
          - §c§lPsychicbound
          enchants:
            DAMAGE_UNDEAD: 1
      supply-items:
      - ==: org.bukkit.inventory.ItemStack
        v: 2580
        type: NETHER_STAR
        meta:
          ==: ItemMeta
          meta-type: UNSPECIFIC
          display-name: §4§l지수함수 런쳐
          lore:
          - 멀어질수록 강해지는 함수의 공격기
          - §c§lPsychicbound
          enchants:
            DAMAGE_UNDEAD: 1
      description:
      - 자신이 바라보는 방향으로 발사체를 발사합니다.
      - 발사체의 궤적은 y=2.0^x의 그래프의 일부와 같습니다.
      - 피격 대상은 발사체의 평면 상 이동거리를 30.0으로 나눈 x에 대하여,
      - 2.0^x의 피해를 입습니다.
      - ''
      - §o아-- 원리합계 계산 문제 싫다~.
    concept:
      base: 2.0
      max-ticks: 200
      knockback: 1.0
      projectile-speed: 1.0
      scale: 10.0
      damage-scale: 1.0
  inv-function:
    ability: proj.science.bucket1572.inversefunction
    common:
      display-name: 역함수
      type: PASSIVE
      interruptible: false
      wand:
        v: 2580
        type: BARRIER
        meta:
          ==: ItemMeta
          meta-type: UNSPECIFIC
          display-name: §a§l역함수 카운터
          lore:
          - 받은 만큼 되갚아주는 함수의 카운터
          - §c§lPsychicbound
          enchants:
            DAMAGE_UNDEAD: 1
      supply-items:
      - ==: org.bukkit.inventory.ItemStack
        v: 2580
        type: BARRIER
        meta:
          ==: ItemMeta
          meta-type: UNSPECIFIC
          display-name: §a§l역함수 카운터
          lore:
          - 받은 만큼 되갚아주는 함수의 카운터
          - §c§lPsychicbound
          enchants:
            DAMAGE_UNDEAD: 1
      description:
      - 자신이 다른 사람의 §l§c원거리 초능력 공격§f에 의해
      - 피해를 입을 경우, 즉시 초능력을 사용한 대상에게
      - (받은 피해) × (1.0)만큼의 피해를 입힙니다.
      - ''
      - §o어떤 함수가 가역함수일 필요충분조건은 그 함수가 일대일대응인 것이다.
    concept:
      coefficient: 1.0
display-name: Function
health-bonus: 0.0
health-regen-per-tick: 2.0
mana: 100.0
mana-regen-per-tick: 2.0
mana-color: BLUE
description:
- 기하학

주석을 달지 않아서 죄송한 말씀 드립니다. 대신 현재 코드를 간략하게 요약하자면, 능력 wand를 가지고 있으면 4초마다 능력에 의해 피해를 입고, 액션바에 공격을 당했습니다. 라는 문구가 나오는 코드입니다. 실제로 게임 내에서도 4초마다 해당 메시지가 출력되는 것을 확인할 수 있었습니다.

문제

그런데 정상적으로 작동하던 다른 능력으로 플레이어가 아닌 엔티티에 공격을 하였을 때 문제가 발생하였습니다. 능력의 구현이나 작동에는 문제가 없었지만, 서버 커맨드 창에 다음과 같은 예외가 발생했습니다.

발생한 예외
[13:22:07 ERROR]: Could not pass event EntityDamageByPsychicEvent to Psychics v0.9.3
java.lang.ClassCastException: org.bukkit.craftbukkit.v1_16_R2.entity.CraftSheep cannot be cast to org.bukkit.entity.Player
        at com.github.noonmaru.psychics.event.EntityDamageByPsychicEvent.getEntity(EntityDamageByPsychicEvent.java:50) ~[?:?]
        at com.github.noonmaru.psychics.event.EntityDamageByPsychicEvent.getEntity(EntityDamageByPsychicEvent.java:14) ~[?:?]
        at com.github.noonmaru.psychics.tap.event.DefaultProvider$EntityEntityProvider.getFrom(DefaultProvider.java:89) ~[?:?]
        at com.github.noonmaru.psychics.tap.event.DefaultProvider$EntityEntityProvider.getFrom(DefaultProvider.java:87) ~[?:?]
        at com.github.noonmaru.psychics.tap.event.EntityEventManager$EventListener.onEvent(EntityEventManager.java:136) ~[?:?]
        at com.github.noonmaru.psychics.tap.event.EntityEventManager.lambda$new$0(EntityEventManager.java:49) ~[?:?]
        at co.aikar.timings.TimedEventExecutor.execute(TimedEventExecutor.java:80) ~[patched_1.16.3.jar:git-Paper-228]
        at org.bukkit.plugin.RegisteredListener.callEvent(RegisteredListener.java:70) ~[patched_1.16.3.jar:git-Paper-228]
        at org.bukkit.plugin.SimplePluginManager.callEvent(SimplePluginManager.java:607) ~[patched_1.16.3.jar:git-Paper-228]
        at org.bukkit.event.Event.callEvent(Event.java:45) ~[patched_1.16.3.jar:git-Paper-228]
        at com.github.noonmaru.psychics.damage.DamageSupportKt.psychicDamage(DamageSupport.kt:170) ~[?:?]
        at com.github.noonmaru.psychics.Ability.psychicDamage(Ability.kt:153) ~[?:?]
        at proj.science.bucket1572.mathematics.function.exponentialfunction.ExponentialFunction$Dummy.onTrail(ExponentialFunction.kt:166) ~[?:?]
        at com.github.noonmaru.psychics.tap.fake.FakeProjectile.update$api(FakeProjectile.kt:140) ~[?:?]
        at com.github.noonmaru.psychics.tap.fake.FakeProjectileManager.updateProjectiles(FakeProjectileManager.kt:47) ~[?:?]
        at com.github.noonmaru.psychics.tap.fake.FakeProjectileManager.update(FakeProjectileManager.kt:37) ~[?:?]
        at com.github.noonmaru.psychics.Psychic.update$psychics_common(Psychic.kt:452) ~[?:?]
        at com.github.noonmaru.psychics.plugin.SchedulerTask.run(SchedulerTask.kt:32) ~[?:?]
        at org.bukkit.craftbukkit.v1_16_R2.scheduler.CraftTask.run(CraftTask.java:99) ~[patched_1.16.3.jar:git-Paper-228]
        at org.bukkit.craftbukkit.v1_16_R2.scheduler.CraftScheduler.mainThreadHeartbeat(CraftScheduler.java:468) ~[patched_1.16.3.jar:git-Paper-228]
        at net.minecraft.server.v1_16_R2.MinecraftServer.b(MinecraftServer.java:1296) ~[patched_1.16.3.jar:git-Paper-228]
        at net.minecraft.server.v1_16_R2.DedicatedServer.b(DedicatedServer.java:371) ~[patched_1.16.3.jar:git-Paper-228]
        at net.minecraft.server.v1_16_R2.MinecraftServer.a(MinecraftServer.java:1211) ~[patched_1.16.3.jar:git-Paper-228]
        at net.minecraft.server.v1_16_R2.MinecraftServer.w(MinecraftServer.java:999) ~[patched_1.16.3.jar:git-Paper-228]
        at net.minecraft.server.v1_16_R2.MinecraftServer.lambda$a$0(MinecraftServer.java:177) ~[patched_1.16.3.jar:git-Paper-228]
        at java.lang.Thread.run(Unknown Source) [?:1.8.0_201]

그래서 커맨드에서 문제가 발생한 부분을 확인했더니,

psychics-common/src/main/java/com/github/noonmaru/psychics/event/EntityDamageByPsychicEvent.java

의 50번째 줄 부분이었습니다.

오류 발생 부분
@NotNull
@Override
public Player getEntity() {
    return (Player) super.getEntity();
}

entity를 받아와서 Player로 Casting하는 중에 대상이 Player로 Casting할 수 없는 대상일 경우, ClassCastExcpetion에 빠지는 것 같았습니다. 물론, 능력 구현에 문제는 없지만, 서버 커맨드를 도배하고, 다른 문제가 발생할 가능성이 있으며, 능력을 구현할 때 따로 try catch로 잡는 것도 불가능해 보이기 때문에 이 부분을 수정할 필요가 있지 않을까 생각합니다. pull-request를 남겨볼까도 생각했지만, 아직 이 이벤트가 어떻게 상호작용하는지 구조를 파악하지 못해서 수정하기가 두렵더군요.

@bucket1582
Copy link
Author

물론 제가 작성한 코드에 문제가 있을 수도 있습니다. 하지만, 그렇다면 왜 문제가 일어나는지를 모르겠습니다.

@Alex4386
Copy link

Alex4386 commented Dec 31, 2020

해당 부분에서 Entity가 Player의 instance인지 확인하지 않아 문제인 것 같습니다.

해당 코드를

@NotNull
@Override
public Player getEntity() {
    Entity entity = super.getEntity();
    if (entity instanceof Player) {
        return (Player) super.getEntity();
    }
    return null;
}

형태로 변경이 필요할 것 같습니다. 제가 PR 만들어 수정하겠습니다.

추가적인 업데이트:
하지만, 이것은 공격 대상이 Player로 한정되기에 문제가 발생할 것 같습니다.

이걸 패치하면 Breaking Change 가 될 것 같은데... 이건 아마도 @noonmaru 님과 상의가 필요 할 것 같습니다.

@noonmaru
Copy link
Owner

헐 왜 저렇게 코딩했지 ㅋㅋ
수정하겠습니다

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants