All versions
๐ด
๐ด
๐ด
๐ด
๐ก
๐ก
๐ก
๐ก
2.0.3
Release
CombatGunSSS 2.0.36 months ago 65
Compatibility
Minecraft: Java Edition
1.21.x
Platforms
Paper
Purpur
Changes
[2.0.3] - 2026-04-18
Fixed
๐ด AmmoPouchManager.unpackPouch() โ Pouch lost when inventory is full (Critical)
- Root cause: When partially unpacking (only a few slots left in inventory), the code always called
pouch.setAmount(0)regardless of how many bullets were actually transferred. The entire pouch was destroyed even if bullets remained inside. - Fix: If
remaining > 0(unpack not completed), update the PDCpouch_quantityto the remaining amount and refresh the lore instead of destroying the pouch. Only callsetAmount(0)when all bullets have been successfully transferred.
๐ด ReloadManager โ Reload task running every 1 tick causing high CPU usage (Critical)
- Root cause:
runTaskTimer(plugin, 0L, 1L)scheduled 20 times per second for every player reloading. With 10 players reloading simultaneously, this resulted in 200 task calls per second just for the progress bar. - Fix: Changed to
runTaskTimer(plugin, 0L, 2L)and adjustedtotalTicks = reloadTime * 10.0so reload duration remains unchanged. This reduces reload system CPU load by approximately 50%.
๐ด GunListener.isHeadshot() โ Inaccurate headshots while player is crouching (Critical)
- Root cause: Used fixed
entity.getHeight() * 0.8without accounting for crouching players (hitbox shrinks to ~1.5 blocks instead of 1.8). - Fix: Detect
player.isSneaking()and multiplyheight *= 0.85before calculating headY threshold. Headshot detection is now accurate for both standing and crouching states.
๐ด CraftingManager.craftFromStation() โ No rollback when crafting fails (Critical)
- Root cause:
consumeIngredients()ran beforecreateResultItem(). IfcreateResultItem()returnednull(invalid gun ID, config error, etc.), ingredients were consumed but no item was given โ permanent item loss. - Fix: Snapshot all input slots before consuming. If
createResultItem()returnsnull, restore ingredients from the snapshot.
๐ก GunListener.applyRecoil() โ Potential NPE when AntiCheatHook is disabled (Medium)
- Root cause:
if (hm2 != null) hm2.getAntiCheatHook().exempt(player)โ checkedhm2but notgetAntiCheatHook(). If the hook was disabled,getAntiCheatHook()could return an uninitialized instance. - Fix: Added full guard:
hm2 != null && hm2.getAntiCheatHook() != null && hm2.getAntiCheatHook().isActive()before callingexempt().
๐ก BleedingManager โ Incorrect damage during server lag (Medium)
- Root cause: Task used
elapsed += 20to count ticks, but when the server lagged (>50ms per tick), actual damage was lower than the configureddamage_per_second. - Fix: Switched to
System.currentTimeMillis()for real-time tracking.lastDamageTimeis now updated only when damage is actually applied, ensuring exactly 1 second between damage ticks regardless of server lag.
๐ก CraftingManager.consumeIngredients() โ Incorrect null-check order (Medium)
- Root cause:
identifyIngredient(item)was called before checkingitem == null, causing potential NPE with empty inventory slots in some edge cases. - Fix: Moved
if (item == null || item.getType().isAir()) continue;before callingidentifyIngredient().
๐ก GunListener.onItemHeldChange() โ Race condition when switching slots rapidly (Medium)
- Root cause: Task with 0-tick delay read
getItemInMainHand()โ if the player switched slots again before the task ran, it would process the wrong slot's item. - Fix: Store
newSlot = event.getNewSlot()before scheduling the task. Inside the task, checkplayer.getInventory().getHeldItemSlot() != newSlotand abort if the player has switched slots again.
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:L5QuCexG"
}
// Legacy Loom dependency
dependencies {
modImplementation "maven.modrinth:BSt2YZOI:L5QuCexG"
}

