Skip to content

feat(event): add ProtectionCreateEvent for player protection actions#17

Open
TheBjoRedCraft wants to merge 11 commits intoversion/1.21.11from
feat/add-event
Open

feat(event): add ProtectionCreateEvent for player protection actions#17
TheBjoRedCraft wants to merge 11 commits intoversion/1.21.11from
feat/add-event

Conversation

@TheBjoRedCraft
Copy link
Member

No description provided.

@TheBjoRedCraft TheBjoRedCraft self-assigned this Mar 16, 2026
Copilot AI review requested due to automatic review settings March 16, 2026 16:29
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new Bukkit event intended to signal when a player successfully creates a protection, and updates Gradle version management to be driven via gradle.properties.

Changes:

  • Introduce ProtectionCreateEvent (custom PlayerEvent) for protection creation.
  • Hook the event into the successful protection purchase/creation flow.
  • Move project version configuration to gradle.properties and read it from the build script.

Reviewed changes

Copilot reviewed 3 out of 4 changed files in this pull request and generated 2 comments.

File Description
src/main/kotlin/dev/slne/surf/protect/paper/region/ProtectionRegion.kt Attempts to emit ProtectionCreateEvent after successful protection creation.
src/main/kotlin/dev/slne/surf/protect/paper/event/ProtectionCreateEvent.kt Adds the new custom Bukkit event class.
gradle.properties Adds centralized version property (and Kotlin code style setting).
build.gradle.kts Reads version from Gradle properties instead of hardcoding it.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

JoField08
JoField08 previously approved these changes Mar 16, 2026
Copilot AI review requested due to automatic review settings March 21, 2026 13:25
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new Bukkit/Paper event to signal when a player successfully creates a protection region, and wires it into the region purchase/creation flow (with additional spawn-protection handling and build versioning updates).

Changes:

  • Introduce ProtectionCreateEvent and fire it after a successful protection purchase.
  • Add a new region creation state for spawn-protected areas and introduce checks for “too near to spawn”.
  • Move project versioning into gradle.properties and read it from build.gradle.kts.

Reviewed changes

Copilot reviewed 4 out of 5 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/main/kotlin/dev/slne/surf/protect/paper/region/info/RegionCreationState.kt Adds TOO_NEAR_FROM_SPAWN state for region creation outcomes.
src/main/kotlin/dev/slne/surf/protect/paper/region/ProtectionRegion.kt Adds spawn-distance validation, fires ProtectionCreateEvent on success, and runs the event call on the global dispatcher.
src/main/kotlin/dev/slne/surf/protect/paper/event/ProtectionCreateEvent.kt New Bukkit event class emitted on protection creation.
gradle.properties Adds kotlin.code.style=official and defines a shared version property.
build.gradle.kts Uses the version Gradle property instead of a hardcoded string.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copilot AI review requested due to automatic review settings March 21, 2026 22:02
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 7 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copilot AI review requested due to automatic review settings March 22, 2026 09:48
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 9 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copilot AI review requested due to automatic review settings March 23, 2026 15:34
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 15 changed files in this pull request and generated 9 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +417 to +430
val state = flag.initialState ?: StateFlag.State.ALLOW

if (flag.isPlayerRelated) {
region.setFlag(flag.flag.regionGroupFlag, RegionGroup.NON_MEMBERS)
region.setFlag(flag.flag, state)

region.setFlag(flag.flag.regionGroupFlag, RegionGroup.MEMBERS)
region.setFlag(flag.flag, StateFlag.State.ALLOW)

continue
}

region.setFlag(flag.flag, state)
}
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For non-player-related flags where initialState is null, applyDefaultFlags falls back to ALLOW and explicitly sets the flag. Previously those flags were left unset (null) during region creation, allowing parent/global region settings to apply. Explicitly forcing ALLOW changes behavior in setups that rely on global denies and can unintentionally override higher-level protection policies. Consider skipping setFlag when initialState is null (or only applying defaults for isPlayerRelated flags here).

