[Perf] Consolidate scheduled tasks into single global tick#317
Closed
Mere-Solace wants to merge 73 commits into
Closed
[Perf] Consolidate scheduled tasks into single global tick#317Mere-Solace wants to merge 73 commits into
Mere-Solace wants to merge 73 commits into
Conversation
* Implemented ActionContextPair, which allows multiple actions under different contexts for the same input path * Hide successor nodes for shared prefixes when terminals have restrictive hidden predicates * Fixed broken input activations and other glitches (+ fixed umbral blade lunge glitched movement) * spotlessApply
…ribute was being pulled in the drop event)
* Add: NonMovable item class hierarchy (SpecialItem / NonMovableItem / SlotAnchoredItem) Closes #199 - Add `SpecialItem`, `NonMovableItem`, `SlotAnchoredItem`, `SoulLinkItem` in `btm.sword.system.item.special` - Add `SPECIAL_ITEM_KEY`, `NON_MOVABLE_KEY`, `SHIELD_KEY`, `CHESTPLATE_KEY` to `KeyRegistry` - Convert Soul Link (`SoulLinkItem`), menu button, shield, and netherite chestplate to `SlotAnchoredItem` - Replace ad-hoc `inventoryUpkeep()` slot checks with `isSatisfied()` / `restore()` calls - Replace hardcoded slot and key guards in `handleInventoryInput()` and `onPlayerDropEvent()` with `NonMovableItem.isNonMovable()` * Docs: Update UmbralBlade LodgedState documentation for interactable registration
* Finishes #147. Fixed a few extra umbral state transition issues + umbral blade impalement logic. * Chore: Apply spotless formatting
…ting - ChatInputCapture: intercepts one async chat message per player, dispatches callback on main thread - DevMenu: op-only debug flag toggles (verbose, combat/movement/config logging, special item checks) - ConfigMenu: section browser grouping all Config.ENTRIES by top-level YAML key - ConfigSectionMenu: paged editor for entries within a single section - ConfigEntryItem: in-place editing for Boolean/Integer/Long/Double/Float; chat-prompt for numerics (Shift+L); EnumSelectionMenu for all enum types; typed r,g,b for Color/TextColor - EnumSelectionMenu: paged enum browser; SoundType supports right-click preview; Material uses itself as display item - Config.forceInitializeAll(): reflection-based eager initialization of all nested Config classes at startup so all sections appear in the menu immediately - ConfigManager: setValue handles Float→double, Color/TextColor→hex string, Enum→name() for correct YAML round-trip
…materials - saveToProject: use getAbsoluteFile() before walking up to build.gradle so relative data folder paths resolve correctly on Windows - EnumSelectionMenu: SoundType shows prefix category browser first (AMBIENT/BLOCK/ENTITY/etc with themed materials), then filtered value list per prefix; back button returns to prefix page - Config.Combat: 20 new ConfigEntry fields for defaultMobHit, grabHit, umbralItemDisplayAttack, punch hit packets; fix duplicate path bug on ATTACK_CLASS_HIT_SOULFIRE - Prefab.Attacks: all four hardcoded HitValuePackets now read from Config.Combat - ConfigMenu: replace rotating SECTION_MATERIALS array with explicit Map<String,Material> keyed by section name
- CombatProfile.reloadFromConfig(): re-reads Config.Entity fields at runtime - EntityAspects.reloadFromProfile(): applies updated profile to live Resources/Aspects, restarts regen tasks - DevMenu: Reload Combat Profile button (RECOVERY_COMPASS) applies both instantly - DevStatEditorMenu: op-only menu to edit all 12 AspectType base values / regen params live via chat input; opened from CharacterMenu dev button - EnumSelectionMenu: ITEM_ sounds now match item materials; BLOCK_ sounds require isItem() to avoid non-obtainable materials (fixes BAMBOO_SAPLING crash); ITEM_ and all other prefixes get smart material resolution; window titles now prepend entry.path so you always know what you're editing
#196, #197, #202) (#217) * Add: Mob ability system with mobile PreAttack wind-up (#196, #197, #202) - MobAbility interface + AbilityCategory enum (MELEE/RANGED) for typed ability dispatch; cooldown map tracked per-ability on Hostile - MobSlashAbility: picks SLASH1/2/3 randomly, runs MobSweepAttack with defaultMobHit (not basicAttack) - MobThrowAbility: launches off-hand item as DroppedItem with parabolic arc - MobSweepAttack: extends SweepAttack, overrides hit() to use defaultMobHit - PreAttackRetreatGoal: RANGED wind-up movement, recomputes backoff each tick - PreAttackState: selects ability on enter, registers ApproachGoal (MELEE) or PreAttackRetreatGoal (RANGED) so mob moves during the telegraph instead of stopping; removes all MOVE+LOOK goals on exit - AttackState: fires pendingAbility immediately on entry — no charge, no distance gate; incapacitation guard prevents execution while grabbed - HostileStateMachine: transition #8 adds !isIncapacitated() guard; transition #13 (target escape mid-charge) removed as obsolete - SwordEntity: onGrabbed()/onReleased() lifecycle hooks (public) - Combatant: wires onGrabbed/onReleased in onGrab, onGrabLetGo, onGrabThrow - Hostile: overrides onGrabbed (setAware false, remove MOVE goals) and onReleased (setAware true) for grab incapacitation - Config: MOB_SLASH_COOLDOWN_TICKS (20), MOB_THROW_COOLDOWN_TICKS (60), MOB_THROW_ARC_HEIGHT (0.4) + matching config.yaml entries - README: updated PreAttack/Attack sections, removed #13, added MobAbility system docs, grab incapacitation section, updated goal table * Add: Mob ability system with VisualProjectile refactor and throw fixes (#196, #197, #202) - Extract VisualProjectile from ThrownItem: pure physics + display base class with event hooks - Add Projectile (headless standalone physics) and ProjectileManager (single tick loop) - ThrownItem now extends VisualProjectile; hook methods resolve origin/basis/dir from thrower - ThrowAction: add throwReady(Combatant, ItemStack) overload for mob AI item injection - MobThrowAbility: fix Bug 1 (wrong hand), Bug 2 (arc direction ignored), guard double-execute - PreAttackState: retreat for ranged abilities, approach for melee; play pre-attack sound - Add WorldListener to cancel block placement during testing - Add PRE_ATTACK sound prefab and config entries
…gle, search, menu click-open - CreativeInventoryMenu: paged browser of all modern materials with chat-based search filter - DevMenu: wooden axe + wither skeleton egg give buttons, block placing toggle, creative inv button - Config.World.BLOCK_INTERACTION_ALLOW_BLOCK_PLACING: block placing and item consume no longer deplete items - Clicking the main menu button inside the inventory now opens the menu - Shift-right drop in inventory now guards against non-movable/empty items
…ers README - Add ProtocolLib 5.3.0 as compileOnly dep and hard server dependency in paper-plugin.yml (reserved for future packet-level work; see listeners/README.md and issue #219) - Add Config.Movement.DASH_DOWNWARD_FLAT_CHECK_MULTIPLIER (default 3.0) for tuning the downward flat-check threshold in Dash - Fix: opening any menu via PlayerMenuManager now clears the cursor item first, preventing the menu button from getting stuck on the player's cursor - Fix: clicking the main menu button while inside an inventory now opens the menu correctly (check reordered before null-guard in SwordPlayer) - Add listeners/README.md documenting the ProtocolLib block-place attempt and implementation notes for revisiting
* Add: Umbral Blade expansion — bugs #205 #179, features #181 #174 #176 Stage 1 (#205): InactiveState hides display (viewRange=0) on enter, restores on exit, fixing spectator-mode head glitch. Stage 2 (#179): RecallingState maxIterations reduced 500→80 (~8s max recall); added onTick fallback STANDBY request for early task cancellation; added LungingState→RecallingState on STANDBY for mid-lunge dash-grab. Stage 3 (#181): WaitingState rewritten with entry-time tracking and distance/timeout auto-recall; add WAITING to BladeRequest; new StandbyState→WaitingState transition; full WaitingState transition set (RECALL, STANDBY, LUNGE, ATTACK_QUICK, ATTACK_HEAVY); hoverBlade() action bound to DROP+SWAP (soulLinkState); config: WAITING_TIMEOUT_MS=8000, WAITING_MAX_DISTANCE=20. Stage 4 (#174): ReclaimType enum (NONE/OVERHEAD_SLAM/AERIAL_SPIKE) on UmbralBlade; onGrab branches on isDashing()+isOnGround() to set reclaimType and request appropriate attack; AttackingQuickState dispatches OVERHEAD_SLAM with SF-gain-on-hit callback; AttackingHeavyState dispatches AERIAL_SPIKE similarly; both reset reclaimType on exit; OVERHEAD_SLAM/AERIAL_SPIKE added to AttackType enum. NOTE: spinning-slash SWAP+SWAP+LEFT variant pending user decision (see plan tradeoff note). Stage 5 (#176): CHANNELING added to ActivationContext; channelInterrupted flag on SwordPlayer; SwordEntity.hit() sets channelInterrupted when target is channeling; channel() in UmbralBladeAction gates on WieldState+SF≥50, locks velocity for 2s, heals on completion or cancels on damage; RIGHT+RIGHT_HOLD (umbralState) binds channel; config: CHANNEL_SOULFIRE_COST=50, CHANNEL_HEAL_AMOUNT=1, CHANNEL_DURATION_MS=2000. Stage 6 (#143) deferred — requires stages 1-3 tested and stable first. * Fix: Fully functional healing system * Add: Per-state blade glow color #229 Glow color is now set centrally in UmbralStateMachine.setState() via a state class -> Config.SwordColor lookup, replacing scattered setGlowing() calls in each state's onEnter/onExit. Six new SwordColor config entries added (standby, attack_quick, lunge, lodged, grab_impale, recall). * Fix: Umbral blade systems * Refactor: Dash logic cleanup + game feel improvements * Fix: Umbral blade & dashing logic fixes * Add: Reclaim attack system — circular slash, DrawUtil.circle(), wield-state input routing - Add ReclaimType.CIRCULAR_SLASH / FORWARD_RUSH enum variants replacing OVERHEAD_SLAM / AERIAL_SPIKE - Add setReclaimType(type, durationMs) with auto-reset timer on UmbralBlade - Trigger CIRCULAR_SLASH reclaim when grabbing blade from WaitingState - Add wieldedUmbralBladeAttack() dispatching by reclaim type, wired into combo input tree - Add DrawUtil.circle() for oriented ring particle patterns using Basis - Add ParticleWrapper.displayAll() batch helper - Add SwordEntity.getCurrentEyeDirectionBasis() / getCurrentBodyDirectionBasis() convenience accessors * Fix: gradle build fixes for GitHUb CI/CD tasks
* Refactor: Generalize AttackProfile — decouple sweep path from Bézier via AttackShape #237 - Add AttackShape interface: resolve(Basis, double) → Function<Double, Vector> - Add BezierShape: local-space and world-space factory methods, moves adjustToBasis logic out of Attack - AttackProfile.controlVectors() replaced by shape() - AttackType: stores AttackShape, accepts any shape impl via new constructors, keeps controlVectors() helper for lunge states - GeneratedAttackProfile: wraps ControlVectors in BezierShape.worldSpace(), removes instanceof coupling in Attack - Attack: drops controlVectors field, generateBezierFunction() → generatePathFunction() delegates to shape - README updated to reflect new extension model * Add: ArcShape and ConeShape AttackShape implementations #237 - ArcShape: sweeps a circular arc in the attacker's horizontal plane. Parameters: radius, startAngle, endAngle (radians, 0=forward), height. Full 360 circle when endAngle - startAngle = 2pi. Matches DrawUtil.circle convention. - ConeShape: sweeps along the rim of a cone aligned to the attacker's forward axis. Parameters: halfAngle (polar offset), range, startSweepAngle, endSweepAngle. ConeShape.symmetric() factory for left/right symmetric fan attacks. - README: document ArcShape, ConeShape, and AOE/sphere extension pattern * Refactor: Move shape classes to style/shape package, wire ArcShape into AttackType #237 * Add: Config entries for hardcoded UmbralBlade/combat values; relabel TODOs to #240/#241 #237 * Refactor: Wire hardcoded values to Config entries in UmbralBlade, AttackType, UmbralBladeAction #237 * Add: Config entries for Dash, Attack, InputRegistrar hardcoded values; wire all to Config #237 * Add: Track AttackType control vector config work as #242 #237
Introduces ImpactType enum (IMPALE/KNOCKBACK) stored as a PDC key on ItemStacks. ThrownItem.onHit() now reads the tag instead of checking material name suffixes. The prefab sword is tagged with IMPALE.
Aligns static final HitValuePacket field names with Java constants convention. Updates all call sites across attack, mob, and listener classes.
Adds three anchored storage buttons (Currency/Material/Quest) in the column above the main menu hotbar slot. Each button has a config-backed material supplier, TEXT_COOL display name, and a per-player lore supplier showing live stats (Steel Credits balance, material slots filled/total). Adds Config.Materials section, loadMaterial helper, STORAGE_BUTTON_KEY, steelCredits/materialSlotsUsed fields on SwordPlayer, and a dev menu button to hot-reload all anchored inventory buttons.
* Fix: Config-drive AttackingHeavyState TODOs and extend CreativeInventoryMenu row * Feat: Make AttackType control vectors config-driven via Supplier<Vector> (#242) - ControlVectors: converted from record to class; stores Supplier<Vector> for each of the four control points. Two constructors accept plain Vectors (eagerly captured) or Suppliers (resolved lazily at attack time). - Config: added loadVector() utility (reads {x,y,z} sub-section) and new Config.AttackCurves class with 76 Vector entries for all 19 AttackType curves, all loaded from the new attack_curves YAML section. - AttackType: replaced every hardcoded Vector literal with a supplier referencing Config.AttackCurves, so /sword reload propagates curve changes without a restart. DEFAULT uses Config.Direction method refs. - config.yaml: added attack_curves section with all 76 default vectors. * Feat: Add Vector support to ConfigEntryItem and ConfigManager (#242) - ConfigEntryItem: Vector entries now display x/y/z in the config menu and accept chat input in "x y z" format via ChatInputCapture. - ConfigManager.setValue: stores Vector as an {x,y,z} YAML sub-section matching the format expected by Config.loadVector(). * Update: Tweak Vector item icon and note ConfigMenu section materials
- ConfigMenu: global search via ChatInputCapture opens filtered ConfigSectionMenu - ConfigSectionMenu: per-section filter with active state indicator and shift-click to clear - EnumSelectionMenu: filter support on both prefix list and value list; use Registry.MATERIAL to exclude legacy/non-item Materials - Menu: add WALL separator item (light blue pane) - DevMenu: replace '#' column separator with WALL item - PlayerListener: guard drop event to only fire when default inventory is open - config.yaml: update a few default values
…, trash clear (#254) * Add: Main menu scene and camera animation pipeline (#233) Introduces the btm.sword.system.scene package with CameraController abstract base (single-owner enforcement via SwordPlayer field), GentleDriftCameraController for the main menu scene (sinusoidal bob + yaw drift, HudDisplayGroup displays), BezierCameraController for cutscenes (follows CameraPath over configurable tick duration), SceneManager (music loop + scene-viewer tracking), and supporting utilities. Hooks into SwordPlayer.onSpawn, InputListener Shift gate, and PlayerListener forced-spectator-exit. Config.Scene added with all defaults. AvatarDisplay stub included. * Add: Packet-driven camera system (ClientboundSetCameraPacket) Introduces PacketAdapter (NMS reflection layer), CameraSession (active attachment state), and CameraService (static attach/detach API). Refactors BezierCameraController and GentleDriftCameraController to use CameraService.attach() instead of spectator-mode targeting — player stays in their original game mode. Both controllers retain a spectator fallback if PacketAdapter reflection fails at runtime. * Fix: Switch PacketAdapter to ProtocolLib; pin Gradle daemon to Java 21 Replaces NMS reflection in PacketAdapter with ProtocolLib's PacketContainer API (PacketType.Play.Server.CAMERA, getIntegers().write). Swaps compileOnly fileTree for net.dmulloy2:ProtocolLib:5.4.0 from Maven Central. Pins org.gradle.java.home to JDK 21 in gradle.properties so Gradle 8.8 runs under Java 21 regardless of the system JAVA_HOME. * Refactor: Make ParticleWrapper fields supplier-based for runtime configurability (#234) Replace fixed-value fields with Supplier<T> equivalents so values are resolved at display time, enabling config hot-reload and runtime-driven particle behavior. Introduces fluent with*() methods (withSpeed, withOptions, withTransition, withBlockData) to avoid Java type-erasure clashes with generic overloads. All existing call sites updated mechanically — no behavior change. * Add: Config.Particles section and particles menu for hot-reloadable particle tuning Adds Config.Particles with type (Particle enum), count, and speed entries for all 18 gameplay Prefab.Particles constants. Wires Prefab suppliers to config fields so values resolve at runtime and respond to /sword reload. Adds EnumSelectionMenu support for Particle enum with keyword-based icon resolution (FLAME → flint_and_steel, CRIT → diamond_sword, etc.). Adds Config.Menu.PARTICLES_ICON and registers the "particles" section in ConfigMenu so it appears as a browsable section in the config GUI. * Refactor: Extract debug toggles from DevMenu into TogglesMenu submenu Move all 10 boolean toggle items out of DevMenu into a dedicated TogglesMenu, and lift the shared toggle() helper up to the Menu base class. * Add: DEU/BDE animation system and scene refactor Introduces DEUAnimationController, StaticSceneController, and a full animation registry backed by animations.yml. Adds AnimationBrowserMenu, DEUBDEMenu, and DeuGroupBrowserMenu for in-game animation browsing. Removes legacy SceneManager, AvatarDisplay, HudDisplayGroup, and GentleDriftCameraController in favour of the new controller model. Renames SoundType → SwordSoundType to avoid collision with the Bukkit API. Adds packet-level MovementListener for cutscene input handling. * Add: Scene overlay system, animation config picker, and ChatInputCapture fix - Add enterSceneOverlay/exitSceneOverlay to SwordPlayer: clears inventory, fills with non-movable glass panes, keeps menu button at slot 22, clears hotbar and offhand, sets player invisible, deactivates umbral blade - DEUAnimationController and StaticSceneController call enter/exitSceneOverlay - DevMenu static scene button now uses Config'd DEUAnimationController instead of StaticSceneController; animation key resolved from AnimationRegistry by anim key - Add Config.Animation.STATIC_MENU_ANIMATION_KEY (default: gentle_v2_default) - ConfigMenu animation section now opens ConfigSectionMenu (not AnimationBrowserMenu) - Add AnimationPickerMenu: paged GUI for selecting animations from AnimationRegistry; used when clicking a String-typed config entry in ConfigEntryItem - Fix ChatInputCapture NoClassDefFoundError: replace PlainTextComponentSerializer with TextComponent instance-check extraction to avoid runtime class resolution failure * Add: Animation stay-fix, blade deactivation API, recovery conditions, trash clear * Fix: NPE guard on gameMode display removal, double .get() call, redundant slot0 branch * Fix: Remove local Windows JDK path from gradle.properties * Fix: Faulty Import * Fix: SpotlessApply
- Add class-level and method Javadoc to ~34 files across listeners, action classes, skill hierarchy, attack shapes, AI states, and utilities - Fix all actionable Javadoc warnings: missing @param/@return, empty comments, no-main-description, and undocumented default constructors - Add private BezierUtil() constructor (also suppresses FinalClass Checkstyle hint) - Javadoc warnings reduced from ~890 to 100 (remaining are undocumented fields in Config/Prefab — out of scope)
* Add: Roguelike wave-run prototype (#268) - RoguelikeRun gamemode: 3-wave PvE (pillagers → wither skeletons → mixed), configurable spawn center and radius, TextDisplay reward chest on completion - Config.Roguelike section: spawn world/X/Y/Z, radius, per-wave enemy counts - QueueManager: register roguelike queue, start solo run immediately on enqueue - MainMenu: Wither Skeleton Skull queue button paired with CTF button - TODO #285: distribute MiscItems once consumable item system is built * Chore: move comms dir from .claude/comms to comms/ at project root * Feat: 5-minute roguelike timeout and per-mob damage log - Reduce RoguelikeRun safety cap from 15 min to 5 min (300 s) - Add DamageEntry record to Hostile tracking attacker UUID, name, weapon (SwordItemType), shard damage, and toughness damage - Override hit() in Hostile to append entries only when the hit actually lands (guarded by invulnerability-window check) * Feat: team-based friendly fire suppression via scoreboard tags Add SwordTeam enum (RED/BLUE/GREEN/YELLOW) backed by Bukkit scoreboard tags. SwordEntity.hit() skips damage when attacker and defender share a team tag. Assignments: Hostile → RED, SwordPlayer → BLUE, Passive → GREEN. joinTeam() / getTeam() exposed on SwordEntity. * Fix: Gamemode timer period 20ms → 1000ms (decrement once per real second) * Fix: restore umbralBladeState and soulLinkState predicates in combo registration * Feat: ErrorListener with safeRemove + try-catch around display spawning/removal * Feat: CTF full infrastructure — flag entity, team management, respawn, scoring, banner-on-head (#280) - Config.Ctf: spawn coords, flag return timer, respawn delay, capture threshold, carrier slow config - CtfTeam enum: RED/BLUE with banner factory (patterned banners), spawn locations from config - FlagEntity: IDLE/CARRIED/DROPPED state machine, ArmorStand visual at base, banner-on-head carrier effect, auto-return timer - CaptureTheFlag1v1 rewrite: proper lifecycle, 5s respawn with team-spawn return, first-to-N or timer win, score messaging - QueueManager: CTF 2-player queue wired, activeMatches map for death routing, startCtfDebug() bypass - PlayerListener: routes death events to active CTF match for flag drop + respawn scheduling - CommonConstraints: NOT_CARRYING_FLAG stub (pending global context constraint refactor) - Prefab.PotionEffects: FLAG_CARRIER_SLOW (config-backed Slowness II applied to flag carriers) - DevMenu: "Start CTF (Solo Debug)" button — bypasses queue, instant launch for one player * Chore: wire issue #297 reference into NOT_CARRYING_FLAG stub * Fix: null scores in getTitle() called before subclass field init * Fix: defer display group unregister 1 tick to avoid Paper chunk-lock warning * Feat: dev button to stop active roguelike run from main menu * Fix: NaN boss bar progress — override getMaxDuration() with constant in CTF * Chore: move menu items for menu refactor into dev menus folder
- Checkstyle config: allow SCREAMING_SNAKE_CASE for static fields, permit
empty catch blocks named 'ignored', allow empty {} blocks by excluding
LCURLY/RCURLY from WhitespaceAround tokens, processJavadoc for UnusedImports,
allowLineBreaks for NoWhitespaceBefore
- Utility classes: add final + private constructor to ~30 utility/static classes
- Static field renames: camelCase → SCREAMING_SNAKE_CASE across TimeArbiter,
QueueManager, SwordEntityArbiter, SwordAction, ActionCaster, MovementListener,
SkillRegistry, CharacterMenu, Misc, and others
- Method renames: Config.Direction UP/DOWN/etc → up/down/etc; WeaponAttackStyle
fDash/bDash/rStrafe/lStrafe accessor names normalized
- Parameter renames: fade_in/fade_out → fadeIn/fadeOut in SwordPlayer; r_diff
etc in InputActionExecutor
- Whitespace fixes: operator spacing (arithmetic, string concat, casts) across
~60 files; comma spacing in method calls throughout
- Empty block style: revert { } → {} for switch arrow cases and catch blocks
now that checkstyle is configured to allow them
…pertinent javadocs.
…ld accessors with getter calls
- Mark knife projectile as unbreakable so handleItemDamageAndCheckIfBroken does not destroy itemStack before the ImpactType check runs (root cause of the always-knockback bug: fresh items reported max damage due to hasDamageValue() returning false, triggering the break path on first hit) - Switch ImpactType.fromItem check from display.getItemStack() to itemStack to avoid PDC loss through the ItemDisplay entity round-trip - Add Prefab.Attacks.KNIFE_THROW: 1 shard, 15 toughness, 0 soulfire - Add hitPacket / knockbackFunction overrides to ThrownItem so ability throws can supply custom hit resolution without subclassing - Knife knockback: velocity * 0.2 added to the target's current velocity - Ability projectiles (tagged ABILITY_ID_KEY) no longer catchable by thrower, not registered in InteractiveItemArbiter, and dispose silently on entity death instead of dropping a world item
ItemStack API: - Replace new ItemStack(Material.X) with ItemStack.of() across the codebase - Replace ItemMeta.displayName() / .displayName() with .customName() Input system: - Rename InputExecutionTree.hasChildren() -> isTerminal() (clearer semantics) - Add getPlainTextInputSequence() debug helper to InputExecutionTree - Reset input tree on charge-action release in InputRegistrar - Reset input tree in MovementAction when player is holding an ability item Ability slot / SwordPlayer: - Add AbilitySlotManager.restoreSlot() and syncSlotItemFromState() so the ability slot can be restored after the gunpowder placeholder replaces it - Fix endHoldingRight() to call restoreSlot() when releasing an ability slot, rather than blindly restoring the pre-hold item stack - Fix onHoldRight() to null-check and clone hand snapshots - Remove stale isAbilityItem() overloads from SwordPlayer (replaced by notHoldingAbilityItem() / AbilitySlotManager) - Remove unused punchingWithLink, commandingWithLink, targetIndicatorTask fields AbilitySlotItem: - Merge EQUIPPED and EMPTY placeholder visual (both now show gray pane) - Change DEPLETED placeholder material to GRAY_DYE CtfTeam: - Replace manual getDyeColor/getTextColor with Lombok @Getter - Modernize world null-check and ItemStack construction Misc: - Add throwDirect(float) overload to ThrowAction delegating to Vector3f form - Add non-uniform displayScaleVector support to VisualProjectile
Replaces the previous flat suppression approach with a 20s sequence in SwordPlayer.testHudSequence(): wither hearts (5s), poisoned hearts (5s), empty food bar via HUD override (5s), and a bubble animation full-to-empty-to-full via TimeArbiter (5s). Removes the redundant enableTimedTestOverride/disableTestOverride/TEST_OVERRIDE_KEY API from HudOverrideManager.
Ability throws (ABILITY_ID_KEY tagged items) were skipping InteractiveItemArbiter.put() after the 10c6f57 cleanup, making them invisible to pickup and dash-to interactions. Remove the guard so they are tracked like any other thrown item; the onGrab refund path and the disposeWithNewInteractiveItem silent-dispose override continue to handle ability-specific behavior correctly. Also adds the custom smithing interaction system (CustomInteractionManager, CustomInventoryInteraction, HUD override infrastructure) and the ROTATE throw style used by smithing refits.
#303, #304, #305) #305 MovementListener: guard Debug.listener() string concat behind Config.Debug.LOGGING_VERBOSE_LISTENER — eliminates 100+ String allocations/sec per player from a no-op debug path. #304 HostileStateMachine: gate broadcastMessage() calls in onAnyTransition/afterAnyTransition behind LOGGING_VERBOSE_HOSTILE — eliminates O(n) getNearbyEntities world scan on every mob AI transition. #303 Hostile/HostileStateMachine: add cachedDistSqToTarget field, refreshTargetDistanceCache() called once at tick() start; all 13 transition conditions replaced with getCachedDistSqToTarget() — eliminates 3-5 Location allocations per mob per tick. #301 SwordEntity: cache SwordTeam in cachedTeam field set by joinTeam(); hit() now compares getCachedTeam() fields directly instead of calling SwordTeam.fromEntity() twice; joinTeam() drops the values() loop and removes only the previously held tag — eliminates 4 allocations per hit.
Add effectiveTransitionCache: Map<Class<?>, List<Transition>> to StateMachine. tick() now calls effectiveTransitionsFor(currentState.getClass()) which lazily computes and caches the filtered subset of transitions whose from-class is assignable from the current state class. Result: O(k) per-tick evaluation where k = transitions for the current state, instead of O(N) across all transitions with isAssignableFrom on every entry. For HostileStateMachine (~20 transitions, 10 distinct from-classes): each tick evaluates 3-7 conditions instead of 20. Cache is invalidated on addTransition() for correctness. Flyweight state instance caching skipped: several state classes (RecallingState, GrabImpaleState, StandbyState, RecoverState) hold task handle fields that are set in onEnter and cancelled in onExit — caching would require auditing every onExit for full cleanup, adding fragility risk for marginal gain on a code path that only runs on transitions.
* Fix ability-slot item swapping and refresh behavior (#292) * Fix: Knife throw impact type, add knife hit packet, ability item cleanup - Mark knife projectile as unbreakable so handleItemDamageAndCheckIfBroken does not destroy itemStack before the ImpactType check runs (root cause of the always-knockback bug: fresh items reported max damage due to hasDamageValue() returning false, triggering the break path on first hit) - Switch ImpactType.fromItem check from display.getItemStack() to itemStack to avoid PDC loss through the ItemDisplay entity round-trip - Add Prefab.Attacks.KNIFE_THROW: 1 shard, 15 toughness, 0 soulfire - Add hitPacket / knockbackFunction overrides to ThrownItem so ability throws can supply custom hit resolution without subclassing - Knife knockback: velocity * 0.2 added to the target's current velocity - Ability projectiles (tagged ABILITY_ID_KEY) no longer catchable by thrower, not registered in InteractiveItemArbiter, and dispose silently on entity death instead of dropping a world item * Update: ItemStack API modernization, input fixes, ability slot restore ItemStack API: - Replace new ItemStack(Material.X) with ItemStack.of() across the codebase - Replace ItemMeta.displayName() / .displayName() with .customName() Input system: - Rename InputExecutionTree.hasChildren() -> isTerminal() (clearer semantics) - Add getPlainTextInputSequence() debug helper to InputExecutionTree - Reset input tree on charge-action release in InputRegistrar - Reset input tree in MovementAction when player is holding an ability item Ability slot / SwordPlayer: - Add AbilitySlotManager.restoreSlot() and syncSlotItemFromState() so the ability slot can be restored after the gunpowder placeholder replaces it - Fix endHoldingRight() to call restoreSlot() when releasing an ability slot, rather than blindly restoring the pre-hold item stack - Fix onHoldRight() to null-check and clone hand snapshots - Remove stale isAbilityItem() overloads from SwordPlayer (replaced by notHoldingAbilityItem() / AbilitySlotManager) - Remove unused punchingWithLink, commandingWithLink, targetIndicatorTask fields AbilitySlotItem: - Merge EQUIPPED and EMPTY placeholder visual (both now show gray pane) - Change DEPLETED placeholder material to GRAY_DYE CtfTeam: - Replace manual getDyeColor/getTextColor with Lombok @Getter - Modernize world null-check and ItemStack construction Misc: - Add throwDirect(float) overload to ThrowAction delegating to Vector3f form - Add non-uniform displayScaleVector support to VisualProjectile * [Perf] Apply low-risk mob and state machine optimizations * Fix: Redo HUD effect test to cycle wither/poison/hunger/bubbles Replaces the previous flat suppression approach with a 20s sequence in SwordPlayer.testHudSequence(): wither hearts (5s), poisoned hearts (5s), empty food bar via HUD override (5s), and a bubble animation full-to-empty-to-full via TimeArbiter (5s). Removes the redundant enableTimedTestOverride/disableTestOverride/TEST_OVERRIDE_KEY API from HudOverrideManager. * Fix: Re-register ability projectiles in InteractiveItemArbiter Ability throws (ABILITY_ID_KEY tagged items) were skipping InteractiveItemArbiter.put() after the 10c6f57 cleanup, making them invisible to pickup and dash-to interactions. Remove the guard so they are tracked like any other thrown item; the onGrab refund path and the disposeWithNewInteractiveItem silent-dispose override continue to handle ability-specific behavior correctly. Also adds the custom smithing interaction system (CustomInteractionManager, CustomInventoryInteraction, HUD override infrastructure) and the ROTATE throw style used by smithing refits. * Fix: WhitespaceAround checkstyle warnings in SwordPlayer debug log * [Perf] Gate debug allocations, cache team and distance-to-target (#301, #303, #304, #305) #305 MovementListener: guard Debug.listener() string concat behind Config.Debug.LOGGING_VERBOSE_LISTENER — eliminates 100+ String allocations/sec per player from a no-op debug path. #304 HostileStateMachine: gate broadcastMessage() calls in onAnyTransition/afterAnyTransition behind LOGGING_VERBOSE_HOSTILE — eliminates O(n) getNearbyEntities world scan on every mob AI transition. #303 Hostile/HostileStateMachine: add cachedDistSqToTarget field, refreshTargetDistanceCache() called once at tick() start; all 13 transition conditions replaced with getCachedDistSqToTarget() — eliminates 3-5 Location allocations per mob per tick. #301 SwordEntity: cache SwordTeam in cachedTeam field set by joinTeam(); hit() now compares getCachedTeam() fields directly instead of calling SwordTeam.fromEntity() twice; joinTeam() drops the values() loop and removes only the previously held tag — eliminates 4 allocations per hit. * [Perf] Partition state machine transitions by from-state (#302) Add effectiveTransitionCache: Map<Class<?>, List<Transition>> to StateMachine. tick() now calls effectiveTransitionsFor(currentState.getClass()) which lazily computes and caches the filtered subset of transitions whose from-class is assignable from the current state class. Result: O(k) per-tick evaluation where k = transitions for the current state, instead of O(N) across all transitions with isAssignableFrom on every entry. For HostileStateMachine (~20 transitions, 10 distinct from-classes): each tick evaluates 3-7 conditions instead of 20. Cache is invalidated on addTransition() for correctness. Flyweight state instance caching skipped: several state classes (RecallingState, GrabImpaleState, StandbyState, RecoverState) hold task handle fields that are set in onEnter and cancelled in onExit — caching would require auditing every onExit for full cleanup, adding fragility risk for marginal gain on a code path that only runs on transitions. * Refactor: ThrowPhase/InventoryMode enums; gate debug scans (#304 #305 #306) (#309) * Fix: Gate throw-cancel log behind Debug.system()
Cache prevDisplayShards and prevDisplayToughness on SwordEntity; return early from updateStatusDisplayText() when neither value has changed, eliminating ~700 Component allocations per second at 35 entities.
…isplay - ThrownItem: re-register ability items in InteractiveItemArbiter so they can be dash-grabbed again (onGrab's refund logic already handles them correctly; the non-registration guard introduced in 10c6f57 was overly broad) - AbilitySlotItem: simplify shouldPreserveOnReplace — any item with ABILITY_SLOT_KEY is a managed slot item and should never be displaced to the player's inventory on restore - AbilitySlotManager: replace direct setAmount/updateDurabilityDisplay mutations in consumeUse() with restoreSlot(), which actually pushes the rebuilt item into the inventory slot so the client sees the updated amount
…he Debug Boolean Variable
Replace per-task ScheduledExecutorService futures with a single BukkitRunnable.runTaskTimer(0, 1) global tick loop. All TimeArbiter registrations now add a TaskHandle to REGISTERED_TASKS; each tick iterates the list, fires tasks whose nextFireTimeMs has elapsed, and removes cancelled entries via removeIf. - Eliminates ~210-280 concurrent ScheduledFutures at runtime - Time-bound tasks apply GLOBAL_TIME_SCALE dynamically on each fire, removing the need to reschedule on setGlobalTimeScale() changes - Public API (runTimeBoundBukkitTaskOnTimer, runTimeIndependentBukkitTaskOnTimer, runFixedIterationTaskTimer, TaskHandle.cancel/pause/resume) unchanged - Removes scheduleTaskFuture(), processRestartRequest(), rescheduleFuture(), and markedToRestart (all internal to the old executor approach) - SwordScheduler's one-shot delays continue using the ScheduledExecutorService
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Related Issues
Closes #299
Relates to #298