Unofficial site, not affiliated with modrinth.com.What is this?
Плагины/CombatGunSSS
CombatGunSSS

CombatGunSSS

Adds 45 unique guns to Minecraft, each with custom damage, recoil, fire rate, and reload mechanics, enhancing combat with balanced gameplay, multiple weapon types, and flexible customization for varied playstyles

226
3

CombatGunSSS 2.0.5

release26 апреля 2026 г.

[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 before fitAttachment() writes the PDC key. Provides getPlayer(), getGunData(), getIncoming() (attachment being fitted), and getReplacedAttachment() (previously occupied slot, or null). Cancellable — cancel to block the attachment action.
  • AttachmentRemoveEvent — fired before removeAttachment() clears the PDC key. Provides getPlayer(), getGunData(), getSlot(), and getRemoved() (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.java extracts all damage-pipeline calculations from GunListener, 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 from damageFalloffStart to min floor.
    • headshotMultiplier(GunData, boolean headshot) — returns headshotMultiplier or 1.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 across GunListener.
  • GunListener now delegates all damage math and spread calculations to DamageCalculator. The private computeFalloffMultiplier() method has been removed (logic moved to DamageCalculator.falloffMultiplier()).

StatsManager — Per-Kill Detail Log (kills_by_gun_detail table)

  • New SQLite table kills_by_gun_detail added via schema migration v3. Stores one row per kill with uuid, gun_id, headshot flag, and Unix timestamp (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 literal confirm argument as a safeguard against accidental use). Clears the in-memory buffer and truncates player_stats, gun_kills, and kills_by_gun_detail in a single transaction. Prints a gold confirmation message on success.
  • Both commands require combatgun.admin permission.
  • Both commands fail gracefully with a clear error if StatsManager is disabled (SQLite unavailable).

Improved

GunListener — God Class Reduction

  • performShot() spread logic (previously a three-branch if/else if/else block) replaced with a single DamageCalculator.effectiveSpread() call.
  • applyEntityDamage() damage calculation (previously inline) replaced with DamageCalculator.finalDamage() and DamageCalculator.baseDamage().
  • isHeadshot() private method now delegates entirely to DamageCalculator.isHeadshot() — single source of truth for headshot geometry.
  • Removed computeFalloffMultiplier() private method (~7 lines) — logic now lives in DamageCalculator.

StatsManager — Schema Version Bumped to 3

  • SCHEMA_VERSION constant updated from 2 to 3.
  • recordKill() now passes the headshot flag to incrementGunKill() so both the aggregate gun_kills table and the new kills_by_gun_detail table are updated in one async task.
  • resetStats(UUID) now also deletes from kills_by_gun_detail in addition to player_stats and gun_kills.
  • resetAllStats() truncates all three stat tables in a single transaction.

CombatGunSSS 2.0.3

release18 апреля 2026 г.

[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 PDC pouch_quantity to the remaining amount and refresh the lore instead of destroying the pouch. Only call setAmount(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 adjusted totalTicks = reloadTime * 10.0 so 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.8 without accounting for crouching players (hitbox shrinks to ~1.5 blocks instead of 1.8).
  • Fix: Detect player.isSneaking() and multiply height *= 0.85 before 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 before createResultItem(). If createResultItem() returned null (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() returns null, restore ingredients from the snapshot.

🟡 GunListener.applyRecoil() — Potential NPE when AntiCheatHook is disabled (Medium)

  • Root cause: if (hm2 != null) hm2.getAntiCheatHook().exempt(player) — checked hm2 but not getAntiCheatHook(). If the hook was disabled, getAntiCheatHook() could return an uninitialized instance.
  • Fix: Added full guard: hm2 != null && hm2.getAntiCheatHook() != null && hm2.getAntiCheatHook().isActive() before calling exempt().

🟡 BleedingManager — Incorrect damage during server lag (Medium)

  • Root cause: Task used elapsed += 20 to count ticks, but when the server lagged (>50ms per tick), actual damage was lower than the configured damage_per_second.
  • Fix: Switched to System.currentTimeMillis() for real-time tracking. lastDamageTime is 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 checking item == null, causing potential NPE with empty inventory slots in some edge cases.
  • Fix: Moved if (item == null || item.getType().isAir()) continue; before calling identifyIngredient().

🟡 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, check player.getInventory().getHeldItemSlot() != newSlot and abort if the player has switched slots again.

CombatGunSSS 2.0.2

release14 апреля 2026 г.

[2.0.2] - 2026-04-14

Fixed

NullPointerException: HudManager.sendNow() when shooting any gun

  • Root cause: GunListener cached plugin.getHudManager() into a final HudManager hudManager field inside its constructor. However, GunListener is instantiated in registerListeners() which runs before startServices() where HudManager is created. The field was always null at the time of assignment.
  • Fix: Removed the cached hudManager field entirely. All two call-sites now use plugin.getHudManager() inline with a null-guard: if (plugin.getHudManager() != null) plugin.getHudManager().sendNow(player). This makes the call lazy — it resolves the reference at the moment of use rather than at construction time, so startup order no longer matters.

CombatGunSSS 2.0.1

release14 апреля 2026 г.

[2.0.1] - 2026-04-14

Fixed

Plugin crash on startup (onEnable exception → plugin disabled)

  • Root cause: Any uncaught exception inside onEnable() caused Bukkit to call disablePlugin() immediately, leaving the plugin in a broken state where commands responded with "plugin is disabled" instead of a useful error message.
  • Fix: Refactored onEnable() into isolated private methods (initManagers(), registerListeners(), startServices(), registerCommands()). Each step is now wrapped in a top-level try-catch. A detailed stack trace is printed to console before the plugin gracefully self-disables — making the actual root cause visible instead of a cryptic command error.

StatsManager (SQLite) failure no longer kills the plugin

  • statsManager.init() is now wrapped in its own try-catch. If SQLite initialisation fails (missing driver, file permission error, corrupted DB), the plugin logs a warning, sets statsManager = null, and continues loading. All stats-dependent features (/gun stats, /gun leaderboard, PAPI %combatgun_kills% etc.) degrade gracefully with a user-friendly error message.

HookManager failure no longer kills the plugin

  • hookManager.initAll() is wrapped in a try-catch. If any soft-depend integration throws an unexpected exception, the hook manager is set to null and the plugin runs without integrations rather than crashing entirely.

Null pointer exceptions when hookManager or statsManager are null

  • GunListener.isAllowed() — WorldGuard check now guards with hm != null before calling canShoot().
  • GunListener.applyRecoil() — AntiCheat exempt call guarded with hm2 != null.
  • GunCommand.handleBuy() — Vault access guarded; returns a friendly error if hook manager is unavailable.
  • GunCommand.handleStats() / handleLeaderboard() — Guarded with statsManager != null check; returns a friendly error if stats are disabled.
  • EntityDeathListener — Stats recording guarded with statsManager != null.

Material.GREY_DYE compile error

  • ThrowableManager used the pre-1.13 material name GREY_DYE which no longer exists. Corrected to GRAY_DYE (American English naming introduced in the 1.13 flattening).

Changed

  • onEnable() restructured into initManagers(), registerListeners(), startServices(), registerCommands(), scheduleCleanup(), printStartupBanner() for clarity and fault isolation.
  • onDisable() wraps each cleanup call in its own try-catch so a failure in one manager never prevents the others from shutting down cleanly.
  • Startup banner now correctly reads version from plugin.yml at runtime via getDescription().getVersion() — no hardcoded version strings in Java code.

CombatGunSSS 2.0.0

release13 апреля 2026 г.

[2.0.0] - 2026-04-12

Added

Weapon Attachment System

  • Four attachment types with stackable stat modifiers:
    • SILENCER — reduces sound radius (config: sound_radius_multiplier) with optional damage penalty.
    • EXTENDED_MAG — adds flat magazine capacity (config: magazine_bonus).
    • GRIP — reduces pitch recoil and bullet spread (config: recoil_pitch_multiplier, spread_multiplier).
    • SCOPE — enables precision scope spread at runtime, even on guns where scopeable: false.
  • Each gun holds at most one attachment per slot. Attaching a second of the same type replaces the first.
  • Attachments persist on the gun item via PersistentDataContainer keys (combatgun:attach_silencer, etc.).
  • Commands: /gun attach <id>, /gun detach <TYPE>, /gun attachments (inspect held gun).
  • Config: Defined under combatgun.attachments.<id> in config.yml. Five built-in definitions included (silencer, extended_mag_ar, extended_mag_smg, tactical_grip, acog_scope).
  • AttachmentManager exposes stat modifier helpers used at shoot time: soundMultiplier(), damageMultiplier(), magBonus(), spreadMultiplier(), recoilPitchMultiplier(), hasScopeAttachment().

Throwable Items (Grenades)

  • Three throwable types, all thrown as Snowball projectiles and detonated on ProjectileHitEvent or after fuse:
    • FRAG — Creates a visual explosion and deals falloff damage to nearby entities.
    • SMOKE — Spawns a timed smoke particle cloud (campfire smoke particles for 10 seconds by default).
    • FLASHBANG — Applies Blindness and Slowness (simulated deafness) to nearby players, scaled by distance.
  • Command: /gun givethrowable <id> [player].
  • Config: Defined under combatgun.throwables.<id> with full control over fuse, radius, damage, duration, and effect ticks. Three built-in throwables included.
  • ThrowableListener handles right-click throw and projectile landing. Registered as a separate listener from GunListener.
  • Projectiles are tracked in ThrowableManager.liveProjectiles and auto-detonate after fuse_ticks if they don't land.

Kill Statistics & Leaderboard

  • New StatsManager backed by SQLite (plugins/CombatGunSSS/stats.db). No external database required.
  • Tracks per-player: kills, deaths, headshots, and per-gun kill counts.
  • Write buffer flushes to DB every 5 minutes and on plugin disable — minimises disk writes while keeping data safe.
  • Commands: /gun stats [player] (view stats), /gun leaderboard (top 10 by kills).
  • New PlaceholderAPI placeholders: %combatgun_kills%, %combatgun_deaths%, %combatgun_headshots%, %combatgun_kd%.
  • EntityDeathListener now calls StatsManager.recordKill() and recordDeath() on every gun kill.
  • SQLite JDBC shaded into the jar via maven-shade-plugin with relocation to dev.duong2012g.combatgun.libs.sqlite — no external jar needed.

Changed

  • CombatGunSSSPlugin — registers AttachmentManager, ThrowableManager, StatsManager; registers ThrowableListener; onDisable() calls statsManager.shutdown(); startup log prints attachment/throwable counts and stats DB status.
  • GunCommand — added attach, detach, attachments, givethrowable, stats, leaderboard to SUB_COMMANDS, switch, tab completion, and help.
  • PlaceholderHook — added kills, deaths, headshots, kd placeholders (total 12 placeholders now).
  • EntityDeathListener — records kill/death to StatsManager on every confirmed gun kill.
  • plugin.yml — version bumped to 2.0.0.
  • pom.xml — version bumped to 2.0.0; added sqlite-jdbc 3.45.1.0 as compile dependency; added maven-shade-plugin to shade and relocate SQLite.
  • config.yml — added combatgun.attachments and combatgun.throwables sections with default definitions.

Совместимость

Minecraft: Java Edition

1.21.x

Платформы

Поддерживаемые окружения

Сервер

Создатели

Детали

Лицензия:Apache-2.0
Опубликован:1 месяц назад
Обновлён:1 неделю назад
Главная