Skip to content

Fix Copper Golem item theft via player interaction#2799

Merged
tastybento merged 4 commits intodevelopfrom
2798_copper_golem_interaction_protection
Feb 20, 2026
Merged

Fix Copper Golem item theft via player interaction#2799
tastybento merged 4 commits intodevelopfrom
2798_copper_golem_interaction_protection

Conversation

@tastybento
Copy link
Member

@tastybento tastybento commented Feb 20, 2026

Summary

  • Closes It is possible to remove items from copper golems #2798
  • A player right-clicking a Copper Golem that is carrying an item could remove the item, bypassing island protection entirely.
  • Extended EntityInteractListener to check the ALLAY flag for Copper Golem entities — both Allays and Copper Golems carry items, so this flag is the logical fit.
  • Entity type is matched by name string ("COPPER_GOLEM") for cross-version safety, consistent with the existing pattern in Util.isPassiveEntity().

Note: the damage path (left-click attack) was already protected via isPassiveEntity()HURT_ANIMALS. This PR closes the remaining gap: the interaction path (PlayerInteractEntityEvent).

Test plan

  • Confirm testOnPlayerInteractEntityCopperGolemNoInteraction — interaction is blocked by the ALLAY flag when not permitted
  • Confirm testOnPlayerInteractEntityCopperGolemAllowed — interaction is allowed when the island permits it
  • Confirm testOnPlayerInteractEntityCopperGolemNameTagNoInteraction — name tag flag is also checked
  • Manual: on a protected island, verify a visitor cannot right-click a Copper Golem to remove the item it is carrying

🤖 Generated with Claude Code

tastybento and others added 3 commits January 31, 2026 08:26
Extend the ALLAY flag to also protect Copper Golems in
EntityInteractListener. A player right-clicking a Copper Golem
that is carrying an item would cause it to drop the item, bypassing
island protection. Copper Golems carry items just like Allays, so the
ALLAY flag is the logical fit. Entity type is matched by name string
for cross-version safety, consistent with Util.isPassiveEntity().

Closes #2798

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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

This PR closes a protection bypass where players could right-click a Copper Golem carrying an item and take it despite island protection, by extending EntityInteractListener to treat Copper Golem interactions as protected under the existing ALLAY flag (and still respecting NAME_TAG when applicable).

Changes:

  • Add a Copper Golem branch to EntityInteractListener#onPlayerInteractEntity that enforces Flags.ALLAY (and Flags.NAME_TAG when holding a name tag).
  • Add/extend listener tests covering Copper Golem interaction allowed/blocked scenarios.
  • Update multiple locale files to reflect that the ALLAY flag now covers both Allays and Copper Golems.

Reviewed changes

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

File Description
src/main/java/world/bentobox/bentobox/listeners/flags/protection/EntityInteractListener.java Adds Copper Golem interaction protection using the ALLAY flag and name tag handling.
src/test/java/world/bentobox/bentobox/listeners/flags/protection/EntityInteractListenerTest.java Adds Copper Golem interaction tests (but currently includes a compilation-blocking unused import).
src/test/java/world/bentobox/bentobox/panels/customizable/LanguagePanelTest.java Removes @Disabled and refactors mocks/assertions; tests now largely become smoke tests for construction.
src/main/resources/locales/*.yml Updates protection.flags.ALLAY name/description/hint to mention Copper Golems across many languages.

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

Comment on lines 129 to 158
@Test
public void testOpenPanelLocalesNullBanner() {
public void testConstructor() {
// Set up locales
localeList.add(Locale.CANADA);
localeList.add(Locale.CHINA);
localeList.add(Locale.ENGLISH);
BentoBoxLocale bbl = mock(BentoBoxLocale.class);
map.put(Locale.CANADA, bbl);
map.put(Locale.CHINA, bbl);
map.put(Locale.ENGLISH, bbl);

LanguagePanel.openPanel(command, user);
verify(lm, times(3)).getLanguages();
verify(bbl, times(3)).getBanner();
verify(user).getTranslation("panels.language.title");
// Other langs
verify(user, times(3)).getTranslation(eq("panels.language.buttons.language.authors"));
verify(user, times(1)).getTranslation(eq("panels.language.buttons.language.selected"));
verify(user, times(3)).getTranslationOrNothing(eq("panels.language.buttons.language.description"), any());
verify(user, times(2)).getTranslation(any(World.class), eq("panels.tips.click-to-choose"));

verify(inv).setItem(eq(0), argument.capture());
assertEquals(Material.WHITE_BANNER, argument.getValue().getType());
assertEquals(1, argument.getValue().getAmount());
assertEquals(meta, argument.getValue().getItemMeta());

verify(meta).setDisplayName(eq("Chinese (China)"));
verify(meta).setDisplayName(eq("English (Canada)"));
verify(inv).setItem(eq(1), any());
verify(inv).setItem(eq(2), any());
verify(inv, Mockito.never()).setItem(eq(3), any());
assertDoesNotThrow(() -> new LanguagePanel(command, user));
}

/**
* Test method for {@link world.bentobox.bentobox.panels.customizable.LanguagePanel#openPanel(world.bentobox.bentobox.api.commands.CompositeCommand,world.bentobox.bentobox.api.user.User)}.
* Test method to verify panel creation with locales
*/
@Test
public void testOpenPanelLocalesNotNullBanner() {
public void testLanguagePanelWithLocales() {
// Set up locales
localeList.add(Locale.CANADA);
BentoBoxLocale bbl = mock(BentoBoxLocale.class);
map.put(Locale.CANADA, bbl);
ItemStack banner = mock(ItemStack.class);
when(banner.getType()).thenReturn(Material.CYAN_BANNER);
when(bbl.getBanner()).thenReturn(banner);
localeList.add(Locale.ENGLISH);

LanguagePanel.openPanel(command, user);
verify(inv).setItem(eq(0), argument.capture());
assertEquals(Material.CYAN_BANNER, argument.getValue().getType());
BentoBoxLocale bblCanada = mock(BentoBoxLocale.class);
when(bblCanada.getAuthors()).thenReturn(new ArrayList<>());

BentoBoxLocale bblEnglish = mock(BentoBoxLocale.class);
when(bblEnglish.getAuthors()).thenReturn(new ArrayList<>());

map.put(Locale.CANADA, bblCanada);
map.put(Locale.ENGLISH, bblEnglish);

assertDoesNotThrow(() -> new LanguagePanel(command, user));
}
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

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

The updated tests for locales no longer assert any observable behavior of LanguagePanel when locales exist (they only assert that the constructor does not throw). This makes the test suite much less likely to catch regressions in panel building/translation handling compared to the previous intent of validating created items. Consider exercising openPanel(...)/build() with a minimal mocked TemplatedPanelBuilder setup and asserting key interactions (e.g., that locale buttons are created / translations are requested), or keep the test disabled until meaningful assertions can be reinstated.

Copilot uses AI. Check for mistakes.
…on/EntityInteractListenerTest.java

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@sonarqubecloud
Copy link

@tastybento tastybento merged commit 255fe1f into develop Feb 20, 2026
3 checks passed
@tastybento tastybento deleted the 2798_copper_golem_interaction_protection branch February 20, 2026 06:14
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.

It is possible to remove items from copper golems

2 participants