**## Overview
CombatMetrics is a lightweight, high-performance combat tracking plugin for Paper 1.21+ servers. It accurately detects and displays Critical Hits and Sprint Combo Hits in real-time using the player's Action Bar. The plugin faithfully replicates vanilla Minecraft's exact combat mechanics, ensuring that every tracked hit matches what would trigger the corresponding subtitle/particle effect in the base game.
Core Concept
┌─────────────────────────────────────────────────────────────────────┐
│ COMBATMETRICS FLOW │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ PLAYER ATTACKS ENTITY │
│ │ │
│ ▼ │
│ ┌────────────────────┐ ┌────────────────────┐ │
│ │ Check Critical │ │ Check Combo │ │
│ │ Hit Conditions │ │ Hit Conditions │ │
│ │ (11 Checks) │ │ (3 Checks) │ │
│ └─────────┬──────────┘ └─────────┬──────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌────────────────────┐ ┌────────────────────┐ │
│ │ Increment Crit │ │ Increment Combo │ │
│ │ Counter │ │ Counter │ │
│ └─────────┬──────────┘ └─────────┬──────────┘ │
│ │ │ │
│ └───────────┬───────────────┘ │
│ ▼ │
│ ┌────────────────────────┐ │
│ │ UPDATE ACTION BAR │ │
│ │ [ ☠ CRITS: X | ⚔ COMBO: Y ] │
│ └────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────┐ │
│ │ No hit for 2 seconds? │ │
│ │ → Reset counters to 0 │ │
│ └────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
✨ Features
Core Features
| Feature | Description |
|---|---|
| Critical Hit Tracking | Detects vanilla-accurate critical hits using 11 strict conditions |
| Combo Hit Tracking | Detects sprint knockback hits for combo counting |
| Real-Time Display | Shows live counters in the Action Bar |
| Auto Reset | Counters automatically reset after 2 seconds of inactivity |
| Left-Aligned Display | Text positioned on left side of screen for better visibility |
| Hit Highlighting | Brief green flash when a hit is registered |
Persistence Features
| Feature | Description |
|---|---|
| Per-Player Toggle | Each player can enable/disable their display |
| Survives Relog | Preference saved using PersistentDataContainer |
| Survives Restart | Settings persist across server restarts |
| No External Storage | Data stored directly on player entity |
⚡ Performance Features
| Feature | Description |
|---|---|
| Async Timer Checks | Reset detection runs on async thread |
| Efficient Data Storage | ConcurrentHashMap for thread-safe access |
| Minimal Overhead | Early-return conditions prevent unnecessary processing |
| Lazy Initialization | Data created only when player attacks |
| Lightweight Task | Timer runs every 5 ticks (0.25 seconds) |
☠️ Critical Hit Detection
CombatMetrics uses vanilla-accurate detection that matches Minecraft's exact critical hit requirements. A hit is only counted as critical if ALL conditions are met:
Condition Checklist
| # | Condition | Method Used | Explanation |
|---|---|---|---|
| 1 | Falling | fallDistance > 0.0 | Player must have positive fall distance |
| 2 | Airborne | !isOnGround() | Player cannot be touching the ground |
| 3 | Not Climbing | !isClimbing() | Cannot be on ladder, vine, or scaffolding |
| 4 | Not In Water | !isInWater() | Cannot be submerged in water |
| 5 | Not In Lava | !isInLava() | Cannot be submerged in lava |
| 6 | Not Swimming | !isSwimming() | Cannot be using swimming animation |
| 7 | Not Gliding | !isGliding() | Cannot be flying with Elytra |
| 8 | No Blindness | !hasPotionEffect(BLINDNESS) | Blindness effect blocks crits |
| 9 | No Slow Falling | !hasPotionEffect(SLOW_FALLING) | Slow falling prevents crits |
| 10 | Not Mounted | !isInsideVehicle() | Cannot be riding any entity |
| 11 | Charged Attack | getAttackCooldown() > 0.9 | Attack must be 90%+ charged |
Visual Representation
CRITICAL HIT VALIDATION
Player State Check Result
══════════════════════════════════════════
fallDistance > 0 ? ───────────→ ✓ PASS
│
▼
!isOnGround() ? ───────────→ ✓ PASS
│
▼
!isClimbing() ? ───────────→ ✓ PASS
│
▼
!isInWater() ? ───────────→ ✓ PASS
│
▼
!isInLava() ? ───────────→ ✓ PASS
│
▼
!isSwimming() ? ───────────→ ✓ PASS
│
▼
!isGliding() ? ───────────→ ✓ PASS
│
▼
No BLINDNESS ? ───────────→ ✓ PASS
│
▼
No SLOW_FALLING ? ───────────→ ✓ PASS
│
▼
!isInsideVehicle()? ───────────→ ✓ PASS
│
▼
attackCooldown > 0.9? ─────────→ ✓ PASS
│
▼
══════════════════════════════════════════
│
▼
★ CRITICAL HIT REGISTERED ★
⚔️ Combo Hit Detection
Combo hits detect sprint knockback attacks - the enhanced knockback applied when a player hits an enemy while sprinting.
Condition Checklist
| # | Condition | Method Used | Explanation |
|---|---|---|---|
| 1 | Sprinting | isSprinting() | Player must be actively sprinting |
| 2 | Charged Attack | getAttackCooldown() > 0.9 | Attack must be 90%+ charged |
| 3 | Living Target | instanceof LivingEntity | Target must be able to receive knockback |
Visual Representation
COMBO HIT VALIDATION
Player State Check Result
══════════════════════════════════════════
isSprinting() ? ───────────→ ✓ PASS
│
▼
attackCooldown > 0.9? ─────────→ ✓ PASS
│
▼
Target is Living? ───────────→ ✓ PASS
│
▼
══════════════════════════════════════════
│
▼
★ COMBO HIT REGISTERED ★
️ Visual Display System
Action Bar Format
┌─────────────────────────────────────────────────────────────────────┐
│ │
│ [ ☠ CRITS: 5 | ⚔ COMBO: 3 ] │
│ ↑ ↑ │
│ └── Left-aligned content └── Invisible spacing pushes left │
│ │
└─────────────────────────────────────────────────────────────────────┘
Color Scheme
| Element | Color | Style |
|---|---|---|
[ ] | Dark Gray | Normal |
☠ | Dark Red | Normal |
CRITS: | Red | Bold |
| Crit Count | White | Normal |
| | Dark Gray | Normal |
⚔ | Gold | Normal |
COMBO: | Yellow | Bold |
| Combo Count | White | Normal |
Hit Highlight Effect
When a hit is registered, the corresponding counter briefly highlights:
Normal Display:
[ ☠ CRITS: 5 | ⚔ COMBO: 3 ]
↑ ↑
White White
After Critical Hit (3 ticks):
[ ☠ CRITS: 6 | ⚔ COMBO: 3 ]
↑
GREEN + BOLD
After Combo Hit (3 ticks):
[ ☠ CRITS: 6 | ⚔ COMBO: 4 ]
↑
GREEN + BOLD
Left-Alignment Technique
Minecraft's Action Bar centers text by default. To achieve left-alignment:
// Append invisible spacing after the content
Component content = actualContent
.append(Component.text(" ") // ~80 spaces
.color(NamedTextColor.BLACK)); // Invisible
This pushes the visible content to the left side of the screen, near the health/armor display.
⏱️ Reset Timer System
How It Works
┌─────────────────────────────────────────────────────────────────────┐
│ RESET TIMER SYSTEM │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ TIME ──────────────────────────────────────────────────────→ │
│ │
│ HIT! RESET! │
│ │ │ │
│ ▼ ▼ │
│ ●━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━● │
│ │←────────────── 2000ms (40 ticks) ──────────────→│ │
│ │ │ │
│ lastHitTime currentTime │
│ │
│ │
│ [Async Task - Every 5 ticks] │
│ │ │
│ ▼ │
│ if (currentTime - lastHitTime >= 2000ms) { │
│ resetCounter(); │
│ updateActionBar(); // Show 0 briefly │
│ } │
│ │
└─────────────────────────────────────────────────────────────────────┘
Independent Timers
Critical and Combo counters have separate timers:
SCENARIO: Player lands a crit, then keeps doing combo hits
Time: 0s 1s 2s 3s 4s 5s
│ │ │ │ │ │
Crits: [1]─────[1]─────[0] (reset at 2s)
│ │ │
Combos: [1]────[2]────[3]────[4]─────[4]─────[0]
↑ ↑
last combo reset at 5s
Grace Period
After counters reset to 0, there's a brief 500ms grace period before the display clears entirely:
HIT! → 2 seconds → RESET TO 0 → 500ms → CLEAR DISPLAY
↓
Show "[ ☠ CRITS: 0 | ⚔ COMBO: 0 ]" briefly
Commands & Permissions
Commands
| Command | Description | Permission |
|---|---|---|
/metrics toggle | Enable/disable action bar display | combatmetrics.use |
/metrics status | View current stats and settings | combatmetrics.use |
/metrics reset | Reset both counters to zero | combatmetrics.use |
Command Aliases
/combatmetrics/cm
Permissions
| Permission | Default | Description |
|---|---|---|
combatmetrics.use | true | Access to all player commands |
combatmetrics.admin | op | Reserved for future admin features |
Command Output Examples
Toggle ON:
✓ Combat Metrics ENABLED
Your combat stats will now display in the action bar.
Toggle OFF:
✗ Combat Metrics DISABLED
Action bar display has been turned off.
Status:
══════ Combat Metrics Status ══════
Display: ENABLED
Current Session:
☠ Critical Hits: 15
⚔ Combo Hits: 23
Reset:
↺ Counters have been reset!
Data Persistence
PersistentDataContainer (PDC) Storage
┌─────────────────────────────────────────────────────────────────────┐
│ PERSISTENCE SYSTEM │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ Namespace: combatmetrics │
│ Key: metrics_display_enabled │
│ Type: BYTE │
│ │
│ Values: │
│ 0 = Display DISABLED │
│ 1 = Display ENABLED │
│ null = Default to ENABLED │
│ │
│ Storage Location: Player Entity NBT Data │
│ │
└─────────────────────────────────────────────────────────────────────┘
Persistence Benefits
| Benefit | Description |
|---|---|
| No Files | No YAML/JSON configuration files per player |
| No Database | No MySQL/SQLite required |
| Automatic | Saved with player data automatically |
| Reliable | Survives crashes, restarts, and relogs |
| Lightweight | Single byte per player |
⚡ Performance Analysis
Memory Usage
Per Player:
┌────────────────────────────────────┐
│ MetricData Object │
├────────────────────────────────────┤
│ int critCount = 4 bytes │
│ int comboCount = 4 bytes │
│ long lastCritTime = 8 bytes │
│ long lastComboTime = 8 bytes │
│ boolean needsUpdate = 1 byte │
│ Object overhead ≈ 16 bytes │
├────────────────────────────────────┤
│ TOTAL ≈ 41 bytes │
└────────────────────────────────────┘
100 Players = ~4.1 KB memory
1000 Players = ~41 KB memory
CPU Usage
| Task | Frequency | Cost |
|---|---|---|
| Damage Event Handler | Per attack | Very Low (early returns) |
| Async Reset Checker | Every 5 ticks | Minimal (simple timestamp comparison) |
| Action Bar Update | On hit/reset | Low (Component creation) |
Optimization Techniques Used
| Technique | Implementation |
|---|---|
| Early Returns | Check cooldown first before other conditions |
| Async Processing | Timer checks run off main thread |
| ConcurrentHashMap | Thread-safe without locks |
| Lazy Loading | MetricData created on first attack |
| Minimal Allocations | Reuse patterns where possible |
| Event Priority | MONITOR priority - runs after other plugins |
Event Flow
Complete Event Lifecycle
┌─────────────────────────────────────────────────────────────────────┐
│ COMPLETE EVENT FLOW │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 1. EntityDamageByEntityEvent Fired │
│ │ │
│ ▼ │
│ 2. Check: Damager is Player? │
│ │ NO → EXIT │
│ │ YES ↓ │
│ ▼ │
│ 3. Check: Target is LivingEntity? │
│ │ NO → EXIT │
│ │ YES ↓ │
│ ▼ │
│ 4. Check: Attack Cooldown > 0.9? │
│ │ NO → EXIT (weak attack) │
│ │ YES ↓ │
│ ▼ │
│ 5. Check Critical Hit Conditions (11 checks) │
│ │ PASS → Increment Crit Counter │
│ ▼ │
│ 6. Check Combo Hit Conditions (2 checks) │
│ │ PASS → Increment Combo Counter │
│ ▼ │
│ 7. Either counter incremented? │
│ │ NO → EXIT │
│ │ YES ↓ │
│ ▼ │
│ 8. Check: Display Enabled for Player? │
│ │ NO → EXIT │
│ │ YES ↓ │
│ ▼ │
│ 9. Update Action Bar with Highlight │
│ │ │
│ ▼ │
│ 10. Schedule Highlight Removal (3 ticks) │
│ │
└─────────────────────────────────────────────────────────────────────┘
Async Reset Task Flow
┌─────────────────────────────────────────────────────────────────────┐
│ ASYNC RESET TASK │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ [Runs every 5 ticks on Async Thread] │
│ │ │
│ ▼ │
│ FOR each online player: │
│ │ │
│ ▼ │
│ Get MetricData (if exists) │
│ │ NULL → SKIP │
│ │ EXISTS ↓ │
│ ▼ │
│ Check: shouldResetCrit(currentTime)? │
│ │ YES → resetCrit() │
│ ▼ │
│ Check: shouldResetCombo(currentTime)? │
│ │ YES → resetCombo() │
│ ▼ │
│ Any reset occurred? │
│ │ NO → CONTINUE │
│ │ YES ↓ │
│ ▼ │
│ Schedule SYNC task: │
│ - Update action bar │
│ - Or clear if both expired │
│ │
└─────────────────────────────────────────────────────────────────────┘
Use Cases
PvP Servers
| Use Case | Benefit |
|---|---|
| Competitive PvP | Players can track their crit consistency |
| Practice Servers | Train timing for critical hits |
| Combo Training | Improve sprint-reset techniques |
| Tournaments | Verify critical hit mechanics |
PvE Servers
| Use Case | Benefit |
|---|---|
| Mob Farming | Optimize damage output |
| Boss Fights | Track DPS effectiveness |
| Speedrunning | Monitor combat efficiency |
Content Creators
| Use Case | Benefit |
|---|---|
| YouTube/Twitch | Visual feedback for viewers |
| Tutorials | Demonstrate critical hit mechanics |
| Challenges | Create crit-based achievements |
Statistics Tracking
What Gets Tracked
| Metric | Description | Reset Condition |
|---|---|---|
| Crit Count | Total critical hits in current streak | 2 seconds no crit |
| Combo Count | Total combo hits in current streak | 2 seconds no combo |
| Last Crit Time | Timestamp of most recent crit | On reset |
| Last Combo Time | Timestamp of most recent combo | On reset |
What Is NOT Tracked
| Not Tracked | Reason |
|---|---|
| All-time statistics | Would require database storage |
| Damage numbers | Beyond plugin scope |
| Kill/death counts | Other plugins handle this |
| Weapon types | Not relevant to hit detection |
Developer API
Accessing CombatMetrics
// Get plugin instance
CombatMetrics plugin = CombatMetrics.getInstance();
// Get the metric manager
MetricManager manager = plugin.getMetricManager();
Reading Player Data
// Get current stats
MetricData data = manager.getMetricData(player);
int crits = data.getCritCount();
int combos = data.getComboCount();
// Check if display is enabled
boolean enabled = manager.isDisplayEnabled(player);
Modifying Player Data
// Manually register hits
manager.registerCriticalHit(player);
manager.registerComboHit(player);
// Reset counters
manager.resetCounters(player);
// Toggle display
boolean newState = manager.toggleDisplay(player);
manager.setDisplayEnabled(player, true);
Custom Action Bar Updates
// Get data and update display
MetricData data = manager.getMetricData(player);
manager.updateActionBar(player, data);
// Update with highlight effect
manager.showHitWithHighlight(player, true, false); // Highlight crit
--
Compatibility
Server Software
| Software | Compatible | Notes |
|---|---|---|
| Paper 1.21.1+ | ✅ | Primary target |
| Paper 1.21.2 | ✅ | Fully supported |
| Paper 1.21.3 | ✅ | Fully supported |
| Paper 1.21.4 | ✅ | Fully supported |
| Paper 1.21.5 | ✅ | Fully supported |
| Paper 1.21.6 | ✅ | Fully supported |
| Paper 1.21.7 | ✅ | Fully supported |
| Paper 1.21.8 | ✅ | Fully supported |
| Spigot | ⚠️ | May work, untested |
| Bukkit | ❌ | Missing Adventure API |
| Folia | ⚠️ | Requires region-aware modifications |
Java Versions
| Java | Compatible |
|---|---|
| Java 21 | ✅ Required |
| Java 22+ | ✅ Should work |
| Java 17 | ❌ Too old for Paper 1.21 |
Plugin Conflicts
| Plugin Type | Compatibility |
|---|---|
| Combat plugins | ✅ Runs on MONITOR priority |
| Action bar plugins | ⚠️ May overwrite display |
| Anticheat plugins | ✅ No conflicts |
| Protection plugins | ✅ Respects cancelled events |
Installation
Step-by-Step
- Download the
CombatMetrics-1.0.0.jarfile - Stop your server
- Place the JAR in your
plugins/folder - Start your server
- Verify with
/plugins- should show green
First-Time Setup
No configuration required! The plugin works out of the box:
- Display is enabled by default for all players
- Players can toggle with
/metrics toggle - Settings automatically persist
Changelog
Version 1.0.0
- Initial release
- Critical hit detection (11 conditions)
- Combo hit detection (3 conditions)
- Action bar display with left-alignment
- Auto-reset after 2 seconds
- PDC-based persistence
- Toggle/status/reset commands
- Async timer task
- Hit highlight effects
FAQ
Q: Why doesn't it detect my critical hits?
A: Ensure your attack is fully charged (90%+) and you're falling without any blocking conditions (water, climbing, slow falling, etc.)
Q: Can both Crit and Combo trigger on the same hit?
A: Yes! If you're falling AND sprinting with a charged attack, both counters will increment.
Q: Does this work in creative mode?
A: Yes, but attack cooldown is always 1.0 in creative, so timing doesn't matter.
Q: Will this cause lag?
A: No. The plugin uses async processing and minimal memory. Tested with 100+ players.
Q: Can I customize the display colors?
A: Not in this version. Colors are hardcoded for consistency.
Q: Does it track hits on all entities?
A: Only hits on LivingEntity (mobs, players, animals, etc.)
Summary
CombatMetrics provides:
✅ Accurate vanilla-matching critical hit detection ✅ Real-time action bar display ✅ Automatic 2-second reset timers ✅ Persistent per-player preferences ✅ Performant async processing ✅ Simple toggle commands ✅ Zero configuration required ✅ Zero dependencies
Perfect for PvP servers, practice servers, and any server where players want to track their combat effectiveness!**