Copilot uses AI. Check for mistakes.
Comment on lines +93 to 97
render.layoutSlot('P')
.updateOnStateChange(paginationState)
.displayIf { _ ->
pagination.canBack()
}
.onRender { slotRender ->
if (pagination.canBack()) {
slotRender.item = previousItem
} else {
slotRender.item = outlineItem
}
.onRender {
if (pagination.canBack()) previousItem else outlineItem
}
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The .onRender { if (pagination.canBack()) previousItem else outlineItem } block doesn't assign the computed item to the slot (contrast with other views that do slotRender.item = ...). If onRender here is the usual (SlotRender) -> Unit, this will result in the slot not updating. Consider using the slotRender parameter and setting slotRender.item explicitly (and same for the next-page slot).

Copilot uses AI. Check for mistakes.
Comment on lines +134 to +148
private fun applyState(
region: ProtectedRegion,
flag: EditableProtectionFlags,
state: StateFlag.State
) {
if (flag.isPlayerRelated) {
region.setFlag(flag.flag, StateFlag.State.ALLOW)
if (state == StateFlag.State.ALLOW) {
region.setFlag(flag.flag.regionGroupFlag, null)
} else {
region.setFlag(flag.flag.regionGroupFlag, RegionGroup.MEMBERS)
}
} else {
region.setFlag(flag.flag, state)
}
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

applyState for player-related flags sets the flag value to ALLOW and only toggles regionGroupFlag between null and MEMBERS. With WorldGuard's group flag semantics, setting group=MEMBERS + ALLOW does not deny non-members (it just makes the flag not apply to them, so they can still be allowed by defaults/parents). To enforce “members-only”, set StateFlag=DENY with regionGroupFlag=NON_MEMBERS; to allow everyone, set StateFlag=ALLOW with regionGroupFlag=null/ALL (or clear both).

Copilot uses AI. Check for mistakes.
Comment on lines +38 to +50
if (playerName.isEmpty() || playerName.isBlank() || playerName.length > 16) {
player.sendText {
appendErrorPrefix()
error("Der Spielername ist ungültig.")
}
player.closeDialog()
viewFrame.open(
ProtectionMemberListView::class.java,
player,
mapOf("protection" to protection)
)
return
}
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the new invalid-name validation, closing the dialog (which currently triggers onClose -> handleAdd(...)) will now show an error (“Spielername ist ungültig.”) and reopen the member list even if the user simply cancelled. Consider changing onClose to behave like a cancel action (navigate back without attempting to add), and keep handleAdd only for onSearch.

Copilot uses AI. Check for mistakes.
private fun createMemberItem(member: OfflinePlayer) = buildItem(Material.PLAYER_HEAD) {
displayName {
protectColored(member.displayName.toSmallCaps(), TextDecoration.BOLD)
protectColored(member.name?.toSmallCaps() ?: "#Unknown", TextDecoration.BOLD)
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fallback name "#Unknown" is English while the rest of the UI/messages in this view are German (and elsewhere you use #Unbekannt). Consider using a consistent localized fallback string here as well.

Suggested change
protectColored(member.name?.toSmallCaps() ?: "#Unknown", TextDecoration.BOLD)
protectColored(member.name?.toSmallCaps() ?: "#Unbekannt", TextDecoration.BOLD)

Copilot uses AI. Check for mistakes.
Comment on lines +400 to 404
withContext(plugin.globalRegionDispatcher) {
protectionUser.bukkitPlayer?.let {
ProtectionCreateEvent(it).callEvent()
}
}
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ProtectionCreateEvent is a PlayerEvent, so it should be fired from the correct Folia thread context for that player. globalRegionDispatcher doesn't guarantee entity-thread safety for player-bound operations; prefer plugin.entityDispatcher(player) (or another player/region-appropriate dispatcher) when calling Bukkit/Paper APIs like event dispatch.

Copilot uses AI. Check for mistakes.
Comment on lines +423 to +425
region.setFlag(flag.flag.regionGroupFlag, RegionGroup.MEMBERS)
region.setFlag(flag.flag, StateFlag.State.ALLOW)

Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

applyDefaultFlags currently sets the RegionGroup flag twice for player-related flags (NON_MEMBERS and then MEMBERS), and also overwrites the StateFlag value (state then ALLOW). The second assignment wins, so the final configuration is effectively group=MEMBERS and state=ALLOW, which does not enforce “deny non-members / allow members” as intended. Suggestion: for player-related flags, set regionGroupFlag = NON_MEMBERS and keep the flag state as DENY (or whatever initialState is), without later overwriting it; this makes the deny apply only to non-members while members are unaffected.

Suggested change
region.setFlag(flag.flag.regionGroupFlag, RegionGroup.MEMBERS)
region.setFlag(flag.flag, StateFlag.State.ALLOW)

Copilot uses AI. Check for mistakes.
Comment on lines +114 to +123
private fun getCurrentState(
region: ProtectedRegion,
flag: EditableProtectionFlags
): StateFlag.State {
return if (flag.isPlayerRelated) {
val group = region.getFlag(flag.flag.regionGroupFlag)
if (group == RegionGroup.MEMBERS) StateFlag.State.DENY else StateFlag.State.ALLOW
} else {
region.getFlag(flag.flag) ?: flag.initialState ?: StateFlag.State.ALLOW
}
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getCurrentState for isPlayerRelated flags is derived from regionGroupFlag == MEMBERS, but (a) the default setup in applyDefaultFlags uses NON_MEMBERS for the “members-only” intent, and (b) the actual StateFlag value is ignored. This will make the UI show the wrong state and toggle from an incorrect baseline. Consider mapping the UI state from the combination of StateFlag value + regionGroupFlag (e.g. DENY + NON_MEMBERS => “Nur für Mitglieder”, otherwise => “Für alle erlaubt”).

Copilot uses AI. Check for mistakes.
Comment on lines +66 to +70
viewFrame.open(
ProtectionInfoView::class.java,
player,
mapOf("protection" to protection)
)
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On validation failures you open ProtectionInfoView, but the dialog isn't closed in these early-return branches. This can leave the search dialog still open (or re-openable) on top of the inventory UI. Consider calling player.closeDialog() before opening the view (same applies to the other early-return validations in this function).

Copilot uses AI. Check for mistakes.
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

Successfully merging this pull request may close these issues.

3 participants