{"id":"noirsplash/cooldown","name":"cooldown","scope":"noirsplash","platform":"roblox","description":"Simple non-yielding Roblox module for managing time between actions.","version":"1.1.0","latest":"1.1.0","versions":["1.0.1","1.0.2","1.1.0"],"license":"GPL-3.0","licenseRating":"unsafe","licenseCaveats":["Strong copyleft: shipping this in your game plausibly requires releasing your game's entire source under GPL-3.0. Not recommended for closed-source projects."],"licenseVerified":false,"dependencies":{},"integrity":"1e5e6d1b1660a0727f2017c11db82d51bb81d4389ee479b206cdc4bb9368662f","likes":0,"downloads":0,"install":"forest install noirsplash/cooldown","url":"https://forest.dev/p/roblox/noirsplash/cooldown","files":"https://api.forest.dev/ai/package/roblox/noirsplash/cooldown/files","readme":"# Cooldown by NoirSplash\r\n**Simple non-yielding Roblox module for managing time between actions.**\r\n\r\nSimilar to a [Maid](https://medium.com/roblox-development/how-to-use-a-maid-class-on-roblox-to-manage-state-651bf74de98b), Cooldown intends to streamline development by keeping your debounce and cooldown management in one place.\r\n\r\n<details>\r\n<summary>How do I use this module?</summary>\r\n\r\n## Installation\r\n\r\n### Import the Module\r\n**Option A: From Roblox**\r\n- Get the module [here](https://www.roblox.com/library/14555653947/Cooldown).\r\n- Insert the module from your toolbox into somewhere your script can see it.\r\n\r\n**Option B: From Github**\r\n- Find the Lua file [here](https://github.com/NoirSplash/cooldown/releases/tag/major-release).\r\n- Import the file into roblox studio using one of the following methods;\r\n  - Right click the object you want to be the parent of your module and `Insert from File...`. Change the file type to \"Script Files\" (from \"All Roblox Model Files\") and select the Lua file you downloaded. You must **transfer the contents of the script to a ModuleScript**.\r\n    \r\n    **or**\r\n  - Open the RAW script (either from the downloaded file or github's raw text viewer) and paste its contents into a ModuleScript in your experience.\r\n\r\n### Require the Module\r\n- After you've imported the module into your experience, require it from any Script or LocalScript you intend to use it in. For this example, we've placed our module from the previous step into `ReplicatedStorage`.\r\n```lua\r\nlocal ReplicatedStorage = game:GetService(\"ReplicatedStorage\")\r\nlocal Cooldown = require(ReplicatedStorage.Cooldown()\r\n```\r\nNow that you've setup the module, take a look below to see how to use it!\r\n\r\n---\r\n</details>\r\n\r\n> [!IMPORTANT]\r\n> Cooldown is not a timer module. There are no methods or signals provided to listen for when a cooldown expires and their status is evaluated only when called.\r\n\r\n---\r\n[Roblox Model](https://www.roblox.com/library/14555653947/Cooldown) | [Latest Release](https://github.com/NoirSplash/cooldown/releases/tag/major-release)\r\n\r\n[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/A0A8OKGQH)\r\n\r\n## Properties\r\n\r\n### GARBAGE_COLLECT_INTERVAL : number\r\n`private, constant`\r\n\r\nDescribes how long (in seconds) the garbage collector should wait between cleanings. Expired cooldowns are automatically cleaned up when they are queried, garbage collection only affects cooldowns that expire and are never called on again. Does nothing if `Cooldown.doCleaning` is set to _false_. `default 120`\r\n\r\n### Cooldown.doCleaning : boolean\r\n`public, variable`\r\n\r\nDetermines if expired cooldowns are automatically cleaned up by the garbage collector. If set to `false`, the cache must be cleaned manually by iterating through and calling `Cooldown.get()` on each entry to remove expired cooldowns or by other means to avoid memory leaks. The loop cannot be restarted once disabled. `default true`\r\n\r\n## Methods\r\n### Cooldown.set(string, number, boolean?) -> ()\r\nThis function sets (or resets) a cooldown based on the given identifier and duration.\r\n#### Parameters\r\n| Name  | Type | Description |\r\n| --- | --- | --- |\r\n| cooldownId | string | The unique identifying string you will use to keep track of the cooldown. |\r\n| duration | number | How many seconds (or milliseconds) from the current time that the cooldown will expire |\r\n| isMillis | boolean? | Whether the duration provided is in seconds _(false)_ or milliseconds _(true)_. `default false`\r\n\r\n### Cooldown.get(string) -> (number?)\r\nReturns the remaining duration of the cooldown matching the identifier given or nil if it is expired/does not exist.\r\n#### Parameters\r\n| Name  | Type | Description |\r\n| --- | --- | --- |\r\n| cooldownId | string | The unique identifying string you gave to `Cooldown.set()`. |\r\n\r\n## Code Examples\r\n### Generic Debounce Pattern\r\nThe following code block shows off the intended usage for simple cooldowns (or debounce.) Because `Cooldown.get()` returns _nil_ if a cooldown is expired, the conditional statement will only evaluate true if the duration of the cooldown has elapsed or does not exist.\r\n```lua\r\nif Cooldown.get(\"Debounce\") then\r\n    return\r\nend\r\nCooldown.set(\"Debounce\", DEBOUNCE_LENGTH)\r\n```\r\n\r\n### Refreshable Cooldown/Combo Timer\r\nInstead of blocking a function this code will reset the timer on a cooldown if it is active, else it will reset a variable. Keep in mind the value will not reset until called again, even if the timer expires.\r\n```lua\r\nlocal combo = 0\r\nif Cooldown.get(\"ComboTimer\") then\r\n    combo += 1\r\n    Cooldown.set(\"ComboTimer\", COMBO_DURATION) -- Reset the timer so you can continue the combo!\r\nelse\r\n    combo = 0\r\n    Cooldown.set(\"ComboTimer\", COMBO_DURATION) -- Start the combo chain!\r\nend\r\n```\r\n**Simplified**\r\n```lua\r\nlocal combo = 0\r\nlocal function combo()\r\n    combo = if Cooldown.get(\"ComboTimer\") then combo + 1 else 0\r\n    Cooldown.set(\"ComboTimer\", COMBO_DURATION)\r\nend\r\n```\r\n\r\n### Jump Reducer\r\nThis script combines the above two techniques into a system that reduces the player's jump height the more consecutive jumps they make, without restricting jumping entirely.\r\n```lua\r\nlocal Players = game:GetService(\"Players\")\r\nlocal ReplicatedStorage = game:GetService(\"ReplicatedStorage\")\r\nlocal UserInputService = game:GetService(\"UserInputService\")\r\n\r\nlocal Cooldown = require(ReplicatedStorage.lib.Cooldown)\r\n\r\nlocal DEFAULT_JUMP_HEIGHT = 7.2\r\nlocal JUMP_COOLDOWN = 0.7\r\nlocal REQUEST_DEBOUNCE = 75 -- milliseconds\r\n\r\nlocal jumpCount = 0\r\n\r\nlocal function setCooldownTimer()\r\n    if Cooldown.get(\"LocalJump\") then\r\n        Cooldown.set(\"LocalJump\", JUMP_COOLDOWN)\r\n    else\r\n        jumpCount = 0\r\n        Cooldown.set(\"LocalJump\", JUMP_COOLDOWN)\r\n    end\r\nend\r\n\r\nUserInputService.JumpRequest:Connect(function()\r\n    if Cooldown.get(\"JumpRequestDebounce\") then\r\n        return\r\n    end\r\n    Cooldown.set(\"JumpRequestDebounce\", REQUEST_DEBOUNCE, true)\r\n    setCooldownTimer()\r\n    jumpCount += 1\r\n\r\n    local character = Players.LocalPlayer.Character\r\n    local humanoid = character and character:FindFirstChildOfClass(\"Humanoid\")\r\n    if not character or not humanoid then\r\n        return\r\n    end\r\n\r\n    local jumpHeight = DEFAULT_JUMP_HEIGHT * math.clamp(1 - jumpCount * 0.1, 0, 1)\r\n    humanoid.JumpHeight = jumpHeight\r\nend)\r\n```\r\n","readmeTruncated":false}