Skip to content
Open

Dev #567

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
dcd670a
change
Nandi0813 Apr 18, 2026
c66c623
execute extra items commands as player instead of console (#493)
Yow-sef Apr 20, 2026
5807e95
added hologram teleport command
Nandi0813 Apr 20, 2026
14b8b7b
fixed possible NPE
Nandi0813 Apr 20, 2026
5e3c6de
feat add allow-lobby-interact config option (#509)
lokspel Apr 28, 2026
f370ed6
feat(ladder): add hearts setting and enforce ladder max health in fights
Nandi0813 May 15, 2026
f885057
feat(arena): add party FFA center setting and update related commands
Nandi0813 May 15, 2026
9a3bfd5
feat(settings): update ladder settings GUI to support additional layo…
Nandi0813 May 15, 2026
a8aa75c
Merge branch 'dev' of https://github.com/ZoneDevelopement/ZonePractic…
Nandi0813 May 15, 2026
d21a16c
Missing pearl configuration & Update dependencies (26.1.2 is supporte…
lokspel May 17, 2026
ec0892f
Refactor tab integration (#527)
lokspel May 17, 2026
20d6c40
fix: fix profile worldtime default value and handle offline players i…
lokspel May 18, 2026
daa22b9
fix: add missing break statements in PartySettingsGui switch (#530)
lokspel May 18, 2026
212d419
fix: not-won round symbols rendering as filled on scoreboard (#532)
lokspel May 18, 2026
d3aa99a
Prevent throwing ender peal if cooldown is 0.0 in the start of the ma…
lokspel May 18, 2026
480bf3f
Fixes (#534)
lokspel May 18, 2026
6b0e18e
Fixes (#537)
lokspel May 18, 2026
f032f31
refactor: remove telemetry logger references from multiple classes
Nandi0813 May 19, 2026
1a51ec6
refactor: simplify arena side build limit check and update player joi…
Nandi0813 May 19, 2026
f659742
fixed possible deadlock
Nandi0813 May 19, 2026
22c53a1
Full MiniMessage support (#544)
lokspel May 19, 2026
6987723
fix: sword ladder was not loading by default (#545)
lokspel May 19, 2026
b704889
Fix sidebar (#547)
lokspel May 19, 2026
781c07c
Fix sidebar (#548)
lokspel May 19, 2026
eaa42b5
Hearts are customizable now and UGLY text (#550)
lokspel May 19, 2026
3b45c45
fix: correct typo in Sumo Rackets GUI item path
Nandi0813 May 20, 2026
8c4e1c8
refactor: add mini message display name methods for item meta and upd…
Nandi0813 May 20, 2026
e8efc55
refactor: update player head retrieval to use PlayerProfile for bette…
Nandi0813 May 20, 2026
2bf5e44
feat: add configuration options for icon editing and custom kit prese…
Nandi0813 May 20, 2026
35008d7
fix: prevent ender pearl usage when match round is not live and strea…
Nandi0813 May 20, 2026
32f9e3b
chore: remove telemetry configuration options from config.yml
Nandi0813 May 20, 2026
7ab2acf
Fix colors (#560)
lokspel May 23, 2026
23d5ea7
Fixes (#562)
lokspel May 25, 2026
1d970c6
fix: preserve custom config keys on BoostedYAML version update + Refa…
lokspel May 25, 2026
c547426
Merge branch 'dev' of https://github.com/ZoneDevelopement/ZonePractic…
Nandi0813 May 25, 2026
72da32d
changed version to 7.6.0-SNAPSHOT
Nandi0813 May 25, 2026
e06f3f0
Add player-caused explosion death message (crystals/TNT) with killer …
lokspel May 26, 2026
a286983
fix: prevent settings being overwritten with defaults on server start…
lokspel May 26, 2026
d702b49
GITBOOK-120: No subject
Nandi0813 May 26, 2026
2a03542
GITBOOK-120: No subject
Nandi0813 May 26, 2026
1ca8083
Merge branch 'dev' of https://github.com/ZoneDevelopement/ZonePractic…
Nandi0813 May 26, 2026
1fb9213
removed gitbook unnecessary
Nandi0813 May 26, 2026
52a8654
gitbook fix
Nandi0813 May 26, 2026
dd6268c
Update gitbook (#566)
lokspel May 27, 2026
fa2a865
fix: remove entities during rollback and arena copy deletion (#568)
lokspel May 27, 2026
34bbfa0
fixes for docs
Nandi0813 May 27, 2026
c841a50
updated supported versions
Nandi0813 May 27, 2026
9bddee3
fix: queue timeout not resetting player status and wrong time unit in…
lokspel May 27, 2026
752dc9f
fix: cancel queue and reset player state on world change (#571)
lokspel May 27, 2026
6b72292
fix: restore support-dependent blocks (vines, etc.) broken by physics…
lokspel May 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ For detailed guides on setup, configuration, and feature usage, please visit our

## Supported Versions

- Primary targets: **1.20.6 / 1.21.X**
- Primary targets: **1.21.11 / 26.1.2**
- Actual supported versions are detected at runtime via the `VersionChecker`
- The plugin automatically disables itself on unsupported versions

Expand Down Expand Up @@ -345,4 +345,4 @@ Copyright © **ZonePractice contributors**

## Contact

For issues, feature requests or contributions, use the project’s GitHub issue tracker.
For issues, feature requests or contributions, use the project’s GitHub issue tracker.
27 changes: 27 additions & 0 deletions SUMMARY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Table of contents

* [✌️ ZonePractice Pro](README.md)

## Overview

* [💡 Getting Started](overview/getting-started.md)

## Setup Guides

* [⚔️ Ladder Setup](setup-guides/ladder-setup.md)
* [🧊 Arena Setup](setup-guides/arena-setup.md)
* [🎮 Event Setup](setup-guides/event-setup.md)
* [✡️ Hologram Setup](setup-guides/hologram-setup.md)

## Informations

* [📜 Configuration Files](informations/configuration-files.md)
* [⚙️ Commands](informations/commands.md)
* [📚 Permissions](informations/permissions.md)

## Extra

* [9️⃣ Modern version Support Informations](extra/modern-version-support-informations.md)
* [🧱 Placeholder API](extra/placeholder-api.md)
* [🖥️ For Developers](extra/for-developers.md)
* [❔ Support](extra/support.md)
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ public void onEnable() {
faststats_metrics.ready();

if (VersionChecker.getBukkitVersion() == null) {
Common.sendConsoleMMMessage("<red>Unsupported server version! Please use 1.20.6 or 1.21.X");
Common.sendConsoleMMMessage("<red>Unsupported server version! Please use 1.21.11 or 26.1.2");
Bukkit.getPluginManager().disablePlugin(this);
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,8 @@ public void onEntityDamage(EntityDamageEvent e) {
Location lobbyLocation = ServerManager.getLobby();
if (lobbyLocation != null)
player.teleport(lobbyLocation);
e.setCancelled(true);
}

e.setCancelled(true);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,9 @@ public void run() {
}

protected void deleteNormal(final String arena, final Cuboid cuboid) {
// Remove all non-player entities before deleting blocks
removeNonPlayerEntities(cuboid);

// OPTIMIZATION: Use iterator directly instead of creating a full list in memory
final Iterator<Block> iterator = cuboid.iterator();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -233,16 +233,16 @@ public static boolean containsDestroyableBlock(Ladder ladder, Block block) {

public static boolean requiresSupport(Block block) {
Material type = block.getType();
return org.bukkit.Tag.FLOWERS.isTagged(type)
|| org.bukkit.Tag.SAPLINGS.isTagged(type)
|| org.bukkit.Tag.CROPS.isTagged(type)
|| org.bukkit.Tag.WALL_POST_OVERRIDE.isTagged(type) // torches, signs on walls, etc.
return Tag.FLOWERS.isTagged(type)
|| Tag.SAPLINGS.isTagged(type)
|| Tag.CROPS.isTagged(type)
|| Tag.WALL_POST_OVERRIDE.isTagged(type) // torches, signs on walls, etc.
|| type == Material.DEAD_BUSH
|| type == Material.SHORT_GRASS
|| type == Material.TALL_GRASS
|| type == Material.FERN
|| type == Material.LARGE_FERN
|| type == Material.VINE
|| type.name().equals("VINE") || type.name().contains("_VINE") || type.name().contains("_VINES")
|| type == Material.SUGAR_CANE
|| type == Material.CACTUS
|| type == Material.SNOW
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,14 +79,14 @@ public void onPlayerInteract(PlayerInteractEvent e) {

FFA ffa = FFAManager.getInstance().getFFAByPlayer(player);
if (ffa == null) return;

// Prevent interaction while waiting for kit selection
if (ffa.isPlayerWaitingForKitSelection(player)) {
ffa.playerSelectKit(player, player.getInventory().getHeldItemSlot());
e.setCancelled(true);
return;
}

if (!action.equals(Action.RIGHT_CLICK_AIR) && !action.equals(Action.RIGHT_CLICK_BLOCK)) return;

Block clickedBlock = e.getClickedBlock();
Expand Down Expand Up @@ -389,6 +389,9 @@ public void onPlayerDeath(PlayerDeathEvent e) {
Player killer = resolveKiller(player, ffa, damageSource);

DeathCause cause = FightUtil.convert(damageSource.getDamageType());
if (cause == DeathCause.EXPLOSION && killer != null && !killer.equals(player)) {
cause = DeathCause.EXPLOSION_BY_PLAYER;
}
ffa.killPlayer(player, killer, cause.getMessage().replace("%killer%", killer != null ? killer.getName() : "Unknown"));

if (killer != null && !killer.equals(player)) {
Expand Down Expand Up @@ -484,4 +487,4 @@ public void onEntityDamage(EntityDamageEvent e) {
}
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,32 @@ public void onBlockPlace(BlockPlaceEvent event) {
}
}

/**
* Captures support-dependent blocks for rollback before physics removes them.
* <p>
* Uses the <b>source block</b> of the physics event (the block that changed,
* triggering neighbor physics) to look up the owning fight — O(1) check instead
* of scanning all active fights for every affected neighbor.
* <p>
* At LOWEST priority the affected block still holds its original material,
* so we snapshot it before physics turns it to air.
*/
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onBlockPhysics(BlockPhysicsEvent e) {
Block block = e.getBlock();

if (!ArenaUtil.requiresSupport(block)) return;
if (BlockUtil.hasMetadata(block, PLACED_IN_FIGHT)) return;

Block source = e.getSourceBlock();
if (source == null) return;

Spectatable spectatable = getByBlock(source);
if (spectatable == null || !spectatable.isBuild()) return;

spectatable.getFightChange().addArenaBlockChange(new ChangedBlock(block));
}

@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onBlockIgnite(BlockIgniteEvent event) {
Block ignitedBlock = event.getBlock();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -691,8 +691,12 @@ public void onPlayerDeath(PlayerDeathEvent e) {
}

DeathCause cause = FightUtil.convert(damageSource.getDamageType());
if (cause == DeathCause.EXPLOSION && killer != null && !killer.equals(player)) {
cause = DeathCause.EXPLOSION_BY_PLAYER;
}
DeathCause finalCause = cause;
Bukkit.getScheduler().runTaskLater(ZonePractice.getInstance(), () ->
match.killPlayer(player, killer, cause.getMessage().replace("%killer%", killer != null ? killer.getName() : "Unknown")), 1L);
match.killPlayer(player, killer, finalCause.getMessage().replace("%killer%", killer != null ? killer.getName() : "Unknown")), 1L);

if (killer != null) {
Statistic statistic = match.getCurrentStat(killer);
Expand Down Expand Up @@ -898,4 +902,4 @@ private static boolean shouldDelegateExplosiveByEntityDamageToLadder(EntityDamag
return ladderType == LadderType.FIREBALL_FIGHT || ladderType == LadderType.TNT_SUMO;
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public enum DeathCause {
FIRE(LanguageManager.getString("FIGHT.DEATH-MESSAGES.FIRE")),
FALL(LanguageManager.getString("FIGHT.DEATH-MESSAGES.FALL")),
EXPLOSION(LanguageManager.getString("FIGHT.DEATH-MESSAGES.EXPLOSION")),
EXPLOSION_BY_PLAYER(LanguageManager.getString("FIGHT.DEATH-MESSAGES.EXPLOSION-BY-PLAYER")),
PLAYER_ATTACK(LanguageManager.getString("FIGHT.DEATH-MESSAGES.PLAYER")),
PLAYER_PROJECTILE(LanguageManager.getString("FIGHT.DEATH-MESSAGES.PROJECTILE")),
SUMO(LanguageManager.getString("FIGHT.DEATH-MESSAGES.SUMO-FALL")),
Expand Down Expand Up @@ -41,4 +42,4 @@ public static DeathCause convert(EntityDamageEvent.DamageCause damageCause) {
};
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -313,13 +313,15 @@ public void onInventoryClick(InventoryClickEvent e) {
public void onPlayerDropItem(PlayerDropItemEvent e) {
Player player = e.getPlayer();

if (isTaggedCosmetic(e.getItemDrop().getItemStack())) {
Profile profile = ProfileManager.getInstance().getProfile(player);
ProfileStatus profileStatus = profile != null ? profile.getStatus() : null;

if (profileStatus != ProfileStatus.OFFLINE && isTaggedCosmetic(e.getItemDrop().getItemStack())) {
e.setCancelled(true);
return;
}

Profile profile = ProfileManager.getInstance().getProfile(player);
ProfileStatus profileStatus = profile.getStatus();
if (profileStatus == null) return;

switch (profileStatus) {
case LOBBY:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,10 @@ public Player getOnlinePlayer() {
// Data persistence

public void saveData() {
if (!fullDataLoaded) {
return;
}

rankedBan.saveToConfig(file.getConfig(), "ranked-ban");

saveCustomLadders();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ public void run() {
}

if (seconds >= maxQueueTime) {
this.endQueue(false, LanguageManager.getString("QUEUES.NO-MATCH-IN-TIME").replace("%maxTime%", String.valueOf(maxQueueTime)));
this.endQueue(false, LanguageManager.getString("QUEUES.NO-MATCH-IN-TIME").replace("%maxTime%", String.valueOf(maxQueueTime / 60)));
return;
}

Expand All @@ -293,4 +293,4 @@ public String getFormattedDuration() {
return StringUtil.formatMillisecondsToMinutes(seconds * 1000L);
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,9 @@ public void run() {
CustomKitQueueManager.getInstance().cancelHostedQueue(player, false, true);
}

CustomKitQueueManager.getInstance().cancelJoinSearch(player, false, false);
CustomKitQueueManager.getInstance().cancelJoinSearch(player, false, true);
Common.sendMMMessage(player, LanguageManager.getString("QUEUES.NO-MATCH-IN-TIME")
.replace("%maxTime%", String.valueOf(MAX_JOIN_SEARCH_TIME)));
.replace("%maxTime%", String.valueOf(MAX_JOIN_SEARCH_TIME / 60)));
return;
}

Expand Down Expand Up @@ -99,4 +99,4 @@ public enum SearchMode {
HOST,
JOIN_OTHERS
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import dev.nandi0813.practice.manager.profile.Profile;
import dev.nandi0813.practice.manager.profile.ProfileManager;
import dev.nandi0813.practice.manager.profile.enums.ProfileStatus;
import dev.nandi0813.practice.manager.queue.QueueManager;
import dev.nandi0813.practice.manager.sidebar.SidebarManager;
import dev.nandi0813.practice.util.Common;
import dev.nandi0813.practice.util.GoldenHead;
Expand Down Expand Up @@ -212,6 +213,10 @@ public void onTeleport(PlayerTeleportEvent e) {
if (profile.getStatus().equals(ProfileStatus.LOBBY)) {
ProfileManager.getInstance().getProfile(player).setStatus(ProfileStatus.OFFLINE);
SidebarManager.getInstance().unLoadSidebar(player);
} else if (profile.getStatus().equals(ProfileStatus.QUEUE)) {
QueueManager.getInstance().endAllQueuesForPlayer(player, true, null);
profile.setStatus(ProfileStatus.OFFLINE);
SidebarManager.getInstance().unLoadSidebar(player);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ public final class VersionChecker {
private VersionChecker() {}

private static volatile BukkitVersion bukkitVersion;
private static final String SUPPORTED_1_21 = "1.21.11";
private static final String SUPPORTED_26 = "26.1.2";

// Matches strings like "(MC: 1.8.8)" or "(MC: 1.21)"
private static final Pattern MC_VERSION_PATTERN = Pattern.compile("\\(MC: ([0-9]+\\.[0-9]+(?:\\.[0-9]+)?)\\)");
Expand All @@ -37,11 +39,11 @@ public static BukkitVersion getBukkitVersion() {
return null;
}

if (mcVersion.startsWith("1.21")) {
if (SUPPORTED_1_21.equals(mcVersion)) {
bukkitVersion = BukkitVersion.v1_21_R3;
}
else if (mcVersion.startsWith("26")) {
bukkitVersion = BukkitVersion.v_26_1_R1;
else if (SUPPORTED_26.equals(mcVersion)) {
bukkitVersion = BukkitVersion.v_26_1_R2;
}
else {
ZonePractice.getInstance().getLogger().warning("Unsupported MC version: " + mcVersion);
Expand All @@ -63,7 +65,7 @@ private static String extractMcVersion(final String bukkitVersionString) {
@Getter
public enum BukkitVersion {
v1_21_R3, // 1.21.11
v_26_1_R1, // 26.1
v_26_1_R2, // 26.1.2
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,10 @@ private boolean isHologramTextDisplay(Entity entity) {
* Used when server is shutting down.
*/
public void quickRollback() {
// Remove all entities before restoring blocks so entities (end crystals, etc.)
// don't leak into the next server session.
removeAllEntities();

List<Map.Entry<Long, BlockChangeEntry>> sorted = new ArrayList<>(blocks.entrySet());
sorted.sort(rollbackComparator());

Expand Down
5 changes: 3 additions & 2 deletions core/src/main/resources/language.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
VERSION: 42
VERSION: 43

CONSOLE-NAME: "<red>Console"
CANT-USE-CONSOLE: "<red>You can't use this command from the console."
Expand Down Expand Up @@ -1765,9 +1765,10 @@ FIGHT:
FIRE: "<red>%player% <yellow>burned to death."
FALL: "<red>%player% <yellow>fell to their death."
EXPLOSION: "<red>%player% <yellow>blew up."
EXPLOSION-BY-PLAYER: "<red>%player% <yellow>was blown up by <gold>%killer%<yellow>."
PLAYER: "<red>%player% <yellow>was killed by <gold>%killer%<yellow>."
PROJECTILE: "<red>%player% <yellow>was shot by <gold>%killer%<yellow>."
SUMO-FALL: "<red>%player% <yellow>fell out of the sumo circle."
SPLEEF-FALL: "<red>%player% <yellow>fell out of the spleef arena."
OWN-PORTAL-JUMP: "<red>%player% <yellow>jumped into their own portal and died."
DEFAULT: "<red>%player% <yellow>died."
DEFAULT: "<red>%player% <yellow>died."
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added gitbook/.gitbook/assets/ezgif.com-gif-maker.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added gitbook/.gitbook/assets/ezgif.com-optimize.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added gitbook/.gitbook/assets/ezgif.com-reverse (1).gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added gitbook/.gitbook/assets/ezgif.com-reverse-10.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added gitbook/.gitbook/assets/ezgif.com-reverse-2.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added gitbook/.gitbook/assets/ezgif.com-reverse-3.gif
Binary file added gitbook/.gitbook/assets/ezgif.com-reverse-4.gif
Binary file added gitbook/.gitbook/assets/ezgif.com-reverse-5.gif
Binary file added gitbook/.gitbook/assets/ezgif.com-reverse-6.gif
Binary file added gitbook/.gitbook/assets/ezgif.com-reverse-7.gif
Binary file added gitbook/.gitbook/assets/ezgif.com-reverse-8.gif
Binary file added gitbook/.gitbook/assets/ezgif.com-reverse-9.gif
Binary file added gitbook/.gitbook/assets/ezgif.com-reverse.gif
42 changes: 42 additions & 0 deletions gitbook/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
description: Official documentation for ZonePractice Pro.
---

# ZonePractice Pro

ZonePractice Pro is a modular Minecraft practice plugin built for modern Paper servers. It features 13 ladder types, ranked/unranked queues, 7 event modes, FFA arenas, party modes (FFA/Split/PvP), match history, cosmetics (armor trims, death effects, shields), custom player kits, hologram leaderboards, staff mode, nick formatting, and full PlaceholderAPI support.

<figure><img src=".gitbook/assets/zonepractice-features.jpg" alt="ZonePractice features"><figcaption><p>Main systems overview</p></figcaption></figure>

## Start here (new server owners)

1. [Getting Started](overview/getting-started.md)
2. [Ladder Setup](setup-guides/ladder-setup.md)
3. [Arena Setup](setup-guides/arena-setup.md)
4. [Event Setup](setup-guides/event-setup.md)
5. [Hologram Setup](setup-guides/hologram-setup.md)

## New in recent releases

- **Cosmetics system** (`/cosmetics`) — armor trims, death effects, shield layouts, lobby movement
- **Custom player kits** (`/editor`, `/customqueue`) — create, share, and queue with custom kits
- **Nick system** (`/nick`) — MiniMessage display name formatting
- **Match history** (`/matchhistory`) — review recent matches
- **Combined queue GUI** — single lobby queue item for ranked/unranked
- **Multi-queue** — queue for multiple ladders simultaneously
- **TNT Sumo / Battle Rush / Pearl Fight** ladder types
- **Juggernaut** event mode
- **Party FFA center** arena setting
- **FAWE fast copy** support for arena cloning

## Reference pages

- [Configuration Files](informations/configuration-files.md)
- [Commands](informations/commands.md)
- [Permissions](informations/permissions.md)
- [Placeholder API](extra/placeholder-api.md)
- [For Developers](extra/for-developers.md)

## Official support

- Discord: [https://discord.gg/XFUhvJR9eN](https://discord.gg/XFUhvJR9eN)
Loading
Loading