Tags
Creators
Details
Licensed Apache-2.0
Published last year
Updated 7 months ago
All versions
1.2.2
Release
Zenith-Mod 1.2.2last year 54
Uploaded by
Compatibility
Minecraft: Java Edition
1.21–1.21.10
1.20.x
1.19.4
Platforms
Paper
Purpur
Changes
Zenith-Mod v1.2.2 Release Notes
Update Notification System & Critical Bug Fixes
🔔 Update Notification System
- Added: Automatic update checking for new plugin versions
- Added: Players with
zenith.update.notifypermission get notified when a new version is available - Added: Clickable green "Modrinth" link that opens the download page
- Features:
- Async version checking via Modrinth API
- Non-blocking update checks
- Clean notification message with clickable link
- Permission-based notification system (default: OP only)
- Result: Staff members are automatically notified of new versions when joining the server
🔓 Unmute System Fix
- Fixed:
active_casenow correctly set tonullafter unmute (instead of unmute case ID) - Fixed:
ip_mutedstatus now properly cleared when unmuting IP-muted players - Fixed: IPMUTE recognition (without underscore) in unmute operations
- Added: Support for both
IP_MUTEandIPMUTEpunishment types in unmute logic - Changed:
updatePlayerMuteStatusnow setsactive_casetonullinstead of unmute case ID - Result: Unmuted players have correct status flags, allowing them to be muted again if needed
⏱️ IP-Mute Duration Display Fix
- Fixed: "Unknown" or "Permanent" duration display for IP-muted players
- Fixed: Correct remaining duration calculation for
IP_MUTEandIPMUTEtypes - Changed: JSON parsing now supports both
"expiry_time"and"expiryTime"formats - Changed: Staff notifications now show accurate remaining mute time for IP-muted players
- Result: Staff see correct remaining time (e.g., "45 minutes") instead of "Unknown" or "Permanent"
🎯 Offense Counter Fix
- Fixed: Offense counting now works per template/reason instead of globally
- Fixed: Different templates (e.g., "Doxx Threats", "Cheating") are counted separately
- Changed: SQL query now filters by reason base (e.g., "Doxx Threats%") instead of all offenses
- Changed: Template-based offense tracking prevents cross-template contamination
- Result: Correct escalation levels per template (1st/2nd/3rd offense per specific reason)
🚀 Player Join Optimization & Mute Command Fix
- Fixed: "Player not found in database" error when muting freshly joined players
- Fixed: Race condition between player join and mute commands
- Changed: Intelligent player database handling on join (existing vs new players)
- Changed: Synchronous database creation for new players to prevent race conditions
- Changed: Asynchronous updates for existing players (last_seen, IP) for performance
- Added: Fallback mechanism for database errors during player join
- Result: Mute commands work immediately after player join, no more "not found" errors
What Changed?
Before:
- ❌ No automatic update notifications for staff
- ❌ Players had to manually check for new versions
- ❌
active_caseset to unmute case ID prevented re-muting players - ❌
ip_mutedstatus not cleared after unmuting IP-muted players - ❌ Staff notifications showed "Unknown" or "Permanent" for IP-muted players
- ❌ Duration calculation failed for
IP_MUTEandIPMUTEtypes - ❌ JSON parsing only checked for
"expiryTime"format - ❌ Offense counting was global across all templates
- ❌ Different templates contaminated each other's offense counts
- ❌ Players got wrong escalation levels (e.g., "2nd Offense" when it was their first)
- ❌ "Player not found in database" error when muting freshly joined players
- ❌ Race condition between player join and mute commands
- ❌ All player joins used asynchronous database operations
After:
- ✅ Automatic update notifications when joining server
- ✅ Clickable Modrinth link for easy download access
- ✅ Permission-based notification system
- ✅
active_casecorrectly set tonullafter unmute - ✅
ip_mutedstatus properly cleared after unmuting IP-muted players - ✅ Both
IP_MUTEandIPMUTEsupported in unmute operations (I dont even know why I did IP_MUTE and IPMUTE in the first place 😭) - ✅ Accurate remaining duration shown in staff notifications
- ✅ Supports both
"expiry_time"and"expiryTime"JSON formats - ✅ Correct duration calculation for all mute types
- ✅ Offense counting works per template/reason
- ✅ Each template tracks offenses independently
- ✅ Correct escalation levels per specific reason
- ✅ Mute commands work immediately after player join
- ✅ No more "Player not found in database" errors
- ✅ Intelligent player database handling (existing vs new players)
- ✅ Synchronous database creation for new players prevents race conditions
Technical Details
Update Notification System
- UpdateChecker.java: New utility class for checking Modrinth API for updates
- UpdateCheckListener.java: Event listener that checks for updates on player join
- API Integration: Fetches version list from
https://api.modrinth.com/v2/project/z-mod/version - Version Comparison: Semantic versioning comparison (MAJOR.MINOR.PATCH)
- Notification: Adventure API message with clickable link using
ClickEvent.OPEN_URL - Permission:
zenith.update.notify(default: OP only) - Thread Safety: Async operations prevent blocking server thread
Unmute System Fix
- MuteManager.unmutePlayerWithCaseId(): Now checks for
MUTE,IP_MUTE, andIPMUTEtypes - MuteManager.unmuteOfflinePlayerWithCaseId(): Same fixes for offline unmute operations
- PlayerRepository.updatePlayerMuteStatus(): Sets
active_casetonullinstead of unmute case ID - PlayerRepository.setIpMuted(): Clears
ip_mutedstatus when unmuting IP-muted players - Case ID Tracking: Original mute case ID stored in
additional_datafor audit trail - Discord Logging: Original case ID displayed in unmute embeds
IP-Mute Duration Display Fix
- MuteHandler.sendStaffNotificationForIpMutedChat(): Fixed JSON parsing for expiry time
- JSON Parsing: Supports both
"expiry_time"(underscore) and"expiryTime"(no underscore) - String Parsing: Proper extraction of
expiry_timevalue from JSON strings - Duration Calculation:
remainingSeconds = (expiryTime - currentTime) / 1000 - Format Display: Uses
DurationParser.formatDuration()for readable time display - Punishment Type Support: Recognizes both
IP_MUTEandIPMUTEtypes
Offense Counter Fix
- HistoryRepository.getOffenseCountByType(): Now filters by reason base instead of all offenses
- Template Integration: Loads BanTemplate to get correct default reason for filtering
- SQL Query:
reason LIKE baseReason + "%"instead ofreason LIKE "%(%" - Cross-Template Prevention: Different templates (e.g., "Doxx Threats", "Cheating") counted separately
- Escalation Accuracy: Each template maintains independent offense counts
- Backward Compatibility: Existing history entries remain unchanged
Player Join Optimization & Mute Command Fix
- PlayerJoinHandler.continueNormalJoinProcess(): Intelligent player database handling
- PlayerRepository.updatePlayerLastSeenAndIp(): New method for updating existing players
- Synchronous Database Creation: New players created synchronously to prevent race conditions
- Asynchronous Updates: Existing players updated asynchronously for performance
- MuteCommand.handleOfflineManualMute(): Online player detection prevents database lookup errors
- Race Condition Prevention: Eliminates timing issues between join and mute commands
- Fallback Mechanism: Graceful error handling with async fallback
Compatibility
Update Notification System
- ✅ Fully backward compatible
- ✅ No configuration required
- ✅ Permission-based access control
- ✅ Works with all server types (Paper/Purpur)
- ✅ Graceful handling of API failures
Unmute System
- ✅ Fully backward compatible with existing unmutes
- ✅ No database migration required
- ✅ Works with all mute types (MUTE, IP_MUTE, IPMUTE)
- ✅ Complete audit trail maintained
- ✅ Discord logging shows original case ID
IP-Mute Duration Display
- ✅ Fully backward compatible
- ✅ Supports both JSON formats for expiry time
- ✅ Handles missing or malformed JSON gracefully
- ✅ Accurate duration calculation for all mute scenarios
- ✅ Staff notifications work for all mute types
Offense Counter Fix
- ✅ Fully backward compatible with existing history entries
- ✅ No database migration required
- ✅ Works with all ban/mute templates
- ✅ Template-based offense tracking
- ✅ Correct escalation levels per reason
Player Join Optimization & Mute Command Fix
- ✅ Fully backward compatible with existing player data
- ✅ No database migration required
- ✅ Works with all server types (Paper/Purpur)
- ✅ Minimal performance impact (only new players affected)
- ✅ Graceful fallback for database errors
Changelog Summary
Added
- 🔔 Update notification system for staff members
- 🔔 Permission
zenith.update.notifyfor update notifications - 🔗 Clickable Modrinth download link in notifications
- 🔗 Async version checking via Modrinth API
Fixed
- 🔓
active_casenow correctly set tonullafter unmute - 🔓
ip_mutedstatus now properly cleared after unmuting IP-muted players - 🔓 Both
IP_MUTEandIPMUTEsupported in unmute operations - ⏱️ Accurate duration display for IP-muted players in staff notifications
- ⏱️ JSON parsing for
"expiry_time"format (with underscore) - ⏱️ Duration calculation for all IP-mute types
- 🎯 Offense counting now works per template instead of globally
- 🎯 Different templates tracked independently (no cross-contamination)
- 🎯 Correct escalation levels per specific reason
- 🚀 "Player not found in database" error when muting freshly joined players
- 🚀 Race condition between player join and mute commands
Changed
- 🔔 Update checks are async and non-blocking
- 🔓 Unmute operations now clear all mute flags correctly
- ⏱️ Duration display uses proper JSON parsing for all formats
- 🎯 SQL queries now filter by reason base instead of all offenses
- 🎯 Template-based offense tracking prevents cross-contamination
- 🚀 Player join handling now uses intelligent database operations
- 🚀 New players created synchronously, existing players updated asynchronously
- 🚀 Mute command detects online players to prevent database lookup errors
Version: 1.2.2
Released: January 17, 2025
Platform: Paper 1.21.4+
Projects on Modrinth are automatically available through a Maven repository for use with JVM build tools such as Gradle. To learn more about the Modrinth Maven API, click here.
Note: When available, you should use the creator's maven repo instead as it will have transitive dependency information that the Modrinth Maven API does not. You may also end up with duplicate dependencies if you use a mix of Modrinth and non-Modrinth Maven repositories for your dependencies, because the group identifier will be different when served through the Modrinth Maven API.
Maven coordinates:
Version ID:
build.gradle:
repositories {
exclusiveContent {
forRepository {
maven {
name = "Modrinth"
url = "https://api.modrinth.com/maven"
}
}
// forRepositories(fg.repository) // Uncomment when using ForgeGradle
filter {
includeGroup "maven.modrinth"
}
}
}
// Standard Gradle dependency
dependencies {
implementation "maven.modrinth:TY8FR9Ml:UKSbjQ5G"
}
// Legacy Loom dependency
dependencies {
modImplementation "maven.modrinth:TY8FR9Ml:UKSbjQ5G"
}

