All versions
2.0.5
Release
CombatGunSSS 2.0.56 months ago 109
Compatibility
Minecraft: Java Edition
1.21.x
Platforms
Bukkit
Paper
Purpur
Spigot
Changes
[2.0.5] - 2026-04-26
Added
AttachmentApplyEvent and AttachmentRemoveEvent โ Developer API
- Two new cancellable events fire when a player attaches or removes an attachment from a gun.
AttachmentApplyEventโ fired beforefitAttachment()writes the PDC key. ProvidesgetPlayer(),getGunData(),getIncoming()(attachment being fitted), andgetReplacedAttachment()(previously occupied slot, ornull). Cancellable โ cancel to block the attachment action.AttachmentRemoveEventโ fired beforeremoveAttachment()clears the PDC key. ProvidesgetPlayer(),getGunData(),getSlot(), andgetRemoved()(the attachment being stripped). Cancellable โ cancel to block the removal.AttachmentManager.fitAttachment(Player, ItemStack, GunData, String)โ new overload that fires the apply event. The no-player overload is retained for internal use.AttachmentManager.removeAttachment(Player, ItemStack, GunData, AttachmentType)โ new overload that fires the remove event.- Example use-cases: locking legendary weapons from modification, auto-returning detached attachments to the player's inventory, logging equipment changes, restricting attachments in specific regions.
DamageCalculator โ Centralised Damage Math Utility
- New
util/DamageCalculator.javaextracts all damage-pipeline calculations fromGunListener, making them independently testable and accessible to add-on plugins. - Static methods:
baseDamage(GunData, double eventMult)โ gun damage ร projectile multiplier ร event multiplier.falloffMultiplier(GunData, double dist)โ linear range-based damage reduction fromdamageFalloffStartto min floor.headshotMultiplier(GunData, boolean headshot)โ returnsheadshotMultiplieror1.0.finalDamage(GunData, double dist, boolean headshot, double eventMult)โ full pipeline in one call.isHeadshot(double hitY, double baseY, double height, boolean crouching)โ single source of truth for headshot detection, accounting for crouch state.effectiveSpread(GunData, double scopeSpread, boolean scoped, boolean ads, double moveMult)โ spread value for all fire modes.pelletSpread(double baseSpread, boolean multiPellet)โ per-pellet spread for shotguns.
- Named constants:
HEAD_ZONE_START(0.80),CROUCH_FACTOR(0.85),SHOTGUN_SPREAD_FACTOR(1.45) โ previously magic numbers scattered acrossGunListener. GunListenernow delegates all damage math and spread calculations toDamageCalculator. The privatecomputeFalloffMultiplier()method has been removed (logic moved toDamageCalculator.falloffMultiplier()).
StatsManager โ Per-Kill Detail Log (kills_by_gun_detail table)
- New SQLite table
kills_by_gun_detailadded via schema migration v3. Stores one row per kill withuuid,gun_id,headshotflag, and Unixtimestamp(ms). - Enables future features: per-weapon leaderboards, session-based kill analytics, and season resets that preserve historical totals in the detail log while zeroing the aggregate counters.
- Two covering indexes (
idx_kbgd_uuid,idx_kbgd_gun) ensure per-player and per-weapon queries stay fast as the table grows. - Schema migration runs automatically on first startup of 2.0.5 โ no manual SQL required.
GunCommand โ Season Reset and Per-Player Stats Reset
/gun statsreset <player>โ resets kills, deaths, headshots, gun kills, and detail records for a single online player. Wipes the in-memory buffer and schedules async DB deletes across all three stat tables./gun seasonreset confirmโ resets ALL players' stats (requires the literalconfirmargument as a safeguard against accidental use). Clears the in-memory buffer and truncatesplayer_stats,gun_kills, andkills_by_gun_detailin a single transaction. Prints a gold confirmation message on success.- Both commands require
combatgun.adminpermission. - Both commands fail gracefully with a clear error if
StatsManageris disabled (SQLite unavailable).
Improved
GunListener โ God Class Reduction
performShot()spread logic (previously a three-branchif/else if/elseblock) replaced with a singleDamageCalculator.effectiveSpread()call.applyEntityDamage()damage calculation (previously inline) replaced withDamageCalculator.finalDamage()andDamageCalculator.baseDamage().isHeadshot()private method now delegates entirely toDamageCalculator.isHeadshot()โ single source of truth for headshot geometry.- Removed
computeFalloffMultiplier()private method (~7 lines) โ logic now lives inDamageCalculator.
StatsManager โ Schema Version Bumped to 3
SCHEMA_VERSIONconstant updated from2to3.recordKill()now passes theheadshotflag toincrementGunKill()so both the aggregategun_killstable and the newkills_by_gun_detailtable are updated in one async task.resetStats(UUID)now also deletes fromkills_by_gun_detailin addition toplayer_statsandgun_kills.resetAllStats()truncates all three stat tables in a single transaction.
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:BSt2YZOI:2Qhu5KoM"
}
// Legacy Loom dependency
dependencies {
modImplementation "maven.modrinth:BSt2YZOI:2Qhu5KoM"
}

