{"id":"zenukopublic/action-buffer","name":"action-buffer","scope":"zenukopublic","platform":"roblox","description":"High-performance circular ring-buffered action queuing and prediction reconciliation for competitive combat games.","version":"1.0.0","latest":"1.0.0","versions":["1.0.0"],"license":"MIT","licenseRating":"safe","licenseCaveats":[],"licenseVerified":true,"dependencies":{},"integrity":"143217e3d45d3579c7ee1eef80776ff4852d46e674a54978fd060619e4c080a1","likes":0,"downloads":0,"install":"forest install zenukopublic/action-buffer","url":"https://forest.dev/p/roblox/zenukopublic/action-buffer","files":"https://api.forest.dev/ai/package/roblox/zenukopublic/action-buffer/files","readme":"# `action-buffer`\n\n> **High-performance circular ring-buffered action queuing and prediction reconciliation for competitive combat games.**\n\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![Language: Luau](https://img.shields.io/badge/Language-Luau-blue.svg)](https://luau-lang.org/)\n[![Wally: Available](https://img.shields.io/badge/Wally-Available-brightgreen.svg)](https://wally.run/)\n\n---\n\n> **Production Origin:** This package was extracted and generalized from infrastructure developed for **Kabbrawl**, a private competitive multiplayer Roblox experience. Kabbrawl itself remains proprietary; this package contains only reusable infrastructure and no proprietary assets or game-specific content.\n\n---\n## ⚔️ Why Action Buffering?\n\nIn fast-paced fighting, action RPG, or sports games, player inputs often arrive while the character is finishing an animation, stunned, or during a frame transition. \n\nWithout an input buffer:\n* Inputs pressed 50 ms before an attack ends are **dropped**, making controls feel unresponsive and \"stiff\".\n* With a naive array queue, memory allocations occur every frame, triggering garbage collection hitches.\n* Inputs queued too early execute unintentionally after long delays.\n\n**`action-buffer`** provides a **zero-allocation circular ring buffer** with a strict temporal expiration window (e.g. 150 ms) and integrated client prediction reconciliation.\n\n---\n\n## ✨ Features\n\n* **Zero Memory Allocation in Hot Paths:** Circular ring buffers reuse table slots without resizing or GC pressure.\n* **Temporal Window Consumption:** Queued inputs expire naturally if the player cannot act within the window.\n* **Multi-Channel Isolation:** Separate channels for Attack, Dodge, Guard, and Skill inputs.\n* **Prediction Reconciliation:** Match optimistic client-predicted actions against server-confirmed sequence IDs.\n\n---\n\n## 🚀 Installation\n\n### Via Wally\nAdd `action-buffer` to your `wally.toml`:\n\n```toml\n[dependencies]\nActionBuffer = \"zenukopublic/action-buffer@1.0.0\"\n```\n\n---\n\n## 📖 Quickstart\n\n```luau\nlocal ActionBuffer = require(Packages.ActionBuffer)\n\nlocal buffer = ActionBuffer.new({\n    capacity = 8,\n    windowSeconds = 0.15, -- 150 ms buffer window\n})\n\n-- When player presses attack button (even during recovery frames):\nUserInputService.InputBegan:Connect(function(input)\n    if input.KeyCode == Enum.KeyCode.E then\n        buffer:push(\"Attack\", currentFrame, { attackType = \"Slash\" })\n    end\nend)\n\n-- In your 60 Hz combat tick / state machine:\nRunService.Heartbeat:Connect(function()\n    if characterState:canAttack() then\n        local action = buffer:consume(\"Attack\")\n        if action then\n            characterState:executeAttack(action.payload.attackType)\n        end\n    end\nend)\n```\n\n---\n\n## 🧪 Testing\n\nRun standalone unit tests headlessly with [Lune](https://github.com/lune-org/lune):\n```bash\nlune run tests/action_buffer.test.luau\n```\n\n---\n\n## 📄 License\n\nMIT License. Free for personal and commercial use.\n","readmeTruncated":false}