Nexal Combat Log
Combat logging prevention for Minecraft servers (Spigot and Paper). A player who disconnects while tagged in combat leaves an NPC holding their items, dies on the spot, or is only recorded, depending on the mode. A Vault fine, a temp-ban command and custom console commands can be stacked on top.
Features
- Combat Tagging: PvP hits tag both players (projectiles, tamed pets, TNT and lingering potions count as the player's); optional PvE tagging for a configurable list of mobs
- Combat Indicators: boss bar, action bar and sidebar scoreboard countdowns, each toggleable
- Punishment Modes for a tagged player who disconnects:
NPC: a zombie NPC spawns with their armor, weapon and offhand and holds their whole inventory. If it is killed, everything drops. If it survives (it expires, the player rejoins first, its chunk unloads or the server stops), the items are stored and given back on the next joinINSTANT_DEATH: the player dies at once and their items drop where they logged outNONE: the combat log is only recorded
- Add-on punishments: a Vault fine, a temp-ban command (for EssentialsX, LiteBans or any ban plugin) and custom console commands, applied when the player is punished (on disconnect in instant death mode, when the NPC is killed in NPC mode). The player is told what was applied when they rejoin
- NPC Details: hologram countdown (native, no hologram plugin needed), a timer that resets when the NPC is hit, the player's health or a custom health, no burning in daylight
- Command Blocking: blacklist or whitelist mode; entries match whole command names, plugin-prefixed commands (
/essentials:home) and a plugin command's aliases; a trailing*matches a prefix - Safe Zone Prevention: WorldGuard integration blocks tagged players from walking or pearling into regions where PvP is denied (or custom regions)
- Admin GUI:
/combatlog adminopens a hub with the settings (combat, indicators, NPC, punishment, command blocking, safe zones, exempt reminders, death snapshot limit), the exempt list and every player's death log - Exempt System: players who are never tagged, stored with the plugin data, with periodic reminders to staff
- Death Inventory Log: browse every death (NPC killed or instant death) and the exact inventory at that moment
- Statistics: combat logs, NPC kills and deaths, times tagged, fines paid and punishments, with a stats GUI, a leaderboard GUI and PlaceholderAPI placeholders
- Dual Storage: JSON or MySQL/MariaDB, with export and import to move between them
Technologies
- Paper API 1.20.1+: Minecraft server API (Spigot compatible)
- Utilizer: Configuration, messages, GUIs, holograms, scheduling
- ACF: Command framework
- nexal-core: JSON and SQL persistence (MariaDB/MySQL), help menu, licensing
- Vault, WorldGuard, PlaceholderAPI: optional integrations
Commands
Aliases: /cl, /combat.
Player Commands
| Command | Description | Permission |
|---|---|---|
/combatlog or /combatlog help [page] | Show help | None |
/cl stats [player] | View combat statistics | nexalcombatlog.stats |
/cl gui | Open stats GUI | nexalcombatlog.gui |
/cl leaderboard (lb, top) | Open leaderboard GUI | nexalcombatlog.leaderboard |
/cl deaths | View your death inventory log | nexalcombatlog.deaths |
Admin Commands
| Command | Description | Permission |
|---|---|---|
/cl admin | Open the admin GUI (console: list the admin commands) | nexalcombatlog.admin |
/cl admin help [page] | List the admin commands | nexalcombatlog.admin |
/cl admin deaths \<player> | View a player's death inventory log | nexalcombatlog.admin |
/cl admin tag \<player> [duration] | Force tag a player in combat (duration in seconds, above 0) | nexalcombatlog.admin |
/cl admin untag \<player> | Remove combat tag from player | nexalcombatlog.admin |
/cl admin exempt add \<player> | Exempt an online player from combat tagging | nexalcombatlog.admin |
/cl admin exempt remove \<player> | Remove exemption | nexalcombatlog.admin |
/cl admin exempt list | List all exempted players | nexalcombatlog.admin |
/cl admin reload | Reload configuration | nexalcombatlog.admin |
/cl admin export | Export data to JSON files in export/ | nexalcombatlog.admin |
/cl admin import | Import data from the JSON files in export/ | nexalcombatlog.admin |
Permissions
| Permission | Description | Default |
|---|---|---|
nexalcombatlog.stats | View own and others' stats | true |
nexalcombatlog.gui | Open stats GUI | true |
nexalcombatlog.leaderboard | View leaderboard | true |
nexalcombatlog.deaths | View death inventory log | true |
nexalcombatlog.admin | Admin GUI and all admin commands | op |
nexalcombatlog.bypass | Bypass combat tagging entirely | op |
nexalcombatlog.bypass.commands | Use blocked commands while in combat | op |
nexalcombatlog.notify | Receive admin notifications (exempt warnings) | op |
Configuration
Changes to config.yml and messages.yml apply automatically. The most used settings can also be changed in /combatlog admin → Configuration. A storage type change needs a restart.
config.yml
storage:
type: json # json or sql
sql:
host: localhost
port: 3306
database: minecraft
username: root
password: ""
combat:
duration: 15 # Tag duration in seconds
pve-enabled: false # Mobs in pve-entities also tag the player they hit
pve-entities: [ZOMBIE, SKELETON, CREEPER, ...]
reset-on-hit: true # Each hit restarts the timer (false: only tops it up)
indicators:
boss-bar:
enabled: true
color: RED # RED, BLUE, GREEN, YELLOW, PURPLE, PINK, WHITE
style: SOLID # SOLID, SEGMENTED_6, SEGMENTED_10, SEGMENTED_12, SEGMENTED_20
title: "..." # %seconds%, %attacker%
action-bar:
enabled: true
message: "..." # %seconds%, %attacker%
scoreboard:
enabled: false
title: "..."
lines: [...] # %seconds%, %attacker%
npc:
duration: 10 # Seconds the NPC stays before it expires
reset-on-damage: true # Hitting the NPC restarts its timer
name: "\<red>%player%'s Logger\</red>"
use-player-health: true # false: use custom-health (may be above 20)
custom-health: 20.0
hologram:
enabled: true
lines: [...] # MiniMessage or & codes; %player%, %seconds%, %health%, %max_health%
offset-y: 2.5
broadcast-spawn: true
broadcast-kill: true
punishment:
mode: NPC # NPC, INSTANT_DEATH or NONE
temp-ban:
enabled: false
duration: 300 # Seconds, passed to the command as %duration%
command: "tempban %player% %duration%s Combat logging"
fine:
enabled: false # Needs Vault and an economy plugin
amount: 1000.0
commands: [] # Console commands, %player% = player name
commands:
mode: BLACKLIST # BLACKLIST or WHITELIST
blacklist: [home, sethome, spawn, tp, tpa, warp, back, rtp, ...]
whitelist: [msg, message, tell, whisper, r, reply, helpop]
safe-zones:
enabled: true # Needs WorldGuard
prevent-entry: true
custom-regions: [] # Empty: regions where PvP is denied
exempt:
warning-interval: 10 # Minutes between staff reminders (0 to disable)
death-log:
max-snapshots: 0 # Inventory snapshots kept per player (0 = unlimited)
The temp ban, fine and custom commands apply when the player is punished: on disconnect in INSTANT_DEATH mode, and when the NPC is killed in NPC mode (the temp ban then runs while the player is offline; the fine and commands run when they rejoin). Nothing is applied in NONE mode or when the NPC survives.
Command list entries are command names without /. home also blocks /essentials:home and /ehome (an EssentialsX alias of home). tp* blocks every command starting with tp.
messages.yml
All chat messages are customizable, with:
- MiniMessage format (
<gradient:...>,\<bold>,\<gray>, ...) and legacy&codes - PlaceholderAPI placeholders
- Sounds, titles and subtitles
The GUI titles (gui-stats-title, gui-leaderboard-title), the empty leaderboard text (gui-no-stats) and the page label (gui-page-info) are in messages.yml too. Keys added by an update fall back to the bundled defaults until you add them to your file.
Moving between JSON and SQL
Run /cl admin export, set storage.type to the new type, restart, then run /cl admin import. Export and import cover players, combat log entries, death snapshots, the exempt list and pending reconnects (items held for players who have not rejoined).
PlaceholderAPI Placeholders
| Placeholder | Description |
|---|---|
%combatlog_in_combat% | "yes" or "no" |
%combatlog_in_combat_colored% | "&cYes" or "&aNo" |
%combatlog_remaining% | Formatted time remaining (e.g. "15s", "1m 5s") |
%combatlog_remaining_seconds% | Raw seconds remaining |
%combatlog_combat_logs% | Player's combat log count |
%combatlog_npc_kills% | NPCs killed by player |
%combatlog_npc_deaths% | Player's NPC death count |
%combatlog_times_tagged% | Total times tagged |
%combatlog_fines_paid% | Total fines paid (e.g. "1,000") |
%combatlog_punishments% | Times punished (instant death or NPC killed) |
%combatlog_exempt% | "yes" or "no" |
%combatlog_top_\<n>_name% | Name at position n by combat logs |
%combatlog_top_\<n>_logs% | Combat logs at position n |
%combatlog_top_\<n>_kills% | NPC kills at position n of the NPC kills ranking |
%combatlog_top_\<n>_deaths% | NPC deaths at position n of the NPC deaths ranking |
%combatlog_top_\<n>_tagged% | Times tagged at position n of the times tagged ranking |
%combatlog_top_\<n>_\<stat>_name% | Name at position n of that ranking (logs, kills, deaths, tagged) |
Rankings list players with a value above 0; an empty position returns N/A. Offline players (in holograms or tab lists) get their stored stats and are never in combat.
Database Schema
Column names are the field names. In JSON storage each table is a key in data.json. Tables created by 1.0.2 or earlier stored inventories as TEXT; those columns are widened to MEDIUMTEXT on startup.
combatlog_users
| Column | Type | Description |
|---|---|---|
| id | VARCHAR(36) | Player UUID (PK) |
| playerName | VARCHAR(16) | Player name |
| combatLogs | INT | Times logged out in combat |
| npcKills | INT | NPCs killed by player |
| npcDeaths | INT | Player's NPC was killed |
| timesTagged | INT | Total times tagged |
| punishmentsIssued | INT | Times punished |
| finesPaid | DOUBLE | Total fines |
| lastTagTime | BIGINT | Last tag timestamp |
| createdAt | BIGINT | Record created |
| updatedAt | BIGINT | Last updated |
combatlog_entries
| Column | Type | Description |
|---|---|---|
| id | VARCHAR(36) | Entry UUID (PK) |
| playerId | VARCHAR(36) | Player who logged |
| playerName | VARCHAR(16) | Player name |
| attackerId | VARCHAR(36) | Attacker UUID |
| attackerName | VARCHAR(16) | Attacker name |
| timestamp | BIGINT | Event timestamp |
| logType | VARCHAR(32) | DISCONNECT, NPC_KILLED, NPC_EXPIRED or INSTANT_DEATH |
| npcWasKilled | BOOLEAN | NPC died |
| npcKillerId | VARCHAR(36) | Who killed the NPC |
| npcKillerName | VARCHAR(16) | Killer name |
combatlog_death_snapshots
| Column | Type | Description |
|---|---|---|
| id | VARCHAR(36) | Entry UUID (PK, same as the combat log entry) |
| playerId | VARCHAR(36) | Player UUID |
| inventoryData | MEDIUMTEXT | Base64-encoded inventory |
| armorData | MEDIUMTEXT | Base64-encoded armor |
| offhandData | MEDIUMTEXT | Base64-encoded offhand |
| timestamp | BIGINT | Snapshot timestamp |
combatlog_exempt
| Column | Type | Description |
|---|---|---|
| id | VARCHAR(36) | Player UUID (PK) |
| playerName | VARCHAR(16) | Player name when exempted |
| addedAt | BIGINT | When the exemption was added |
combatlog_pending_reconnects
What happened to a combat logger, kept until they rejoin.
| Column | Type | Description |
|---|---|---|
| id | VARCHAR(36) | Player UUID (PK) |
| playerName | VARCHAR(16) | Player name |
| outcome | VARCHAR(32) | HELD (items to give back), NPC_KILLED or INSTANT_DEATH |
| killerName | VARCHAR(36) | Who killed the NPC |
| inventoryData | MEDIUMTEXT | Base64-encoded inventory held for the player |
| armorData | MEDIUMTEXT | Base64-encoded armor held for the player |
| offhandData | MEDIUMTEXT | Base64-encoded offhand held for the player |
| fineTaken | DOUBLE | Fine taken on disconnect |
| banned | BOOLEAN | Whether the temp-ban command ran |
| createdAt | BIGINT | Record created |
Soft Dependencies
- PlaceholderAPI: placeholders
- Vault: economy fines
- WorldGuard: safe zone detection
- DecentHolograms, HolographicDisplays, FancyHolograms: optional hologram providers (native holograms work without them)
How It Works
- A player hits another → both are tagged for combat (dying ends the tag)
- The timer runs → boss bar, action bar or scoreboard show the countdown
- Commands are blocked → teleports and the like, per the blacklist or whitelist
- Safe zones are closed → a tagged player cannot enter them (WorldGuard)
- The player disconnects while tagged → an NPC spawns holding their items (NPC mode), or they die (instant death mode)
- The NPC is killed → their items drop, the killer is credited and the temp ban runs
- The NPC survives → their items are given back when they rejoin
- The player rejoins → they are told what happened; after an NPC death the fine and commands apply
Installation
- Download the plugin JAR
- Place it in the
/pluginsfolder - Start or restart the server
- Configure
config.ymlor use/combatlog admin(changes apply automatically; a storage type change needs a restart)