
Team-HomeGUI Plugin
A lightweight team system with team homes, private team chat, personal homes, and a clean home GUI
[1.3.1] — Click Event Fix
Critical Bug Fixes
- Inventory item jitter on click — clicking on valid inventory menu items would bounce back
to their original position. The issue was that
event.setCancelled(true)was called for ALL clicks before checking if the click was actually on a valid menu slot. Now the event is only cancelled for clicks on valid interactive items (Team Home banner, personal homes, action buttons, and confirm-delete dialog). Clicks outside these areas are ignored naturally without artificial cancellation.
- Inventory item jitter on click — clicking on valid inventory menu items would bounce back
to their original position. The issue was that
[1.3.0] — Bug-fix & Feature Release
New Feature
- Confirm-Delete Home GUI — clicking the red dye (delete) button in the Home GUI now
opens a 27-slot confirmation dialog instead of deleting instantly.
- Slot 11 (user-facing 12) → 🔴 Red glass pane "No" — cancel
- Slot 13 (user-facing 14) → 🛏 Red bed "Delete Home?" — centre icon
- Slot 15 (user-facing 16) → 🟢 Lime glass pane "Yes" — confirm permanent deletion
Critical Bug Fixes
- NPE crash when opening Home GUI —
loc.getWorld().getName()was called without a null check; if a world was deleted or unloaded after a home was saved, opening the GUI caused aNullPointerExceptionand crashed the inventory for that player. Now shows"World no longer exists"gracefully for both personal homes and team home. - Race condition in HomeManager — inner
HashMap<String, Location>was not thread-safe; the async save thread iterating it while the main thread wrote to it could causeConcurrentModificationExceptionand silent data loss. Changed toConcurrentHashMapfor inner maps.
Bug Fixes — Logic
- Mass message-key mismatch — dozens of
plugin.msg(key)calls used keys that did not exist inteam-config.yml, causing players to see raw"Message not found: <key>"strings. All handlers now reference the correct existing keys or new keys added in this release:TeamHandler:invite-no-permission,invite-already-in-team,leave-success,player-left-team,player-not-in-team,kick-no-permission,cannot-kick-owner,kick-broadcast(updated placeholders{kicker}/{kicked})ChatHandler:chat-already-enabled,chat-already-disabled; team-message format now readssettings.chat-format(was hardcoded missing key"team-chat-format") and correctly replaces{team}and callsTeamPlugin.color()SettingsHandler: all promote / demote / transfer / name / invite messages now match config keys;"settings-name-success","settings-invite-changed","settings-transfer-success/received/broadcast"and"settings-promote-self-error"addedAdminHandler:"wrong-password","admin-team-already-exists","admin-ban-success","admin-unban-success","admin-add-success/target","admin-already-banned","admin-not-banned","admin-disbanned-target","admin-remove-team-success"alignedListHandler:"list-entry"and"list-footer"added to config
SettingsHandler.handleAdminSettings()always returned "team not found" — the handler was readingargs[1](which contains the literal string"settings") instead ofargs[2]as the team ID. Fixed all admin-settings argument indices accordingly.- Admin
/team admin settingssub-command was unreachable —AdminHandler.handleAdmin()had no"settings"case in its switch statement. Added routing toSettingsHandler. Team.canInvite()ignored Admin role — the public method only checked Owner andmembersCanInvite, making the Admin role unable to invite whenmembersCanInvite=false. Now consistent withTeamHandler.canInvite().- No max-members enforcement on invite —
TeamHandler.handleInvite()never checked the configuredsettings.max-memberslimit. Teams could grow without bound. Fixed. - Self-invite not caught — a player could invite themselves; added explicit check using
existing
"invite-self-error"config key. - Pending-invite not checked — a target with a pending invite from any team could receive
multiple invites. Now uses the existing
"invite-already-pending"key. GUISlotsenum had duplicate slot values —DELETE_DYE_*andSET_DYE_*both pointed to slots 29–33 (which were never used; real action slots are 20–24). Replaced withACTION_1..5+ newCONFIRM_NO / CONFIRM_BED / CONFIRM_YESslots.ListHandlerreturned teams in random order —ConcurrentHashMap.values()has no guaranteed iteration order; added alphabetical sort.
Bug Fixes — Performance / Safety
Team.getOwnerName()could block the main thread —Bukkit.getOfflinePlayer(UUID)may perform disk I/O to read playerdata files. Now checks the online-player cache first, thengetOfflinePlayerIfCached()(no I/O), and only falls back to the disk call for completely unknown players.- WarmupListener did not restore custom walk/fly speed — after a warmup the speed was always reset to Bukkit defaults (0.2 / 0.1), overriding server-rank speed multipliers. The actual speeds are now saved before freezing and restored on cancel or completion.
HomeManager.getHomeNames()returned a mutable live view — callers iterating the result while a concurrent modification occurred could getConcurrentModificationException. Now returnsSet.copyOf().- Home name validation inconsistency —
HomeServiceallowed-and had no length cap, whileHomeHandlerdid not allow-and enforced 16 chars. Unified to the stricter^[a-zA-Z0-9_]{1,16}$pattern across both paths. gui.show-coordinatesdefault mismatch — Java fallback wastruewhile the config file default isfalse. Changed Java fallback tofalse.
Config Changes (
team-config.yml)Added keys:
cannot-kick-owner,team-full,chat-already-enabled,chat-already-disabled,list-entry,list-footer,admin-target-is-banned,admin-add-success,admin-add-target-msg,admin-already-banned,admin-not-banned,admin-removed-from-team,admin-cannot-remove-admin-team,admin-disbanned-target,admin-remove-team-success,settings-name-success,settings-name-changed-broadcast,settings-name-failed,settings-invite-changed,settings-invite-changed-broadcast,settings-transfer-success,settings-transfer-received,settings-transfer-broadcast,settings-help,admin-settings-help,settings-promote-self-error,usage-settings-name/color/invite/promote/demote/transfer,usage-admin-settingsUpdated keys:
kick-broadcast→ now uses{kicker}and{kicked}placeholderssettings-name-broadcast→ now uses{name}and{player}placeholders
- Confirm-Delete Home GUI — clicking the red dye (delete) button in the Home GUI now
opens a 27-slot confirmation dialog instead of deleting instantly.
Нет описания изменений
[1.2.0] — Bug Fix Release
Fixed
🔴 Critical
-
HomeManager/TeamManager—save()not synchronized → homes/teams lost on server shutdownsaveAsync()dispatches aBukkitRunnableto a worker thread. When the server stops,onDisable()callssave()on the main thread while that worker thread may still be executing a previoussave(). BecauseYamlConfigurationis not thread-safe, the two threads interleaved theirdata.set(…)anddata.save(…)calls, producing a corrupted or empty file. The result was that all personal homes (and team data) were silently wiped every time the server restarted. Bothsave()methods are nowsynchronized. Additionally,onDisable()callsgetScheduler().cancelTasks(this)before saving, eliminating the race window entirely. -
HomeService.getPlayerMaxHomes()— wrong config key → home limit always 2 The method readsettings.default-max-homesbut the actual key inhome-config.ymlisdefault-max-homes(root level, nosettingsprefix). The missing prefix causedgetInt()to always fall back to its hardcoded default of2, capping every player at two homes regardless of what was configured. Fixed to read the correct keydefault-max-homes.
🟡 Medium
-
HomeService.teleportHome()— wrong path and wrong type fordisabled-worlds→ world blacklist never enforced via GUIgetString("settings.disabled-worlds", "")was wrong on two counts: the path prefixsettings.does not exist inhome-config.yml, and the value is a YAML list, not a plain string. The method always received an empty string and silently skipped the world check entirely, allowing players to teleport intoworld_netherandworld_the_endthrough the GUI regardless of the blacklist. Fixed to usegetStringList("disabled-worlds")at the correct root path. -
HomeHandler.handlePlayerSetHome()—player.getLocation()not cloned before storagehomeManager.setHome(…, player.getLocation())stored a direct reference to Bukkit's mutableLocationobject. Bukkit may reuse this object internally, meaning the stored coordinates could silently change after the call. Fixed by passingplayer.getLocation().clone()instead. (HomeService.setHome()already cloned correctly; this aligns the two code paths.)
Changed
- Version bumped
1.1.0 → 1.2.0.
-
[1.1.0] — Bug Fix Release
Fixed
🔴 Critical
-
AdminHandler.handleAdminAdd()— admin team auto-creation always failed Previously the method calledhandleAdminCreate()with a mismatchedargsarray (args[2]was the placeholder string"dummy"instead of the real password). The password check always failed, so/team admin add <player>silently broke whenever the admin team did not yet exist. The method now creates the admin team directly viaTeamManager.createTeam(), skipping the redundant password validation entirely. -
HomeService.canSetHome()— economy charged before slot-limit check If a player had already reached their home limit, the old code debited their balance first and then checked the limit, causing money to be lost without a home being set. Validation order is now: name format → slot limit → economy charge. The same fix was applied toHomeHandler.handlePlayerSetHome(). -
Dual cooldown maps — players could bypass home teleport cooldown The
/homecommand (HomeHandler) wrote cooldowns toHomeManager.teleportCooldownswhile the GUI (HomeService/MenuListener) wrote toCooldownManager.homeCooldowns. Because neither path read the other map a player could alternate between the command and the GUI to teleport with no cooldown delay.HomeManager.teleportCooldownshas been removed entirely. All three paths —/homecommand, personal-home GUI click, and team-home GUI click — now useCooldownManagerexclusively.
🟡 Medium
-
CooldownManager.checkTeamCooldown()— permission nodeteamplugin.team.nocooldownwas missing fromplugin.ymlThe permission existed in code but was never declared, so permission-management plugins could not grant it and the bypass never worked. Added toplugin.ymlwithdefault: op. -
MenuListener— wrong config key used for delete-home success message The listener looked upmessages.del-success, a key that does not exist inhome-config.yml. The correct key ismessages.delhome-success. Players always saw the hardcoded fallback string instead of the configured message. -
saveAsyncFuture()— unsafe method still callable BothTeamManagerandHomeManagerkept asaveAsyncFuture()method that was documented as unsafe (causesConcurrentModificationExceptionwithFileConfiguration). The method is now marked@Deprecatedand throwsUnsupportedOperationExceptionto prevent accidental future use. -
CooldownManager.cleanupExpiredCooldowns()— never called → slow memory leak The cleanup method existed but was never scheduled. A repeating async task (every 10 minutes) is now registered inTeamPlugin.onEnable()to drain stale entries from the cooldown maps.
🟢 Minor
AdminHandler— hardcoded§colour codeshandleAdminList()andshowTeamInfo()used raw§codes which bypass the plugin's colour API. Replaced with&-codes processed viaTeamPlugin.color().
Added
TeamPlugin.getCooldownManager()— public getter so handlers can share the singleCooldownManagerinstance without reaching throughhomeService.
Changed
HomeManager:teleportCooldownsmap and its getter/setter removed. Oldhomes.ymlfiles that contain acooldownsub-key are silently ignored on load and not written back, providing a clean migration path.- Version bumped
1.0.9 → 1.1.0.
-
[1.0.9] - 2026-05-17
Fixed
- Admin team creation always fails —
AdminHandler.handleAdminCreate()was readingargs[1](the literal string"create") as the password instead ofargs[2](the actual password supplied by the player). Every/team admin create <password>call would compare"create"against the configured password, causing it to always fail with "incorrect password". Fixed by readingargs[2]. - Tab-completing
/team hometeleports the player —TeamCommand.onTabComplete()had acase "home"branch inside theargs.length == 2block that calledplugin.getHomeService().teleportHome(player, args[0])(i.e., teleported the player to home"home"every time they pressed Tab after/team home). Replaced with a proper tab-completion loop that suggests the player's existing home names. - GUI sethome bypasses economy charge — Clicking the LIME_DYE "Set Home" button in the Home GUI called
homeManager.setHome()directly, skipping the economy deduction andcanSetHome()validation path insideHomeService. Fixed by routing the call throughHomeService.setHome(), which handles both economy and limit checks consistently with the command-based flow.
- Admin team creation always fails —
Нет описания изменений
[1.0.7] - 2026-05-08
Added
- XP Bar Countdown — During the teleport warmup, the experience bar now counts down visually (level number = seconds remaining, bar fill = proportion left). The bar is restored to its original value immediately after the teleport fires or is cancelled.
Fixed
- Warmup shows but teleport never happens —
HomeService.teleportHome()now callscanTeleportHome()before starting the warmup countdown. Previously the validation step was skipped entirely: the cooldown was set, the "Teleporting in N seconds…" message was sent, but the destinationLocationcould benull, so the actualplayer.teleport()silently failed or threw aNullPointerException. - Home limit bypass via EssentialsX
/sethome—EssentialsInterceptListener(priorityHIGHEST) now intercepts all/homeand/sethomeevents regardless of arguments, cancels them before EssentialsX can act, and opens our Home GUI instead. This prevents EssentialsX from writing homes to its own userdata and bypassing our home-count limits. setHome()skipped limit check —HomeService.setHome()now callscanSetHome()before writing to storage, enforcing the configured home maximum on every code path.
Changed
/home [anything]→ always opens GUI — Typing/home,/home home1, or any variant now opens the Home GUI. Players select which home to teleport to from there./sethome [anything]→ always opens GUI — Typing/sethome,/sethome myhouse, or any variant now opens the Home GUI. Players pick which slot to set from there.softdependinplugin.ymlnow includesEssentialsto guarantee correct load order relative to EssentialsX.
[1.0.6] - 2026-05-07
Added
- Team SetHome Command - Team owners can now set shared team homes with
/team sethome - Team Owner Disband - Team owners can disband teams by using
/team leave - Enhanced PlaceholderAPI - Added 18 new placeholders for teams and homes
- GUI Color Improvements - Visual distinction: cyan (ready), gray (unset), black (no permission)
- Missing Messages - Added "owner-cannot-leave" and "team-sethome-success" messages
Changed
- Major Architecture Refactoring - Complete code quality improvement following SOLID principles
- Eliminated God Class - TeamCommand.java reduced from ~400 lines to ~100 lines, now only handles routing
- New Service Layer - Created HomeService, CooldownManager, TeamValidator for better separation of concerns
- Handler Refactoring - Moved chat, color, and list logic from TeamCommand to dedicated handler classes
- Code Deduplication - Unified cooldown management and home access logic across the codebase
- Type Safety - Created GUISlots enum to eliminate magic numbers and prevent GUI slot errors
- Validation Centralization - TeamValidator provides consistent team name validation with offensive word filtering
- Memory Management - Improved performance with better object lifecycle management
- Default Warmup Time - Set to 5 seconds instead of 0 for better teleport experience
Fixed
- Message System - All placeholders now work correctly with proper config separation
- Personal Home Messages -
/sethomenow shows correct personal home messages instead of team messages - Config Issues - Fixed missing messages that caused "message not found" errors
- Placeholder Conflicts - Personal homes use home-config, team messages use team-config
- Team Home Messages - Fixed team sethome functionality and messaging
- Owner Leave Functionality - Team owners can now properly disband their teams
Enhanced
- PlaceholderAPI Integration - Added comprehensive placeholders:
- Team:
%team_name%,%team_colored_name%,%team_role%,%team_count%,%team_has_team%,%team_is_owner%,%team_is_admin%,%team_owner%,%team_has_home%,%team_home_world%,%team_home_x%,%team_home_y%,%team_home_z% - Homes:
%team_homes_count%,%team_homes_max%,%team_homes_list%,%team_has_homes%
- Team:
- GUI Visual Experience - Better color coding for different home states
- Code Maintainability - Better code organization and single responsibility principle
- Developer Experience - Clearer code structure and better documentation
- Team SetHome Command - Team owners can now set shared team homes with
[1.0.5] - 2026-05-07
Fixed
- Tab Completion —
/homeand/sethomenow only show actual homes instead of default home1,2,3 suggestions - EssentialX Compatibility — Removed blocking check that prevented
/sethome <name>from working with EssentialX installed - Missing Message — Added missing
admin-help-listmessage that caused errors in admin command help - Plugin Prefix — Changed from "[Teams]" to "[Team-Home]" for better branding
- Tab Completion —
[1.0.4] - 2026-05-07
Fixed
- Command Routing — Created separate
HomeCommandclass for/home,/sethome,/delhomecommands - /sethome Command — Now correctly sets personal home instead of team home
- /team Command — Now correctly shows team help instead of opening home GUI
- Tab Completion —
/homeand/sethomenow show home names instead of team commands - GUI Banner Color — Fixed
MenuListenerto check forBLACK_BANNERinstead ofWHITE_BANNERfor team home teleport - Tab Completion Cleanup — Removed home-related tab completion from
TeamCommandsince commands are now separate
- Command Routing — Created separate
[1.0.3] - 2026-05-06
Fixed
- Tab Completion —
/sethomenow shows existing home names in tab completion - Duplicate Home Bug —
/sethomenow properly overwrites existing homes instead of creating duplicates - EssentialX Compatibility — Added check for EssentialX plugin with permission override option
- Build Errors — Fixed syntax errors and added Vault dependency to pom.xml
Added
- EssentialX Override Permission —
teamplugin.override.essentialsto bypass EssentialX detection - EssentialX Compatibility Message — Configurable message when EssentialX is detected
- Vault Dependency — Added VaultAPI dependency for economy features
Changed
- Improved
/sethomelogic to handle existing homes correctly - Enhanced tab completion system for better user experience
- Added EssentialX compatibility layer for better server integration
- Tab Completion —
[1.0.2] - 2026-05-05
Fixed
- Paper 1.21.11 API Compatibility — Fixed
NoSuchMethodErrorforItemStack.setItemMeta()which now returnsbooleaninstead ofvoid - GUI now properly opens on
/homecommand without crashing
Added
-
New
home-config.ymloptions:gui.rows— Configurable GUI rows (3-6)gui.filler-material— Custom background materialteleport.warmup— Delay before teleport with freeze optionteleport.freeze-on-warmup— Freeze player during warmupteleport.cancel-on-move— Cancel teleport if player movesfeatures.personal-homes— Toggle personal homesfeatures.team-homes— Toggle team homesfeatures.sounds— Toggle GUI soundsdisabled-worlds— Blacklist worlds where homes are disabledeconomy.enabled— Economy integration toggleeconomy.sethome-cost/economy.teleport-cost— Costs
-
New
team-config.ymloptions:max-members— Limit team size (default: 20)features.team-chat— Toggle team chatfeatures.global-chat-prefix— Toggle [Team] prefix in global chatfeatures.sounds— Toggle team soundscreation.require-password— Require password to create teamscreation.default-invite-only— Default invite-only settingcreation.default-members-can-invite— Default member invite permissioneconomy.enabled/economy.create-cost/economy.sethome-cost— Economydamage.disable-pvp-between-members— Prevent friendly fire
Changed
- Improved README format (ZombieApocalypseSSS style)
- Updated table of contents structure
- Troubleshooting section now uses collapsible
<details>elements - Combined Commands & Permissions section for better readability
- Paper 1.21.11 API Compatibility — Fixed
1.0.1
- Fixed invalid YAML indentation in
team-config.yml. - Standardized permissions to
teamplugin.*and documented home/admin permissions inplugin.yml. - Added teleport cooldown enforcement to
/team home. - Added validation for personal home names to prevent unsafe YAML paths/reserved keys.
- Fixed team rename so command IDs, player mappings, and pending invites update with the new name.
- Made admin team creation respect
admin.team-name. - Hardened team/home data loading against invalid UUID entries.
- Fixed invalid YAML indentation in
[1.0.0] - 2026-05-05
Added
- Complete Team management system (create, invite, accept/deny, kick, leave, disband)
- Role system: Owner, Admin, Member with proper permission hierarchy
- Team Home (shared for all team members)
- Personal Multi-Home system (up to 5 homes based on permissions:
team-home-plugin.homes.3/4/5) - Beautiful Home Management GUI with sounds (click, success, error)
- Team-only chat system (
/team chat enable/disable) - Full admin commands with protected Admin team and ban system
- PlaceholderAPI expansion (
%team_name%,%team_colored_name%,%team_color%,%team_role%,%team_count%) - Comprehensive tab completion for all commands
- Pagination support for
/team list - Configurable team name validation (length, regex, reserved names)
- Full message customization through
team-config.yml - Persistent data for teams, homes, and cooldowns using YAML
- Sound effects and visual feedback in GUI
- Support for both legacy
AsyncPlayerChatEventand PaperAsyncChatEvent
Changed
- All user-facing messages moved to config for easy customization
- Improved command structure and help menus
- Enhanced GUI with better item lore and visual indicators
- Optimized data handling using
ConcurrentHashMap - Better error handling and user feedback
Fixed
- Encoding issues (mojibake) with Unicode box-drawing characters
- Cooldown persistence across server restarts
- Various minor bugs in settings and admin commands
- Improved stability and performance
Technical
- Built for Paper 1.21+
- Requires Java 21
- Soft dependencies: PlaceholderAPI, DiscordSRV
- Clean, modular code architecture (Managers + Listeners + Models)
[Unreleased]
To be added in future versions
- Team warps / team spawn
- Team bank / economy integration
- More GUI customization options
- Team PvP toggle
- Advanced permission system per team

