Integration Guide
This guide walks through integrating GroupManager into your own Hytale plugin, using a PvP minigame plugin as an example use case.
1. Add the Dependency
Add GroupManager as a compile-only dependency:
dependencies {
compileOnly(files("libs/groupmanager.jar"))
}
In your manifest.json, declare GroupManager as an optional dependency:
{
"Dependencies": {
"HaporeLab:GroupManager": "*"
}
}
2. Access the API
import com.groupmanager.api.GroupManagerProvider;
import com.groupmanager.api.GroupService;
import com.groupmanager.api.GroupType;
public class MyPlugin extends JavaPlugin {
private GroupService groupApi;
@Override
public void start() {
groupApi = GroupManagerProvider.get();
if (groupApi == null) {
getLogger().at(Level.WARNING).log("GroupManager not found, group features disabled");
return;
}
// GroupManager is available
}
}
3. Common Integration Patterns
Queuing Groups Together
When your plugin has a queue system, check if players are grouped and queue them together:
public void queuePlayer(UUID playerUuid) {
if (groupApi == null) {
// Solo queue
addToQueue(playerUuid);
return;
}
Optional<GroupService.GroupInfo> group = groupApi.getPlayerGroup(playerUuid);
if (group.isPresent()) {
// Queue the entire group
GroupService.GroupInfo info = group.get();
// Only permanent group leaders can queue their group
if (info.type() == GroupType.PERMANENT && !info.leaderUuid().equals(playerUuid)) {
sendMessage(playerUuid, "Only the group leader can queue!");
return;
}
for (UUID member : info.memberUuids()) {
addToQueue(member);
}
} else {
addToQueue(playerUuid);
}
}
Preventing Friendly Fire
public boolean shouldApplyDamage(UUID attacker, UUID victim) {
if (groupApi != null && groupApi.areInSameGroup(attacker, victim)) {
return false; // Teammates can't hurt each other
}
return true;
}
Creating Match Teams
Use temporary groups to manage teams during a match:
public void startMatch(Player leader, List<Player> teamMembers) {
// Save original groups
Map<UUID, UUID> originalGroups = new HashMap<>();
for (Player p : teamMembers) {
groupApi.getPlayerGroup(p.getUuid()).ifPresent(g ->
originalGroups.put(p.getUuid(), g.groupId())
);
}
// Create temp group
GroupService.GroupResult result = groupApi.createTemporaryGroup(leader, teamMembers);
UUID matchGroupId = result.groupId();
// Pause GroupHud during match (no-op if AutoMultiHud is present)
for (Player p : teamMembers) {
groupApi.pauseHud(p.getUuid());
}
// ... match logic ...
// After match ends:
groupApi.dissolveTemporaryGroup(matchGroupId, originalGroups);
for (Player p : teamMembers) {
groupApi.resumeHud(p.getUuid());
}
}
pauseHud/resumeHud are safe to call unconditionally. If AutoMultiHud is installed, GroupManager handles it internally and these calls become no-ops.
Broadcasting to a Team
groupApi.broadcastToGroup(groupId, "Match starting in 10 seconds!");
groupApi.broadcastToGroupExcept(groupId, mvpUuid, playerName + " got a double kill!");
4. Listening for Events
Register an event listener to react to group changes:
@Override
public void start() {
groupApi = GroupManagerProvider.get();
if (groupApi == null) return;
groupApi.registerEventListener(new GroupEventListener() {
@Override
public void onGroupDissolved(UUID groupId) {
// Remove group from any active queues or actvity
removeGroupFromQueue(groupId);
}
@Override
public void onMemberLeft(UUID groupId, UUID playerUuid) {
// Check if group still meets minimum size for queue or actvity
groupApi.getGroup(groupId).ifPresent(info -> {
if (info.size() < getMinTeamSize()) {
removeGroupFromQueue(groupId);
groupApi.broadcastToGroup(groupId,
"Removed from queue: not enough members.");
}
});
}
});
}
5. Handling Player Connections
When players reconnect to your server, notify GroupManager:
// In your player join handler
groupApi.reconnectPlayer(player);
// In your player quit handler
groupApi.disconnectPlayer(player);
GroupManager will restore the player's group membership and HUD automatically.
6. Permissions Check
If your plugin needs to verify GroupManager permissions:
import com.groupmanager.permissions.GroupManagerPermissions;
// Check if a player can invite others
String permission = GroupManagerPermissions.GROUP_INVITE;
// Use your permission system to check: hasPermission(player, permission)
7. Temporary Groups and Coalitions
Why Temporary Groups?
Permanent groups are the groups players create with /group invite. They persist across sessions and belong to the players. Your plugin should never modify or dissolve permanent groups to fit its own needs.
When your plugin runs an external activity (a minigame, a dungeon, a raid, a tournament, etc.), the players that enter may come from different permanent groups — or some may not be grouped at all. You need a way to organize them into teams without touching their permanent groups. That's what temporary groups are for.
createTemporaryGroup() creates a short-lived group that your plugin controls entirely. When the activity ends, you dissolve it and every player goes back to their original permanent group as if nothing happened.
When Do You Need Coalitions?
Consider this scenario: your plugin runs a 4v4 activity. Two permanent groups of 2 players each queue together and are placed on the same team. Inside your activity, those 4 players need to function as one team — same HUD, same group chat, same compass markers. A coalition is simply a temporary group that merges players from multiple permanent groups into one team for the duration of the activity.
Another common scenario: a permanent group of 3 enters a 3v3 activity. You don't need to merge them with anyone, but you still need a temporary copy so that any changes during the activity (a player leaving, disconnecting) don't affect the permanent group. In this case you create a temporary group that mirrors the permanent one.
In summary, use createTemporaryGroup() whenever players enter an external activity — whether you're merging multiple groups into a coalition or simply cloning a single permanent group for isolation.
Restoring Players After the Activity
GroupManager provides three methods to restore players to their permanent groups, depending on the situation:
| Situation | Method | Player state |
|---|---|---|
| Activity ends normally | dissolveTemporaryGroup() | All players restored at once |
| Player leaves voluntarily (online) | restorePlayerFromCoalition() | Single player, still connected |
| Player disconnects mid-activity | restorePermanentGroupOnDisconnect() | Single player, offline |
| Player reconnects to active activity | rejoinCoalitionGroup() | Moves back into the temporary group |
Lifecycle
- Activity starts — Create temporary groups with
createTemporaryGroup(), saving each player's original permanent group ID. - Player disconnects — Call
restorePermanentGroupOnDisconnect()so their permanent group mapping is preserved for when they reconnect. - Player reconnects —
reconnectPlayer()restores the permanent group automatically. Then callrejoinCoalitionGroup()to move them back into the activity's temporary group. - Player leaves voluntarily — Call
restorePlayerFromCoalition()to remove them from the temporary group and return them to their permanent group immediately. - Activity ends — Call
dissolveTemporaryGroup()for each temporary group, passing the original groups map. All remaining players are restored to their permanent groups.
Full Example
public class ActivityManager {
private final GroupService groupApi;
// State per activity instance — store alongside your activity data
private final Map<UUID, UUID> originalPermanentGroups = new HashMap<>();
private final List<UUID> temporaryGroupIds = new ArrayList<>();
// --- 1. Create temporary groups when the activity starts ---
public void startActivity(List<Player> team1, List<Player> team2) {
temporaryGroupIds.add(createTemporaryTeam(team1));
temporaryGroupIds.add(createTemporaryTeam(team2));
}
private UUID createTemporaryTeam(List<Player> team) {
// Save each player's permanent group before creating the temporary one
for (Player p : team) {
groupApi.getPlayerGroup(p.getUuid()).ifPresent(g ->
originalPermanentGroups.put(p.getUuid(), g.groupId())
);
}
Player leader = team.get(0);
List<Player> members = team.subList(1, team.size());
GroupService.GroupResult result = groupApi.createTemporaryGroup(leader, members);
return result.groupId();
}
// --- 2. A player disconnects during the activity ---
public void onPlayerDisconnect(UUID playerUuid) {
UUID permanentGroupId = originalPermanentGroups.get(playerUuid);
if (permanentGroupId != null) {
// Restore the permanent group mapping so reconnectPlayer() works later
groupApi.restorePermanentGroupOnDisconnect(playerUuid, permanentGroupId);
}
}
// --- 3. A player reconnects to an activity that is still running ---
public void onPlayerReconnect(Player player, List<PlayerRef> teamMembers) {
// reconnectPlayer() already restored their permanent group.
// Now move them back into their team's temporary group.
groupApi.rejoinCoalitionGroup(
player, teamMembers,
originalPermanentGroups, temporaryGroupIds);
}
// --- 4. A player leaves the activity voluntarily ---
public void onPlayerLeave(Player player) {
UUID permanentGroupId = originalPermanentGroups.get(player.getUuid());
if (permanentGroupId != null) {
// Remove from temporary group and restore permanent group (player stays online)
groupApi.restorePlayerFromCoalition(
player, permanentGroupId, temporaryGroupIds);
}
}
// --- 5. Activity ends — dissolve all temporary groups ---
public void endActivity() {
for (UUID tempGroupId : temporaryGroupIds) {
groupApi.dissolveTemporaryGroup(tempGroupId, originalPermanentGroups);
}
temporaryGroupIds.clear();
originalPermanentGroups.clear();
}
}
Always store originalPermanentGroups and temporaryGroupIds as part of your activity/instance state. Every restoration method needs them, and they must survive for the entire duration of the activity.
You don't need to call all of these methods in every plugin. If your activity doesn't support reconnection, you can skip rejoinCoalitionGroup(). If players can't leave voluntarily, you can skip restorePlayerFromCoalition(). The only essential calls are createTemporaryGroup() at the start and dissolveTemporaryGroup() at the end.
Best Practices
- Always null-check the API — GroupManager may not be installed on every server.
- Cache the API reference — call
GroupManagerProvider.get()once instart(). - Unregister listeners — clean up in
shutdown()to prevent memory leaks. - Use temporary groups for matches — don't modify permanent groups for game logic.
- Pause/resume HUD — hide the group HUD during activities that have their own UI. These calls are safe unconditionally — GroupManager automatically handles AutoMultiHud compatibility internally.
- Save original groups — when creating temporary groups, save the original group IDs so you can restore them later.
- Handle disconnects in coalitions — call
restorePermanentGroupOnDisconnect()so reconnection works correctly.
8. Customizing the Group HUD
GroupManager lets external plugins add a prefix and/or suffix to each player's name in the group HUD, without modifying the actual display name. This is ideal for RPG plugins, leveling systems, class systems, or any plugin that wants to show extra info alongside player names.
Adding Prefix / Suffix
GroupService api = GroupManagerProvider.get();
if (api != null) {
// Show level before the name
api.setHudPrefix(playerUuid, "[Lv." + level + "] ");
// Show class after the name
api.setHudSuffix(playerUuid, " | " + className);
// HUD now shows: "[Lv.12] Steve | Warrior - Leader"
}
Updating on Level-Up
public void onPlayerLevelUp(UUID playerUuid, int newLevel) {
GroupService api = GroupManagerProvider.get();
if (api != null) {
api.setHudPrefix(playerUuid, "[Lv." + newLevel + "] ");
}
}
Clearing
// Remove both prefix and suffix
api.clearHudPrefixSuffix(playerUuid);
// Or remove individually
api.setHudPrefix(playerUuid, null); // removes prefix
api.setHudSuffix(playerUuid, ""); // removes suffix
Prefix and suffix are automatically cleaned up when a player disconnects. You don't need to call clearHudPrefixSuffix in your disconnect handler.
Checking Online Members
You can also check which group members are currently online:
api.getPlayerGroup(playerUuid).ifPresent(group -> {
List<UUID> online = group.onlineMemberUuids();
System.out.println(online.size() + " / " + group.size() + " members online");
});
// Or check a specific player
boolean isOnline = api.isPlayerOnline(someUuid);