mirror of
https://github.com/mcMMO-Dev/mcMMO.git
synced 2025-07-28 10:05:27 +02:00
Fix parties unintentionally becoming leader-less Fixes #3771
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
Version 2.2.040
|
Version 2.2.040
|
||||||
|
Fixed bug where a party leader could leave a party and the party would be left without a party leader
|
||||||
Fixed a bug where EcoEnchants or other similar plugins could cause an infinite loop within mcMMO
|
Fixed a bug where EcoEnchants or other similar plugins could cause an infinite loop within mcMMO
|
||||||
(Codebase) Updated Adventure Libs
|
(Codebase) Updated Adventure Libs
|
||||||
Added 'Happy_Ghast' to experience.yml for combat XP
|
Added 'Happy_Ghast' to experience.yml for combat XP
|
||||||
|
@@ -93,7 +93,7 @@ public class Party {
|
|||||||
public List<Player> getVisibleMembers(Player player) {
|
public List<Player> getVisibleMembers(Player player) {
|
||||||
ArrayList<Player> visibleMembers = new ArrayList<>();
|
ArrayList<Player> visibleMembers = new ArrayList<>();
|
||||||
|
|
||||||
for (Player p : onlineMembers) {
|
for (Player p : getOnlineMembers()) {
|
||||||
if (player.canSee(p)) {
|
if (player.canSee(p)) {
|
||||||
visibleMembers.add(p);
|
visibleMembers.add(p);
|
||||||
}
|
}
|
||||||
@@ -116,11 +116,11 @@ public class Party {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean addOnlineMember(Player player) {
|
public boolean addOnlineMember(Player player) {
|
||||||
return onlineMembers.add(player);
|
return getOnlineMembers().add(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean removeOnlineMember(Player player) {
|
public boolean removeOnlineMember(Player player) {
|
||||||
return onlineMembers.remove(player);
|
return getOnlineMembers().remove(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
|
@@ -273,10 +273,25 @@ public final class PartyManager {
|
|||||||
requireNonNull(player, "player cannot be null!");
|
requireNonNull(player, "player cannot be null!");
|
||||||
requireNonNull(party, "party cannot be null!");
|
requireNonNull(party, "party cannot be null!");
|
||||||
|
|
||||||
LinkedHashMap<UUID, String> members = party.getMembers();
|
final LinkedHashMap<UUID, String> members = party.getMembers();
|
||||||
String playerName = player.getName();
|
final String playerName = player.getName();
|
||||||
|
|
||||||
|
if (party.getLeader().getUniqueId().equals(player.getUniqueId())) {
|
||||||
members.remove(player.getUniqueId());
|
members.remove(player.getUniqueId());
|
||||||
|
if (!members.isEmpty()) {
|
||||||
|
for (Entry<UUID, String> entry : members.entrySet()) {
|
||||||
|
final UUID memberUUID = entry.getKey();
|
||||||
|
final String memberName = entry.getValue();
|
||||||
|
if (!memberUUID.equals(party.getLeader().getUniqueId())) {
|
||||||
|
party.setLeader(new PartyLeader(memberUUID, memberName));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
members.remove(player.getUniqueId());
|
||||||
|
}
|
||||||
|
|
||||||
if (player.isOnline()) {
|
if (player.isOnline()) {
|
||||||
party.getOnlineMembers().remove(player.getPlayer());
|
party.getOnlineMembers().remove(player.getPlayer());
|
||||||
@@ -285,11 +300,6 @@ public final class PartyManager {
|
|||||||
if (members.isEmpty()) {
|
if (members.isEmpty()) {
|
||||||
parties.remove(party);
|
parties.remove(party);
|
||||||
} else {
|
} else {
|
||||||
// If the leaving player was the party leader, appoint a new leader from the party members
|
|
||||||
if (party.getLeader().getUniqueId().equals(player.getUniqueId())) {
|
|
||||||
setPartyLeader(members.keySet().iterator().next(), party);
|
|
||||||
}
|
|
||||||
|
|
||||||
informPartyMembersQuit(party, playerName);
|
informPartyMembersQuit(party, playerName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,15 +1,30 @@
|
|||||||
package com.gmail.nossr50.party;
|
package com.gmail.nossr50.party;
|
||||||
|
|
||||||
import static java.util.logging.Logger.getLogger;
|
import static java.util.logging.Logger.getLogger;
|
||||||
|
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
import static org.mockito.ArgumentMatchers.contains;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import com.gmail.nossr50.MMOTestEnvironment;
|
import com.gmail.nossr50.MMOTestEnvironment;
|
||||||
|
import com.gmail.nossr50.datatypes.interactions.NotificationType;
|
||||||
|
import com.gmail.nossr50.datatypes.party.Party;
|
||||||
|
import com.gmail.nossr50.datatypes.party.PartyLeader;
|
||||||
import com.gmail.nossr50.datatypes.player.McMMOPlayer;
|
import com.gmail.nossr50.datatypes.player.McMMOPlayer;
|
||||||
import com.gmail.nossr50.mcMMO;
|
import com.gmail.nossr50.mcMMO;
|
||||||
|
import com.gmail.nossr50.util.player.NotificationManager;
|
||||||
|
import com.gmail.nossr50.util.player.UserManager;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
import org.bukkit.OfflinePlayer;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
@@ -24,7 +39,7 @@ class PartyManagerTest extends MMOTestEnvironment {
|
|||||||
mockBaseEnvironment(logger);
|
mockBaseEnvironment(logger);
|
||||||
|
|
||||||
// currently unnecessary, but may be needed for future tests
|
// currently unnecessary, but may be needed for future tests
|
||||||
Mockito.when(partyConfig.isPartyEnabled()).thenReturn(true);
|
when(partyConfig.isPartyEnabled()).thenReturn(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterEach
|
@AfterEach
|
||||||
@@ -32,7 +47,7 @@ class PartyManagerTest extends MMOTestEnvironment {
|
|||||||
cleanUpStaticMocks();
|
cleanUpStaticMocks();
|
||||||
|
|
||||||
// disable parties in config for other tests
|
// disable parties in config for other tests
|
||||||
Mockito.when(partyConfig.isPartyEnabled()).thenReturn(false);
|
when(partyConfig.isPartyEnabled()).thenReturn(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -94,4 +109,207 @@ class PartyManagerTest extends MMOTestEnvironment {
|
|||||||
() -> partyManager.createParty(null, partyName, partyPassword));
|
() -> partyManager.createParty(null, partyName, partyPassword));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkPartyPasswordFailsWithIncorrectPassword() {
|
||||||
|
PartyManager partyManager = new PartyManager(mcMMO.p);
|
||||||
|
|
||||||
|
Party party = Mockito.mock(Party.class);
|
||||||
|
Player player = Mockito.mock(Player.class);
|
||||||
|
|
||||||
|
when(party.isLocked()).thenReturn(true);
|
||||||
|
when(party.getPassword()).thenReturn("correctPassword");
|
||||||
|
|
||||||
|
boolean result = partyManager.checkPartyPassword(player, party, "wrongPassword");
|
||||||
|
|
||||||
|
assertThat(result).isFalse();
|
||||||
|
verify(player).sendMessage(contains("Party password is incorrect"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkPartyPasswordFailsWithNullInput() {
|
||||||
|
PartyManager partyManager = new PartyManager(mcMMO.p);
|
||||||
|
|
||||||
|
Party party = Mockito.mock(Party.class);
|
||||||
|
Player player = Mockito.mock(Player.class);
|
||||||
|
|
||||||
|
when(party.isLocked()).thenReturn(true);
|
||||||
|
when(party.getPassword()).thenReturn("secure");
|
||||||
|
|
||||||
|
boolean result = partyManager.checkPartyPassword(player, party, null);
|
||||||
|
|
||||||
|
assertThat(result).isFalse();
|
||||||
|
verify(player).sendMessage(
|
||||||
|
contains("This party is password protected. Please provide a password to join."));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkPartyExistenceReturnsTrueIfExists() {
|
||||||
|
PartyManager partyManager = new PartyManager(mcMMO.p);
|
||||||
|
|
||||||
|
Party party = Mockito.mock(Party.class);
|
||||||
|
Mockito.when(party.getName()).thenReturn("ExistingParty");
|
||||||
|
|
||||||
|
partyManager.getParties().add(party);
|
||||||
|
|
||||||
|
boolean result = partyManager.checkPartyExistence(player, "ExistingParty");
|
||||||
|
|
||||||
|
assertThat(result).isTrue();
|
||||||
|
Mockito.verify(player).sendMessage(Mockito.contains("Party ExistingParty already exists!"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void inSamePartyShouldReturnTrueIfSameParty() {
|
||||||
|
PartyManager partyManager = new PartyManager(mcMMO.p);
|
||||||
|
|
||||||
|
Party party = Mockito.mock(Party.class);
|
||||||
|
Player playerA = mock(Player.class);
|
||||||
|
Player playerB = mock(Player.class);
|
||||||
|
|
||||||
|
McMMOPlayer mmoA = mock(McMMOPlayer.class);
|
||||||
|
McMMOPlayer mmoB = mock(McMMOPlayer.class);
|
||||||
|
|
||||||
|
mockedUserManager.when(() -> UserManager.getPlayer(playerA)).thenReturn(mmoA);
|
||||||
|
mockedUserManager.when(() -> UserManager.getPlayer(playerB)).thenReturn(mmoB);
|
||||||
|
|
||||||
|
when(mmoA.getParty()).thenReturn(party);
|
||||||
|
when(mmoB.getParty()).thenReturn(party);
|
||||||
|
|
||||||
|
assertThat(partyManager.inSameParty(playerA, playerB)).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void areAlliesShouldReturnTrueIfMutuallyAllied() {
|
||||||
|
PartyManager partyManager = new PartyManager(mcMMO.p);
|
||||||
|
|
||||||
|
Player p1 = mock(Player.class);
|
||||||
|
Player p2 = mock(Player.class);
|
||||||
|
|
||||||
|
McMMOPlayer mmo1 = mock(McMMOPlayer.class);
|
||||||
|
McMMOPlayer mmo2 = mock(McMMOPlayer.class);
|
||||||
|
|
||||||
|
Party party1 = mock(Party.class);
|
||||||
|
Party party2 = mock(Party.class);
|
||||||
|
|
||||||
|
mockedUserManager.when(() -> UserManager.getPlayer(p1)).thenReturn(mmo1);
|
||||||
|
mockedUserManager.when(() -> UserManager.getPlayer(p2)).thenReturn(mmo2);
|
||||||
|
|
||||||
|
when(mmo1.getParty()).thenReturn(party1);
|
||||||
|
when(mmo2.getParty()).thenReturn(party2);
|
||||||
|
when(party1.getAlly()).thenReturn(party2);
|
||||||
|
when(party2.getAlly()).thenReturn(party1);
|
||||||
|
|
||||||
|
assertTrue(partyManager.areAllies(p1, p2));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void removeFromPartyDoesNothing() {
|
||||||
|
PartyManager partyManager = new PartyManager(mcMMO.p);
|
||||||
|
|
||||||
|
McMMOPlayer mmoPlayer = mock(McMMOPlayer.class);
|
||||||
|
when(mmoPlayer.getParty()).thenReturn(null);
|
||||||
|
|
||||||
|
partyManager.removeFromParty(mmoPlayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void removeFromPartyWithPartyRemovesCorrectly() {
|
||||||
|
PartyManager partyManager = new PartyManager(mcMMO.p);
|
||||||
|
|
||||||
|
McMMOPlayer mmoPlayer = mock(McMMOPlayer.class);
|
||||||
|
Player player = mock(Player.class);
|
||||||
|
Party party = mock(Party.class);
|
||||||
|
UUID uuid = UUID.randomUUID();
|
||||||
|
|
||||||
|
when(player.getUniqueId()).thenReturn(uuid);
|
||||||
|
when(player.getName()).thenReturn("PlayerName");
|
||||||
|
when(player.isOnline()).thenReturn(true);
|
||||||
|
when(player.getPlayer()).thenReturn(player);
|
||||||
|
|
||||||
|
when(mmoPlayer.getPlayer()).thenReturn(player);
|
||||||
|
when(mmoPlayer.getParty()).thenReturn(party);
|
||||||
|
|
||||||
|
when(party.getMembers()).thenReturn(new LinkedHashMap<>(Map.of(uuid, "PlayerName")));
|
||||||
|
when(party.getOnlineMembers()).thenReturn(new ArrayList<>(List.of(player)));
|
||||||
|
when(party.getLeader()).thenReturn(new PartyLeader(uuid, "PlayerName"));
|
||||||
|
|
||||||
|
partyManager.getParties().add(party);
|
||||||
|
partyManager.removeFromParty(mmoPlayer);
|
||||||
|
|
||||||
|
// Party should be removed since it had only one member
|
||||||
|
assertFalse(partyManager.getParties().contains(party));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void changeOrJoinPartyNotInPartyTriggersEventAndReturnsTrue() {
|
||||||
|
PartyManager partyManager = new PartyManager(mcMMO.p);
|
||||||
|
|
||||||
|
McMMOPlayer mmoPlayer = mock(McMMOPlayer.class);
|
||||||
|
Player player = mock(Player.class);
|
||||||
|
|
||||||
|
when(mmoPlayer.getPlayer()).thenReturn(player);
|
||||||
|
when(mmoPlayer.inParty()).thenReturn(false);
|
||||||
|
|
||||||
|
assertTrue(partyManager.changeOrJoinParty(mmoPlayer, "NewParty"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void removeFromPartyLeaderLeavesNewLeaderIsAssigned() {
|
||||||
|
PartyManager partyManager = new PartyManager(mcMMO.p);
|
||||||
|
|
||||||
|
UUID oldLeaderUUID = UUID.randomUUID();
|
||||||
|
UUID newLeaderUUID = UUID.randomUUID();
|
||||||
|
|
||||||
|
// Setup players
|
||||||
|
OfflinePlayer oldLeader = mock(OfflinePlayer.class);
|
||||||
|
when(oldLeader.getUniqueId()).thenReturn(oldLeaderUUID);
|
||||||
|
when(oldLeader.getName()).thenReturn("OldLeader");
|
||||||
|
when(oldLeader.isOnline()).thenReturn(true);
|
||||||
|
when(oldLeader.getPlayer()).thenReturn(
|
||||||
|
mock(Player.class)); // required for party.getOnlineMembers()
|
||||||
|
|
||||||
|
OfflinePlayer newLeader = mock(OfflinePlayer.class);
|
||||||
|
when(newLeader.getUniqueId()).thenReturn(newLeaderUUID);
|
||||||
|
when(newLeader.getName()).thenReturn("NewLeader");
|
||||||
|
|
||||||
|
// Setup party and members
|
||||||
|
Party party = new Party(new PartyLeader(oldLeaderUUID, "OldLeader"), "SomeParty", null);
|
||||||
|
party.getMembers().put(oldLeaderUUID, "OldLeader");
|
||||||
|
party.getMembers().put(newLeaderUUID, "NewLeader");
|
||||||
|
|
||||||
|
Player newLeaderOnline = mock(Player.class);
|
||||||
|
when(newLeaderOnline.getUniqueId()).thenReturn(newLeaderUUID);
|
||||||
|
party.getOnlineMembers().add(newLeaderOnline); // simulate second member online
|
||||||
|
|
||||||
|
partyManager.getParties().add(party);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
partyManager.removeFromParty(oldLeader, party);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
PartyLeader newLeaderObj = party.getLeader();
|
||||||
|
assertThat(newLeaderUUID).isEqualTo(newLeaderObj.getUniqueId());
|
||||||
|
assertThat("NewLeader").isEqualTo(newLeaderObj.getPlayerName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void joinInvitedPartyPartyDoesNotExistDoesNotJoin() {
|
||||||
|
PartyManager partyManager = new PartyManager(mcMMO.p);
|
||||||
|
|
||||||
|
McMMOPlayer mmoPlayer = mock(McMMOPlayer.class);
|
||||||
|
Player player = mock(Player.class);
|
||||||
|
Party partyWhichNoLongerExists = mock(Party.class);
|
||||||
|
|
||||||
|
when(mmoPlayer.getPartyInvite()).thenReturn(partyWhichNoLongerExists);
|
||||||
|
when(mmoPlayer.getPlayer()).thenReturn(player);
|
||||||
|
|
||||||
|
assertFalse(partyManager.getParties().contains(partyWhichNoLongerExists));
|
||||||
|
|
||||||
|
partyManager.joinInvitedParty(mmoPlayer);
|
||||||
|
|
||||||
|
// Should have sent disband message
|
||||||
|
notificationManager.verify(() ->
|
||||||
|
NotificationManager.sendPlayerInformation(player, NotificationType.PARTY_MESSAGE,
|
||||||
|
"Party.Disband"));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
Reference in New Issue
Block a user