This page is only available in Korean for now.

프로젝트 이벤트는 플러그인이 스크립트의 함수를 부르는 통로예요. StarLight의 기본 이벤트(메시지 수신 등)도 같은 방식으로 동작해요. 플러그인이 이벤트를 등록하면 사용자는 프로젝트 설정의 이벤트 목록에서 그 이벤트를 허용하고, 스크립트에 이벤트 함수를 작성해요.

이벤트 정의

ProjectEvent를 상속해요.

AlarmEvent.kt
class AlarmEvent : ProjectEvent() {

    // 카테고리 안에서의 ID예요. 영문, 숫자, -, _만 쓸 수 있어요.
    override val id: String = "alarm"

    // 이벤트 목록에 보이는 이름이에요.
    override val name: String = translate {
        Locale.ENGLISH { "Alarm" }
        Locale.KOREAN  { "알람" }
    }

    // 스크립트에서 작성할 함수 이름이에요.
    override val functionName: String = "onAlarm"

    // 함수 인자의 이름과 형식이에요. 호출할 때 형식을 검사해요.
    override val argTypes: Array<CodeGenerator.Argument<*>> = arrayOf(
        "time"  typedAs String::class,
        "label" typedAs String::class,
    )

    // 새 프로젝트를 만들 때 함수 위에 붙는 주석이에요. (선택)
    override val functionComment: String = "알람이 울릴 때 호출돼요."

    // 이벤트 목록에서 이름과 함께 보이는, 이벤트가 일어나는 때예요. (선택, PluginCore 1.0.0 이상)
    override val description: String = translate {
        Locale.ENGLISH { "When an alarm goes off" }
        Locale.KOREAN  { "알람이 울릴 때" }
    }
}

프로젝트 설정의 받을 이벤트 목록은 이벤트마다 usage, name, description, 이벤트 ID를 보여 줘요. usage는 스크립트가 이벤트를 받는 방법이고, 기본값은 onAlarm(time, label)처럼 함수 이름과 인자예요. 함수가 아닌 다른 방법으로 전달하는 이벤트라면 usage를 바꾸고, dispatch()와 generateCode()를 재정의해 전달 방법과 새 프로젝트의 기본 코드를 정할 수 있어요.

typedAs는 ProjectEvent 안에서 쓸 수 있는 중위 함수예요. typedAs<String>("time") 형태로도 쓸 수 있어요.

등록

onEnable()에서 registerProjectEvents { }로 등록해요. 이벤트는 반드시 카테고리 안에 넣어야 해요.

ClockPlugin.kt
override fun onEnable() {
    registerProjectEvents {
        category("clock") {
            add<AlarmEvent>()
        }
    }
}

이벤트의 전체 ID는 <플러그인 ID>.<카테고리>.<이벤트 ID> 예요. 플러그인 ID가 clock이라면 위 이벤트는 clock.clock.alarm이 돼요. 카테고리는 category("a") { category("b") { … } }처럼 중첩할 수 있어요.

팁

웹 서버 플러그인은 category("server") { add<WebServerSetupEvent>() }로 webserver.server.setup 이벤트를 등록해요.

사용자 쪽

  1. 프로젝트 설정의 받을 이벤트에서 플러그인의 이벤트를 체크해요. 이벤트는 플러그인별로 묶여 있고, 프로젝트의 API 방식과 상관없이 받을 수 있어요. ID 직접 편집에서는 와일드카드도 쓸 수 있어서, clock.*은 clock 플러그인의 모든 이벤트를 받아요.
  2. 스크립트에 functionName과 같은 이름의 함수를 작성해요.
main.js (Rhino)
function onAlarm(time, label) {
    Api.replyRoom("알림방", time + " " + label);
}
main.js (NeonJS)
// NeonJS 프로젝트는 ES 모듈이라 이벤트 함수를 export 해야 해요.
export function onAlarm(time, label) {
    console.log(`${time} ${label}`);
}

새 프로젝트를 만들 때 이벤트를 고르면 함수 틀과 functionComment가 기본 코드에 들어가요. 함수 이름이 같은 이벤트가 둘 이상이면 처음 것만 함수로 만들고 나머지는 주석 처리해요.

이벤트 호출

모든 프로젝트에 보내기

fireProjectEvent<T>()는 이 이벤트를 받을 수 있는 모든 프로젝트의 함수를 호출해요.

Kotlin
fireProjectEvent<AlarmEvent>("07:30", "기상") { project, e ->
    log.error { "${project.info.name}에서 onAlarm 실행 실패: ${e.message}" }
}

호출되는 프로젝트는 아래 조건을 모두 만족해야 해요.

  • 컴파일되어 있어요(project.isCompiled).
  • 켜져 있어요(project.info.isEnabled).
  • 받을 이벤트에 이 이벤트가 들어 있어요(project.isEventCallAllowed(eventId)).

프로젝트 하나에 보내기

Kotlin
val called: Boolean = project.fireEvent<AlarmEvent>("07:30", "기상") { e ->
    log.error { "onAlarm 실행 실패: ${e.message}" }
}

Project.fireEvent<T>()는 프로젝트가 이벤트를 허용하지 않으면 false를 돌려줘요. fireProjectEvent<T>()와 달리 컴파일 여부나 켜짐 여부는 확인하지 않으므로, 필요하면 project.isCompiled, project.info.isEnabled를 먼저 확인하세요.

직접 호출하기

이벤트 ID가 필요하거나 호출 조건을 직접 정하고 싶다면 ProjectEventManager와 Project.callFunction()을 써요. 웹 서버 플러그인이 쓰는 방식이에요.

Kotlin
val eventId = ProjectEventManager.validateAndGetEventID(AlarmEvent::class) ?: return
if (project.isCompiled && project.isEventCallAllowed(eventId)) {
    project.callFunction("onAlarm", arrayOf("07:30", "기상")) { e ->
        log.error { "onAlarm 실행 실패: ${e.message}" }
    }
}

인자 검사

fireProjectEvent와 Project.fireEvent는 함수를 호출하기 전에 인자를 검사해요.

  • 넘긴 인자 수가 argTypes보다 많으면 예외가 발생해요.
  • 각 인자가 argTypes의 형식(또는 그 하위 형식)이 아니면 예외가 발생해요.
  • 등록하지 않은 이벤트로 호출해도 예외가 발생해요.

스크립트 안에서 생긴 오류는 예외로 던지지 않고 onFailure/onException 콜백으로 전달돼요.

다음 단계